diff options
Diffstat (limited to 'lib/Target/Mips')
121 files changed, 13785 insertions, 4885 deletions
diff --git a/lib/Target/Mips/AsmParser/CMakeLists.txt b/lib/Target/Mips/AsmParser/CMakeLists.txt index 28f521910901..f1675560853a 100644 --- a/lib/Target/Mips/AsmParser/CMakeLists.txt +++ b/lib/Target/Mips/AsmParser/CMakeLists.txt @@ -1,6 +1,3 @@ -include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) add_llvm_library(LLVMMipsAsmParser MipsAsmParser.cpp ) - -add_dependencies(LLVMMipsAsmParser MipsCommonTableGen) diff --git a/lib/Target/Mips/AsmParser/LLVMBuild.txt b/lib/Target/Mips/AsmParser/LLVMBuild.txt index e7ca243d0e7f..dd8e3cf6d8cd 100644 --- a/lib/Target/Mips/AsmParser/LLVMBuild.txt +++ b/lib/Target/Mips/AsmParser/LLVMBuild.txt @@ -19,5 +19,5 @@ type = Library name = MipsAsmParser parent = Mips -required_libraries = MC MCParser Support MipsDesc MipsInfo +required_libraries = MC MCParser MipsDesc MipsInfo Support add_to_library_groups = Mips diff --git a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index cdae6c2f37e5..53b30f9210b0 100644 --- a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -7,24 +7,30 @@ // //===----------------------------------------------------------------------===// +#include "MCTargetDesc/MipsMCExpr.h" #include "MCTargetDesc/MipsMCTargetDesc.h" #include "MipsRegisterInfo.h" #include "MipsTargetStreamer.h" +#include "llvm/ADT/APInt.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/TargetRegistry.h" -#include "llvm/ADT/APInt.h" using namespace llvm; +#define DEBUG_TYPE "mips-asm-parser" + namespace llvm { class MCInstrInfo; } @@ -54,137 +60,81 @@ private: namespace { class MipsAsmParser : public MCTargetAsmParser { - MipsTargetStreamer &getTargetStreamer() { - MCTargetStreamer &TS = Parser.getStreamer().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); + unsigned checkTargetMatchPredicate(MCInst &Inst) override; - MipsAsmParser::OperandMatchResultTy - parseFGR64Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, MCStreamer &Out, + unsigned &ErrorInfo, + bool MatchingInlineAsm) override; - MipsAsmParser::OperandMatchResultTy - parseFGR32Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + /// Parse a register as used in CFI directives + bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; - MipsAsmParser::OperandMatchResultTy - parseFGRH32Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + bool ParseParenSuffix(StringRef Name, OperandVector &Operands); - MipsAsmParser::OperandMatchResultTy - parseFCCRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + bool ParseBracketSuffix(StringRef Name, OperandVector &Operands); - MipsAsmParser::OperandMatchResultTy - parseACC64DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) override; - MipsAsmParser::OperandMatchResultTy - parseLO32DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + bool ParseDirective(AsmToken DirectiveID) override; - MipsAsmParser::OperandMatchResultTy - parseHI32DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MipsAsmParser::OperandMatchResultTy parseMemOperand(OperandVector &Operands); MipsAsmParser::OperandMatchResultTy - parseCOP2(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MatchAnyRegisterNameWithoutDollar(OperandVector &Operands, + StringRef Identifier, SMLoc S); MipsAsmParser::OperandMatchResultTy - parseMSA128BRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MatchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S); - MipsAsmParser::OperandMatchResultTy - parseMSA128HRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MipsAsmParser::OperandMatchResultTy ParseAnyRegister(OperandVector &Operands); - MipsAsmParser::OperandMatchResultTy - parseMSA128WRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MipsAsmParser::OperandMatchResultTy ParseImm(OperandVector &Operands); - MipsAsmParser::OperandMatchResultTy - parseMSA128DRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MipsAsmParser::OperandMatchResultTy ParseJumpTarget(OperandVector &Operands); - MipsAsmParser::OperandMatchResultTy - parseMSA128CtrlRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MipsAsmParser::OperandMatchResultTy parseInvNum(OperandVector &Operands); - MipsAsmParser::OperandMatchResultTy - parseInvNum(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MipsAsmParser::OperandMatchResultTy ParseLSAImm(OperandVector &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 searchSymbolAlias(OperandVector &Operands); - bool tryParseRegisterOperand(SmallVectorImpl<MCParsedAsmOperand *> &Operands, - bool is64BitReg); + bool ParseOperand(OperandVector &, StringRef Mnemonic); bool needsExpansion(MCInst &Inst); - void expandInstruction(MCInst &Inst, SMLoc IDLoc, + // Expands assembly pseudo instructions. + // Returns false on success, true otherwise. + bool expandInstruction(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); - void expandLoadImm(MCInst &Inst, SMLoc IDLoc, + + bool expandLoadImm(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); - void expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, + + bool expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); - void expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, + + bool 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 reportParseError(Twine ErrorMsg); + bool reportParseError(SMLoc Loc, Twine ErrorMsg); bool parseMemOffset(const MCExpr *&Res, bool isParenExpr); bool parseRelocOperand(const MCExpr *&Res); @@ -192,9 +142,12 @@ class MipsAsmParser : public MCTargetAsmParser { const MCExpr *evaluateRelocExpr(const MCExpr *Expr, StringRef RelocStr); bool isEvaluated(const MCExpr *Expr); + bool parseSetFeature(uint64_t Feature); + bool parseDirectiveCPLoad(SMLoc Loc); + bool parseDirectiveCPSetup(); + bool parseDirectiveNaN(); bool parseDirectiveSet(); - bool parseDirectiveMipsHackStocg(); - bool parseDirectiveMipsHackELFFlags(); + bool parseDirectiveOption(); bool parseSetAtDirective(); bool parseSetNoAtDirective(); @@ -202,25 +155,22 @@ class MipsAsmParser : public MCTargetAsmParser { bool parseSetNoMacroDirective(); bool parseSetReorderDirective(); bool parseSetNoReorderDirective(); + bool parseSetNoMips16Directive(); + bool parseSetFpDirective(); bool parseSetAssignment(); - bool parseDirectiveWord(unsigned Size, SMLoc L); + bool parseDataDirective(unsigned Size, SMLoc L); bool parseDirectiveGpWord(); + bool parseDirectiveGpDWord(); + bool parseDirectiveModule(); + bool parseDirectiveModuleFP(); + bool parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI, + StringRef Directive); 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); + bool eatComma(StringRef ErrorStr); int matchCPURegisterName(StringRef Symbol); @@ -236,11 +186,11 @@ class MipsAsmParser : public MCTargetAsmParser { int matchMSA128CtrlRegisterName(StringRef Name); - int regKindToRegClass(int RegKind); - unsigned getReg(int RC, int RegNo); - int getATReg(); + unsigned getGPR(int RegNo); + + int getATReg(SMLoc Loc); bool processInstruction(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); @@ -250,17 +200,102 @@ class MipsAsmParser : public MCTargetAsmParser { // Example: INSERT.B $w0[n], $1 => 16 > n >= 0 bool validateMSAIndex(int Val, int RegKind); + void setFeatureBits(unsigned Feature, StringRef FeatureString) { + if (!(STI.getFeatureBits() & Feature)) { + setAvailableFeatures( + ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); + } + } + + void clearFeatureBits(unsigned Feature, StringRef FeatureString) { + if (STI.getFeatureBits() & Feature) { + setAvailableFeatures( + ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); + } + } + public: + enum MipsMatchResultTy { + Match_RequiresDifferentSrcAndDst = FIRST_TARGET_MATCH_RESULT_TY +#define GET_OPERAND_DIAGNOSTIC_TYPES +#include "MipsGenAsmMatcher.inc" +#undef GET_OPERAND_DIAGNOSTIC_TYPES + + }; + MipsAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser, - const MCInstrInfo &MII) - : MCTargetAsmParser(), STI(sti), Parser(parser), - hasConsumedDollar(false) { + const MCInstrInfo &MII, const MCTargetOptions &Options) + : MCTargetAsmParser(), STI(sti), Parser(parser) { // Initialize the set of available features. setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + + getTargetStreamer().updateABIInfo(*this); + + // Assert exactly one ABI was chosen. + assert((((STI.getFeatureBits() & Mips::FeatureO32) != 0) + + ((STI.getFeatureBits() & Mips::FeatureEABI) != 0) + + ((STI.getFeatureBits() & Mips::FeatureN32) != 0) + + ((STI.getFeatureBits() & Mips::FeatureN64) != 0)) == 1); + + if (!isABI_O32() && !useOddSPReg() != 0) + report_fatal_error("-mno-odd-spreg requires the O32 ABI"); } MCAsmParser &getParser() const { return Parser; } MCAsmLexer &getLexer() const { return Parser.getLexer(); } + + /// True if all of $fcc0 - $fcc7 exist for the current ISA. + bool hasEightFccRegisters() const { return hasMips4() || hasMips32(); } + + bool isGP64bit() const { return STI.getFeatureBits() & Mips::FeatureGP64Bit; } + bool isFP64bit() const { return STI.getFeatureBits() & Mips::FeatureFP64Bit; } + bool isABI_N32() const { return STI.getFeatureBits() & Mips::FeatureN32; } + bool isABI_N64() const { return STI.getFeatureBits() & Mips::FeatureN64; } + bool isABI_O32() const { return STI.getFeatureBits() & Mips::FeatureO32; } + bool isABI_FPXX() const { return STI.getFeatureBits() & Mips::FeatureFPXX; } + + bool useOddSPReg() const { + return !(STI.getFeatureBits() & Mips::FeatureNoOddSPReg); + } + + bool inMicroMipsMode() const { + return STI.getFeatureBits() & Mips::FeatureMicroMips; + } + bool hasMips1() const { return STI.getFeatureBits() & Mips::FeatureMips1; } + bool hasMips2() const { return STI.getFeatureBits() & Mips::FeatureMips2; } + bool hasMips3() const { return STI.getFeatureBits() & Mips::FeatureMips3; } + bool hasMips4() const { return STI.getFeatureBits() & Mips::FeatureMips4; } + bool hasMips5() const { return STI.getFeatureBits() & Mips::FeatureMips5; } + bool hasMips32() const { + return (STI.getFeatureBits() & Mips::FeatureMips32); + } + bool hasMips64() const { + return (STI.getFeatureBits() & Mips::FeatureMips64); + } + bool hasMips32r2() const { + return (STI.getFeatureBits() & Mips::FeatureMips32r2); + } + bool hasMips64r2() const { + return (STI.getFeatureBits() & Mips::FeatureMips64r2); + } + bool hasMips32r6() const { + return (STI.getFeatureBits() & Mips::FeatureMips32r6); + } + bool hasMips64r6() const { + return (STI.getFeatureBits() & Mips::FeatureMips64r6); + } + bool hasDSP() const { return (STI.getFeatureBits() & Mips::FeatureDSP); } + bool hasDSPR2() const { return (STI.getFeatureBits() & Mips::FeatureDSPR2); } + bool hasMSA() const { return (STI.getFeatureBits() & Mips::FeatureMSA); } + + bool inMips16Mode() const { + return STI.getFeatureBits() & Mips::FeatureMips16; + } + // TODO: see how can we get this info. + bool abiUsesSoftFloat() const { return false; } + + /// Warn if RegNo is the current assembler temporary. + void WarnIfAssemblerTemporary(int RegNo, SMLoc Loc); }; } @@ -269,53 +304,59 @@ 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 + /// Broad categories of register classes + /// The exact class is finalized by the render method. + enum RegKind { + RegKind_GPR = 1, /// GPR32 and GPR64 (depending on isGP64bit()) + RegKind_FGR = 2, /// FGR32, FGR64, AFGR64 (depending on context and + /// isFP64bit()) + RegKind_FCC = 4, /// FCC + RegKind_MSA128 = 8, /// MSA128[BHWD] (makes no difference which) + RegKind_MSACtrl = 16, /// MSA control registers + RegKind_COP2 = 32, /// COP2 + RegKind_ACC = 64, /// HI32DSP, LO32DSP, and ACC64DSP (depending on + /// context). + RegKind_CCR = 128, /// CCR + RegKind_HWRegs = 256, /// HWRegs + RegKind_COP3 = 512, /// COP3 + + /// Potentially any (e.g. $1) + RegKind_Numeric = RegKind_GPR | RegKind_FGR | RegKind_FCC | RegKind_MSA128 | + RegKind_MSACtrl | RegKind_COP2 | RegKind_ACC | + RegKind_CCR | RegKind_HWRegs | RegKind_COP3 }; private: enum KindTy { - k_CondCode, - k_CoprocNum, - k_Immediate, - k_Memory, - k_PostIndexRegister, - k_Register, - k_PtrReg, - k_Token, - k_LSAImm + k_Immediate, /// An immediate (possibly involving symbol references) + k_Memory, /// Base + Offset Memory Address + k_PhysRegister, /// A physical register from the Mips namespace + k_RegisterIndex, /// A register index in one or more RegKind. + k_Token /// A simple token } Kind; - MipsOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} +public: + MipsOperand(KindTy K, MipsAsmParser &Parser) + : MCParsedAsmOperand(), Kind(K), AsmParser(Parser) {} + +private: + /// For diagnostics, and checking the assembler temporary + MipsAsmParser &AsmParser; struct Token { const char *Data; unsigned Length; }; - struct RegOp { - unsigned RegNum; - RegisterKind Kind; + struct PhysRegOp { + unsigned Num; /// Register Number + }; + + struct RegIdxOp { + unsigned Index; /// Index into the register class + RegKind Kind; /// Bitfield of the kinds it could possibly be + const MCRegisterInfo *RegInfo; }; struct ImmOp { @@ -323,33 +364,173 @@ private: }; struct MemOp { - unsigned Base; + MipsOperand *Base; const MCExpr *Off; }; union { struct Token Tok; - struct RegOp Reg; + struct PhysRegOp PhysReg; + struct RegIdxOp RegIdx; struct ImmOp Imm; struct MemOp Mem; }; SMLoc StartLoc, EndLoc; + /// Internal constructor for register kinds + static std::unique_ptr<MipsOperand> CreateReg(unsigned Index, RegKind RegKind, + const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + auto Op = make_unique<MipsOperand>(k_RegisterIndex, Parser); + Op->RegIdx.Index = Index; + Op->RegIdx.RegInfo = RegInfo; + Op->RegIdx.Kind = RegKind; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + public: - void addRegOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getReg())); + /// Coerce the register to GPR32 and return the real register for the current + /// target. + unsigned getGPR32Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_GPR) && "Invalid access!"); + AsmParser.WarnIfAssemblerTemporary(RegIdx.Index, StartLoc); + unsigned ClassID = Mips::GPR32RegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } - void addPtrRegOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getPtrReg())); + /// Coerce the register to GPR64 and return the real register for the current + /// target. + unsigned getGPR64Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_GPR) && "Invalid access!"); + unsigned ClassID = Mips::GPR64RegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + +private: + /// Coerce the register to AFGR64 and return the real register for the current + /// target. + unsigned getAFGR64Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_FGR) && "Invalid access!"); + if (RegIdx.Index % 2 != 0) + AsmParser.Warning(StartLoc, "Float register should be even."); + return RegIdx.RegInfo->getRegClass(Mips::AFGR64RegClassID) + .getRegister(RegIdx.Index / 2); + } + + /// Coerce the register to FGR64 and return the real register for the current + /// target. + unsigned getFGR64Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_FGR) && "Invalid access!"); + return RegIdx.RegInfo->getRegClass(Mips::FGR64RegClassID) + .getRegister(RegIdx.Index); + } + + /// Coerce the register to FGR32 and return the real register for the current + /// target. + unsigned getFGR32Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_FGR) && "Invalid access!"); + return RegIdx.RegInfo->getRegClass(Mips::FGR32RegClassID) + .getRegister(RegIdx.Index); + } + + /// Coerce the register to FGRH32 and return the real register for the current + /// target. + unsigned getFGRH32Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_FGR) && "Invalid access!"); + return RegIdx.RegInfo->getRegClass(Mips::FGRH32RegClassID) + .getRegister(RegIdx.Index); + } + + /// Coerce the register to FCC and return the real register for the current + /// target. + unsigned getFCCReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_FCC) && "Invalid access!"); + return RegIdx.RegInfo->getRegClass(Mips::FCCRegClassID) + .getRegister(RegIdx.Index); + } + + /// Coerce the register to MSA128 and return the real register for the current + /// target. + unsigned getMSA128Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_MSA128) && "Invalid access!"); + // It doesn't matter which of the MSA128[BHWD] classes we use. They are all + // identical + unsigned ClassID = Mips::MSA128BRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to MSACtrl and return the real register for the + /// current target. + unsigned getMSACtrlReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_MSACtrl) && "Invalid access!"); + unsigned ClassID = Mips::MSACtrlRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to COP2 and return the real register for the + /// current target. + unsigned getCOP2Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_COP2) && "Invalid access!"); + unsigned ClassID = Mips::COP2RegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to COP3 and return the real register for the + /// current target. + unsigned getCOP3Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_COP3) && "Invalid access!"); + unsigned ClassID = Mips::COP3RegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to ACC64DSP and return the real register for the + /// current target. + unsigned getACC64DSPReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_ACC) && "Invalid access!"); + unsigned ClassID = Mips::ACC64DSPRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to HI32DSP and return the real register for the + /// current target. + unsigned getHI32DSPReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_ACC) && "Invalid access!"); + unsigned ClassID = Mips::HI32DSPRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to LO32DSP and return the real register for the + /// current target. + unsigned getLO32DSPReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_ACC) && "Invalid access!"); + unsigned ClassID = Mips::LO32DSPRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to CCR and return the real register for the + /// current target. + unsigned getCCRReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_CCR) && "Invalid access!"); + unsigned ClassID = Mips::CCRRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to HWRegs and return the real register for the + /// current target. + unsigned getHWRegsReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_HWRegs) && "Invalid access!"); + unsigned ClassID = Mips::HWRegsRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } +public: void addExpr(MCInst &Inst, const MCExpr *Expr) const { // Add as immediate when possible. Null MCExpr = 0. - if (Expr == 0) + if (!Expr) Inst.addOperand(MCOperand::CreateImm(0)); else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr)) Inst.addOperand(MCOperand::CreateImm(CE->getValue())); @@ -357,6 +538,100 @@ public: Inst.addOperand(MCOperand::CreateExpr(Expr)); } + void addRegOperands(MCInst &Inst, unsigned N) const { + llvm_unreachable("Use a custom parser instead"); + } + + /// Render the operand to an MCInst as a GPR32 + /// Asserts if the wrong number of operands are requested, or the operand + /// is not a k_RegisterIndex compatible with RegKind_GPR + void addGPR32AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getGPR32Reg())); + } + + /// Render the operand to an MCInst as a GPR64 + /// Asserts if the wrong number of operands are requested, or the operand + /// is not a k_RegisterIndex compatible with RegKind_GPR + void addGPR64AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getGPR64Reg())); + } + + void addAFGR64AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getAFGR64Reg())); + } + + void addFGR64AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getFGR64Reg())); + } + + void addFGR32AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getFGR32Reg())); + // FIXME: We ought to do this for -integrated-as without -via-file-asm too. + if (!AsmParser.useOddSPReg() && RegIdx.Index & 1) + AsmParser.Error(StartLoc, "-mno-odd-spreg prohibits the use of odd FPU " + "registers"); + } + + void addFGRH32AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getFGRH32Reg())); + } + + void addFCCAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getFCCReg())); + } + + void addMSA128AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getMSA128Reg())); + } + + void addMSACtrlAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getMSACtrlReg())); + } + + void addCOP2AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getCOP2Reg())); + } + + void addCOP3AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getCOP3Reg())); + } + + void addACC64DSPAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getACC64DSPReg())); + } + + void addHI32DSPAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getHI32DSPReg())); + } + + void addLO32DSPAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getLO32DSPReg())); + } + + void addCCRAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getCCRReg())); + } + + void addHWRegsAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getHWRegsReg())); + } + void addImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); const MCExpr *Expr = getImm(); @@ -366,46 +641,72 @@ public: void addMemOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getMemBase())); + Inst.addOperand(MCOperand::CreateReg(getMemBase()->getGPR32Reg())); 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 isReg() const override { + // As a special case until we sort out the definition of div/divu, pretend + // that $0/$zero are k_PhysRegister so that MCK_ZERO works correctly. + if (isGPRAsmReg() && RegIdx.Index == 0) + return true; + + return Kind == k_PhysRegister; + } + bool isRegIdx() const { return Kind == k_RegisterIndex; } + bool isImm() const override { return Kind == k_Immediate; } + bool isConstantImm() const { + return isImm() && dyn_cast<MCConstantExpr>(getImm()); + } + bool isToken() const override { + // Note: It's not possible to pretend that other operand kinds are tokens. + // The matcher emitter checks tokens first. + return Kind == k_Token; + } + bool isMem() const override { return Kind == k_Memory; } + bool isConstantMemOff() const { + return isMem() && dyn_cast<MCConstantExpr>(getMemOff()); + } + template <unsigned Bits> bool isMemWithSimmOffset() const { + return isMem() && isConstantMemOff() && isInt<Bits>(getConstantMemOff()); + } bool isInvNum() const { return Kind == k_Immediate; } - bool isLSAImm() const { return Kind == k_LSAImm; } + bool isLSAImm() const { + if (!isConstantImm()) + return false; + int64_t Val = getConstantImm(); + return 1 <= Val && Val <= 4; + } 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 getReg() const override { + // As a special case until we sort out the definition of div/divu, pretend + // that $0/$zero are k_PhysRegister so that MCK_ZERO works correctly. + if (Kind == k_RegisterIndex && RegIdx.Index == 0 && + RegIdx.Kind & RegKind_GPR) + return getGPR32Reg(); // FIXME: GPR64 too - 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; + assert(Kind == k_PhysRegister && "Invalid access!"); + return PhysReg.Num; } const MCExpr *getImm() const { - assert((Kind == k_Immediate || Kind == k_LSAImm) && "Invalid access!"); + assert((Kind == k_Immediate) && "Invalid access!"); return Imm.Val; } - unsigned getMemBase() const { + int64_t getConstantImm() const { + const MCExpr *Val = getImm(); + return static_cast<const MCConstantExpr *>(Val)->getValue(); + } + + MipsOperand *getMemBase() const { assert((Kind == k_Memory) && "Invalid access!"); return Mem.Base; } @@ -415,8 +716,13 @@ public: return Mem.Off; } - static MipsOperand *CreateToken(StringRef Str, SMLoc S) { - MipsOperand *Op = new MipsOperand(k_Token); + int64_t getConstantMemOff() const { + return static_cast<const MCConstantExpr *>(getMemOff())->getValue(); + } + + static std::unique_ptr<MipsOperand> CreateToken(StringRef Str, SMLoc S, + MipsAsmParser &Parser) { + auto Op = make_unique<MipsOperand>(k_Token, Parser); Op->Tok.Data = Str.data(); Op->Tok.Length = Str.size(); Op->StartLoc = S; @@ -424,130 +730,162 @@ public: 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; + /// Create a numeric register (e.g. $1). The exact register remains + /// unresolved until an instruction successfully matches + static std::unique_ptr<MipsOperand> + CreateNumericReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + DEBUG(dbgs() << "CreateNumericReg(" << Index << ", ...)\n"); + return CreateReg(Index, RegKind_Numeric, RegInfo, S, E, Parser); } - 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; + /// Create a register that is definitely a GPR. + /// This is typically only used for named registers such as $gp. + static std::unique_ptr<MipsOperand> + CreateGPRReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_GPR, RegInfo, S, E, Parser); } - 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; + /// Create a register that is definitely a FGR. + /// This is typically only used for named registers such as $f0. + static std::unique_ptr<MipsOperand> + CreateFGRReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_FGR, RegInfo, S, E, Parser); } - 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)); + /// Create a register that is definitely an FCC. + /// This is typically only used for named registers such as $fcc0. + static std::unique_ptr<MipsOperand> + CreateFCCReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_FCC, RegInfo, S, E, Parser); } - bool isGPR64Asm() const { - return Kind == k_Register && Reg.Kind == Kind_GPR64; + /// Create a register that is definitely an ACC. + /// This is typically only used for named registers such as $ac0. + static std::unique_ptr<MipsOperand> + CreateACCReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_ACC, RegInfo, S, E, Parser); } - bool isHWRegsAsm() const { - assert((Kind == k_Register) && "Invalid access!"); - return Reg.Kind == Kind_HWRegs; + /// Create a register that is definitely an MSA128. + /// This is typically only used for named registers such as $w0. + static std::unique_ptr<MipsOperand> + CreateMSA128Reg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_MSA128, RegInfo, S, E, Parser); } - bool isCCRAsm() const { - assert((Kind == k_Register) && "Invalid access!"); - return Reg.Kind == Kind_CCRRegs; + /// Create a register that is definitely an MSACtrl. + /// This is typically only used for named registers such as $msaaccess. + static std::unique_ptr<MipsOperand> + CreateMSACtrlReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_MSACtrl, RegInfo, S, E, Parser); } - bool isAFGR64Asm() const { - return Kind == k_Register && Reg.Kind == Kind_AFGR64Regs; - } - - bool isFGR64Asm() const { - return Kind == k_Register && Reg.Kind == Kind_FGR64Regs; + static std::unique_ptr<MipsOperand> + CreateImm(const MCExpr *Val, SMLoc S, SMLoc E, MipsAsmParser &Parser) { + auto Op = make_unique<MipsOperand>(k_Immediate, Parser); + Op->Imm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; } - bool isFGR32Asm() const { - return (Kind == k_Register) && Reg.Kind == Kind_FGR32Regs; + static std::unique_ptr<MipsOperand> + CreateMem(std::unique_ptr<MipsOperand> Base, const MCExpr *Off, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + auto Op = make_unique<MipsOperand>(k_Memory, Parser); + Op->Mem.Base = Base.release(); + Op->Mem.Off = Off; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; } - bool isFGRH32Asm() const { - return (Kind == k_Register) && Reg.Kind == Kind_FGRH32Regs; + bool isGPRAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index <= 31; } - - bool isFCCRegsAsm() const { - return (Kind == k_Register) && Reg.Kind == Kind_FCCRegs; + bool isFGRAsmReg() const { + // AFGR64 is $0-$15 but we handle this in getAFGR64() + return isRegIdx() && RegIdx.Kind & RegKind_FGR && RegIdx.Index <= 31; } - - bool isACC64DSPAsm() const { - return Kind == k_Register && Reg.Kind == Kind_ACC64DSP; + bool isHWRegsAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_HWRegs && RegIdx.Index <= 31; } - - bool isLO32DSPAsm() const { - return Kind == k_Register && Reg.Kind == Kind_LO32DSP; + bool isCCRAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_CCR && RegIdx.Index <= 31; } - - bool isHI32DSPAsm() const { - return Kind == k_Register && Reg.Kind == Kind_HI32DSP; + bool isFCCAsmReg() const { + if (!(isRegIdx() && RegIdx.Kind & RegKind_FCC)) + return false; + if (!AsmParser.hasEightFccRegisters()) + return RegIdx.Index == 0; + return RegIdx.Index <= 7; } - - bool isCOP2Asm() const { return Kind == k_Register && Reg.Kind == Kind_COP2; } - - bool isMSA128BAsm() const { - return Kind == k_Register && Reg.Kind == Kind_MSA128BRegs; + bool isACCAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_ACC && RegIdx.Index <= 3; } - - bool isMSA128HAsm() const { - return Kind == k_Register && Reg.Kind == Kind_MSA128HRegs; + bool isCOP2AsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_COP2 && RegIdx.Index <= 31; } - - bool isMSA128WAsm() const { - return Kind == k_Register && Reg.Kind == Kind_MSA128WRegs; + bool isCOP3AsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_COP3 && RegIdx.Index <= 31; } - - bool isMSA128DAsm() const { - return Kind == k_Register && Reg.Kind == Kind_MSA128DRegs; + bool isMSA128AsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_MSA128 && RegIdx.Index <= 31; } - - bool isMSA128CRAsm() const { - return Kind == k_Register && Reg.Kind == Kind_MSA128CtrlRegs; + bool isMSACtrlAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_MSACtrl && RegIdx.Index <= 7; } /// getStartLoc - Get the location of the first token of this operand. - SMLoc getStartLoc() const { return StartLoc; } + SMLoc getStartLoc() const override { return StartLoc; } /// getEndLoc - Get the location of the last token of this operand. - SMLoc getEndLoc() const { return EndLoc; } + SMLoc getEndLoc() const override { return EndLoc; } - virtual void print(raw_ostream &OS) const { - llvm_unreachable("unimplemented!"); + virtual ~MipsOperand() { + switch (Kind) { + case k_Immediate: + break; + case k_Memory: + delete Mem.Base; + break; + case k_PhysRegister: + case k_RegisterIndex: + case k_Token: + break; + } + } + + void print(raw_ostream &OS) const override { + switch (Kind) { + case k_Immediate: + OS << "Imm<"; + Imm.Val->print(OS); + OS << ">"; + break; + case k_Memory: + OS << "Mem<"; + Mem.Base->print(OS); + OS << ", "; + Mem.Off->print(OS); + OS << ">"; + break; + case k_PhysRegister: + OS << "PhysReg<" << PhysReg.Num << ">"; + break; + case k_RegisterIndex: + OS << "RegIdx<" << RegIdx.Index << ":" << RegIdx.Kind << ">"; + break; + case k_Token: + OS << Tok.Data; + break; + } } }; // class MipsOperand } // namespace @@ -562,7 +900,67 @@ static const MCInstrDesc &getInstDesc(unsigned Opcode) { bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode()); + Inst.setLoc(IDLoc); + + if (MCID.isBranch() || MCID.isCall()) { + const unsigned Opcode = Inst.getOpcode(); + MCOperand Offset; + + switch (Opcode) { + default: + break; + case Mips::BEQ: + case Mips::BNE: + case Mips::BEQ_MM: + case Mips::BNE_MM: + assert(MCID.getNumOperands() == 3 && "unexpected number of operands"); + Offset = Inst.getOperand(2); + if (!Offset.isImm()) + break; // We'll deal with this situation later on when applying fixups. + if (!isIntN(inMicroMipsMode() ? 17 : 18, Offset.getImm())) + return Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), + 1LL << (inMicroMipsMode() ? 1 : 2))) + return Error(IDLoc, "branch to misaligned address"); + break; + case Mips::BGEZ: + case Mips::BGTZ: + case Mips::BLEZ: + case Mips::BLTZ: + case Mips::BGEZAL: + case Mips::BLTZAL: + case Mips::BC1F: + case Mips::BC1T: + case Mips::BGEZ_MM: + case Mips::BGTZ_MM: + case Mips::BLEZ_MM: + case Mips::BLTZ_MM: + case Mips::BGEZAL_MM: + case Mips::BLTZAL_MM: + case Mips::BC1F_MM: + case Mips::BC1T_MM: + assert(MCID.getNumOperands() == 2 && "unexpected number of operands"); + Offset = Inst.getOperand(1); + if (!Offset.isImm()) + break; // We'll deal with this situation later on when applying fixups. + if (!isIntN(inMicroMipsMode() ? 17 : 18, Offset.getImm())) + return Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), + 1LL << (inMicroMipsMode() ? 1 : 2))) + return Error(IDLoc, "branch to misaligned address"); + break; + } + } + + // SSNOP is deprecated on MIPS32r6/MIPS64r6 + // We still accept it but it is a normal nop. + if (hasMips32r6() && Inst.getOpcode() == Mips::SSNOP) { + std::string ISA = hasMips64r6() ? "MIPS64r6" : "MIPS32r6"; + Warning(IDLoc, "ssnop is deprecated for " + ISA + " and is equivalent to a " + "nop instruction"); + } + if (MCID.hasDelaySlot() && Options.isReorder()) { // If this instruction has a delay slot and .set reorder is active, // emit a NOP after it. @@ -611,7 +1009,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, } // if load/store if (needsExpansion(Inst)) - expandInstruction(Inst, IDLoc, Instructions); + return expandInstruction(Inst, IDLoc, Instructions); else Instructions.push_back(Inst); @@ -624,17 +1022,27 @@ bool MipsAsmParser::needsExpansion(MCInst &Inst) { case Mips::LoadImm32Reg: case Mips::LoadAddr32Imm: case Mips::LoadAddr32Reg: + case Mips::LoadImm64Reg: return true; default: return false; } } -void MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc, +bool MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { switch (Inst.getOpcode()) { + default: + assert(0 && "unimplemented expansion"); + return true; case Mips::LoadImm32Reg: return expandLoadImm(Inst, IDLoc, Instructions); + case Mips::LoadImm64Reg: + if (!isGP64bit()) { + Error(IDLoc, "instruction requires a CPU feature not currently enabled"); + return true; + } + return expandLoadImm(Inst, IDLoc, Instructions); case Mips::LoadAddr32Imm: return expandLoadAddressImm(Inst, IDLoc, Instructions); case Mips::LoadAddr32Reg: @@ -642,7 +1050,31 @@ void MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc, } } -void MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc, +namespace { +template <int Shift, bool PerformShift> +void createShiftOr(int64_t Value, unsigned RegNo, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + MCInst tmpInst; + if (PerformShift) { + tmpInst.setOpcode(Mips::DSLL); + tmpInst.addOperand(MCOperand::CreateReg(RegNo)); + tmpInst.addOperand(MCOperand::CreateReg(RegNo)); + tmpInst.addOperand(MCOperand::CreateImm(16)); + tmpInst.setLoc(IDLoc); + Instructions.push_back(tmpInst); + tmpInst.clear(); + } + tmpInst.setOpcode(Mips::ORi); + tmpInst.addOperand(MCOperand::CreateReg(RegNo)); + tmpInst.addOperand(MCOperand::CreateReg(RegNo)); + tmpInst.addOperand( + MCOperand::CreateImm(((Value & (0xffffLL << Shift)) >> Shift))); + tmpInst.setLoc(IDLoc); + Instructions.push_back(tmpInst); +} +} + +bool MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { MCInst tmpInst; const MCOperand &ImmOp = Inst.getOperand(1); @@ -650,8 +1082,10 @@ void MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc, const MCOperand &RegOp = Inst.getOperand(0); assert(RegOp.isReg() && "expected register operand kind"); - int ImmValue = ImmOp.getImm(); + int64_t ImmValue = ImmOp.getImm(); tmpInst.setLoc(IDLoc); + // FIXME: gas has a special case for values that are 000...1111, which + // becomes a li -1 and then a dsrl if (0 <= ImmValue && ImmValue <= 65535) { // For 0 <= j <= 65535. // li d,j => ori d,$zero,j @@ -668,25 +1102,76 @@ void MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc, 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. + } else if ((ImmValue & 0xffffffff) == ImmValue) { + // For any value of j that is representable as a 32-bit integer, create + // a sequence of: // 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); + createShiftOr<0, false>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + } else if ((ImmValue & (0xffffLL << 48)) == 0) { + if (!isGP64bit()) { + Error(IDLoc, "instruction requires a CPU feature not currently enabled"); + return true; + } + + // <------- lo32 ------> + // <------- hi32 ------> + // <- hi16 -> <- lo16 -> + // _________________________________ + // | | | | + // | 16-bytes | 16-bytes | 16-bytes | + // |__________|__________|__________| + // + // For any value of j that is representable as a 48-bit integer, create + // a sequence of: + // li d,j => lui d,hi16(j) + // ori d,d,hi16(lo32(j)) + // dsll d,d,16 + // ori d,d,lo16(lo32(j)) + tmpInst.setOpcode(Mips::LUi); tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); + tmpInst.addOperand( + MCOperand::CreateImm((ImmValue & (0xffffLL << 32)) >> 32)); + Instructions.push_back(tmpInst); + createShiftOr<16, false>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + createShiftOr<0, true>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + } else { + if (!isGP64bit()) { + Error(IDLoc, "instruction requires a CPU feature not currently enabled"); + return true; + } + + // <------- hi32 ------> <------- lo32 ------> + // <- hi16 -> <- lo16 -> + // ___________________________________________ + // | | | | | + // | 16-bytes | 16-bytes | 16-bytes | 16-bytes | + // |__________|__________|__________|__________| + // + // For any value of j that isn't representable as a 48-bit integer. + // li d,j => lui d,hi16(j) + // ori d,d,lo16(hi32(j)) + // dsll d,d,16 + // ori d,d,hi16(lo32(j)) + // dsll d,d,16 + // ori d,d,lo16(lo32(j)) + tmpInst.setOpcode(Mips::LUi); tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); - tmpInst.addOperand(MCOperand::CreateImm(ImmValue & 0xffff)); - tmpInst.setLoc(IDLoc); + tmpInst.addOperand( + MCOperand::CreateImm((ImmValue & (0xffffLL << 48)) >> 48)); Instructions.push_back(tmpInst); + createShiftOr<32, false>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + createShiftOr<16, true>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + createShiftOr<0, true>(ImmValue, RegOp.getReg(), IDLoc, Instructions); } + return false; } -void +bool MipsAsmParser::expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { MCInst tmpInst; @@ -727,9 +1212,10 @@ MipsAsmParser::expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, tmpInst.addOperand(MCOperand::CreateReg(SrcRegOp.getReg())); Instructions.push_back(tmpInst); } + return false; } -void +bool MipsAsmParser::expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { MCInst tmpInst; @@ -761,6 +1247,7 @@ MipsAsmParser::expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, tmpInst.addOperand(MCOperand::CreateImm(ImmValue & 0xffff)); Instructions.push_back(tmpInst); } + return false; } void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, @@ -771,8 +1258,6 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, 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(); @@ -792,10 +1277,46 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, 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; + // These are some of the types of expansions we perform here: + // 1) lw $8, sym => lui $8, %hi(sym) + // lw $8, %lo(sym)($8) + // 2) lw $8, offset($9) => lui $8, %hi(offset) + // add $8, $8, $9 + // lw $8, %lo(offset)($9) + // 3) lw $8, offset($8) => lui $at, %hi(offset) + // add $at, $at, $8 + // lw $8, %lo(offset)($at) + // 4) sw $8, sym => lui $at, %hi(sym) + // sw $8, %lo(sym)($at) + // 5) sw $8, offset($8) => lui $at, %hi(offset) + // add $at, $at, $8 + // sw $8, %lo(offset)($at) + // 6) ldc1 $f0, sym => lui $at, %hi(sym) + // ldc1 $f0, %lo(sym)($at) + // + // For load instructions we can use the destination register as a temporary + // if base and dst are different (examples 1 and 2) and if the base register + // is general purpose otherwise we must use $at (example 6) and error if it's + // not available. For stores we must use $at (examples 4 and 5) because we + // must not clobber the source register setting up the offset. + const MCInstrDesc &Desc = getInstDesc(Inst.getOpcode()); + int16_t RegClassOp0 = Desc.OpInfo[0].RegClass; + unsigned RegClassIDOp0 = + getContext().getRegisterInfo()->getRegClass(RegClassOp0).getID(); + bool IsGPR = (RegClassIDOp0 == Mips::GPR32RegClassID) || + (RegClassIDOp0 == Mips::GPR64RegClassID); + if (isLoad && IsGPR && (BaseRegNum != RegOpNum)) + TmpRegNum = RegOpNum; + else { + int AT = getATReg(IDLoc); + // At this point we need AT to perform the expansions and we exit if it is + // not available. + if (!AT) + return; + TmpRegNum = getReg( + (isGP64bit()) ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, AT); + } + TempInst.setOpcode(Mips::LUi); TempInst.addOperand(MCOperand::CreateReg(TmpRegNum)); if (isImmOpnd) @@ -823,7 +1344,7 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, TempInst.addOperand(MCOperand::CreateReg(BaseRegNum)); Instructions.push_back(TempInst); TempInst.clear(); - // And finaly, create original instruction with low part + // And finally, create original instruction with low part // of offset and new base. TempInst.setOpcode(Inst.getOpcode()); TempInst.addOperand(MCOperand::CreateReg(RegOpNum)); @@ -845,10 +1366,24 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, TempInst.clear(); } -bool MipsAsmParser::MatchAndEmitInstruction( - SMLoc IDLoc, unsigned &Opcode, - SmallVectorImpl<MCParsedAsmOperand *> &Operands, MCStreamer &Out, - unsigned &ErrorInfo, bool MatchingInlineAsm) { +unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) { + // As described by the Mips32r2 spec, the registers Rd and Rs for + // jalr.hb must be different. + unsigned Opcode = Inst.getOpcode(); + + if (Opcode == Mips::JALR_HB && + (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg())) + return Match_RequiresDifferentSrcAndDst; + + return Match_Success; +} + +bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, + MCStreamer &Out, + unsigned &ErrorInfo, + bool MatchingInlineAsm) { + MCInst Inst; SmallVector<MCInst, 8> Instructions; unsigned MatchResult = @@ -861,7 +1396,7 @@ bool MipsAsmParser::MatchAndEmitInstruction( if (processInstruction(Inst, IDLoc, Instructions)) return true; for (unsigned i = 0; i < Instructions.size(); i++) - Out.EmitInstruction(Instructions[i]); + Out.EmitInstruction(Instructions[i], STI); return false; } case Match_MissingFeature: @@ -873,7 +1408,7 @@ bool MipsAsmParser::MatchAndEmitInstruction( if (ErrorInfo >= Operands.size()) return Error(IDLoc, "too few operands for instruction"); - ErrorLoc = ((MipsOperand *)Operands[ErrorInfo])->getStartLoc(); + ErrorLoc = ((MipsOperand &)*Operands[ErrorInfo]).getStartLoc(); if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc; } @@ -882,18 +1417,28 @@ bool MipsAsmParser::MatchAndEmitInstruction( } case Match_MnemonicFail: return Error(IDLoc, "invalid instruction"); + case Match_RequiresDifferentSrcAndDst: + return Error(IDLoc, "source and destination must be different"); } return true; } +void MipsAsmParser::WarnIfAssemblerTemporary(int RegIndex, SMLoc Loc) { + if ((RegIndex != 0) && ((int)Options.getATRegNum() == RegIndex)) { + if (RegIndex == 1) + Warning(Loc, "Used $at without \".set noat\""); + else + Warning(Loc, Twine("Used $") + Twine(RegIndex) + " with \".set at=$" + + Twine(RegIndex) + "\""); + } +} + int MipsAsmParser::matchCPURegisterName(StringRef Name) { int CC; - if (Name == "at") - return getATReg(); - CC = StringSwitch<unsigned>(Name) .Case("zero", 0) + .Case("at", 1) .Case("a0", 4) .Case("a1", 5) .Case("a2", 6) @@ -910,9 +1455,10 @@ int MipsAsmParser::matchCPURegisterName(StringRef Name) { .Case("s7", 23) .Case("k0", 26) .Case("k1", 27) + .Case("gp", 28) .Case("sp", 29) .Case("fp", 30) - .Case("gp", 28) + .Case("s8", 30) .Case("ra", 31) .Case("t0", 8) .Case("t1", 9) @@ -926,22 +1472,23 @@ int MipsAsmParser::matchCPURegisterName(StringRef Name) { .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 (isABI_N32() || isABI_N64()) { + // 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 (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); + if (CC == -1) + CC = StringSwitch<unsigned>(Name) + .Case("a4", 8) + .Case("a5", 9) + .Case("a6", 10) + .Case("a7", 11) + .Case("kt0", 26) + .Case("kt1", 27) + .Default(-1); + } return CC; } @@ -1017,59 +1564,6 @@ int MipsAsmParser::matchMSA128CtrlRegisterName(StringRef Name) { 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; @@ -1078,53 +1572,34 @@ bool MipsAssemblerOptions::setATReg(unsigned Reg) { return true; } -int MipsAsmParser::getATReg() { return Options.getATRegNum(); } +int MipsAsmParser::getATReg(SMLoc Loc) { + int AT = Options.getATRegNum(); + if (AT == 0) + reportParseError(Loc, + "Pseudo instruction requires $at, which is not available"); + return AT; +} unsigned MipsAsmParser::getReg(int RC, int RegNo) { return *(getContext().getRegisterInfo()->getRegClass(RC).begin() + RegNo); } +unsigned MipsAsmParser::getGPR(int RegNo) { + return getReg(isGP64bit() ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, + RegNo); +} + int MipsAsmParser::matchRegisterByNumber(unsigned RegNum, unsigned RegClass) { if (RegNum > - getContext().getRegisterInfo()->getRegClass(RegClass).getNumRegs()) + getContext().getRegisterInfo()->getRegClass(RegClass).getNumRegs() - 1) 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; +bool MipsAsmParser::ParseOperand(OperandVector &Operands, StringRef Mnemonic) { + DEBUG(dbgs() << "ParseOperand\n"); - 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); @@ -1136,6 +1611,8 @@ MipsAsmParser::ParseOperand(SmallVectorImpl<MCParsedAsmOperand *> &Operands, if (ResTy == MatchOperand_ParseFail) return true; + DEBUG(dbgs() << ".. Generic Parser\n"); + switch (getLexer().getKind()) { default: Error(Parser.getTok().getLoc(), "unexpected token in operand"); @@ -1143,29 +1620,15 @@ MipsAsmParser::ParseOperand(SmallVectorImpl<MCParsedAsmOperand *> &Operands, 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(); - } + // Almost all registers have been parsed by custom parsers. There is only + // one exception to this. $zero (and it's alias $0) will reach this point + // for div, divu, and similar instructions because it is not an operand + // to the instruction definition but an explicit register. Special case + // this situation for now. + if (ParseAnyRegister(Operands) != MatchOperand_NoMatch) return false; - } + // Maybe it is a symbol reference. StringRef Identifier; if (Parser.parseIdentifier(Identifier)) @@ -1177,47 +1640,19 @@ MipsAsmParser::ParseOperand(SmallVectorImpl<MCParsedAsmOperand *> &Operands, const MCExpr *Res = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None, getContext()); - Operands.push_back(MipsOperand::CreateImm(Res, S, E)); + Operands.push_back(MipsOperand::CreateImm(Res, S, E, *this)); 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::Tilde: 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; + DEBUG(dbgs() << ".. generic integer\n"); + OperandMatchResultTy ResTy = ParseImm(Operands); + return ResTy != MatchOperand_Success; } case AsmToken::Percent: { // It is a symbol reference or constant expression. @@ -1228,7 +1663,7 @@ MipsAsmParser::ParseOperand(SmallVectorImpl<MCParsedAsmOperand *> &Operands, SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - Operands.push_back(MipsOperand::CreateImm(IdVal, S, E)); + Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this)); return false; } // case AsmToken::Percent } // switch(getLexer().getKind()) @@ -1240,23 +1675,30 @@ const MCExpr *MipsAsmParser::evaluateRelocExpr(const MCExpr *Expr, 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"); + // It's a constant, evaluate reloc value. + int16_t Val; + switch (getVariantKind(RelocStr)) { + case MCSymbolRefExpr::VK_Mips_ABS_LO: + // Get the 1st 16-bits. + Val = MCE->getValue() & 0xffff; + break; + case MCSymbolRefExpr::VK_Mips_ABS_HI: + // Get the 2nd 16-bits. Also add 1 if bit 15 is 1, to compensate for low + // 16 bits being negative. + Val = ((MCE->getValue() + 0x8000) >> 16) & 0xffff; + break; + case MCSymbolRefExpr::VK_Mips_HIGHER: + // Get the 3rd 16-bits. + Val = ((MCE->getValue() + 0x80008000LL) >> 32) & 0xffff; + break; + case MCSymbolRefExpr::VK_Mips_HIGHEST: + // Get the 4th 16-bits. + Val = ((MCE->getValue() + 0x800080008000LL) >> 48) & 0xffff; + break; + default: + report_fatal_error("Unsupported reloc value!"); } - return Res; + return MCConstantExpr::Create(Val, getContext()); } if (const MCSymbolRefExpr *MSRE = dyn_cast<MCSymbolRefExpr>(Expr)) { @@ -1268,6 +1710,12 @@ const MCExpr *MipsAsmParser::evaluateRelocExpr(const MCExpr *Expr, } if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr)) { + MCSymbolRefExpr::VariantKind VK = getVariantKind(RelocStr); + + // Try to create target expression. + if (MipsMCExpr::isSupportedBinaryExpr(VK, BE)) + return MipsMCExpr::Create(VK, Expr, getContext()); + const MCExpr *LExp = evaluateRelocExpr(BE->getLHS(), RelocStr); const MCExpr *RExp = evaluateRelocExpr(BE->getRHS(), RelocStr); Res = MCBinaryExpr::Create(BE->getOpcode(), LExp, RExp, getContext()); @@ -1298,8 +1746,8 @@ bool MipsAsmParser::isEvaluated(const MCExpr *Expr) { } case MCExpr::Unary: return isEvaluated(cast<MCUnaryExpr>(Expr)->getSubExpr()); - default: - return false; + case MCExpr::Target: + return true; } return false; } @@ -1348,9 +1796,27 @@ bool MipsAsmParser::parseRelocOperand(const MCExpr *&Res) { bool MipsAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { - StartLoc = Parser.getTok().getLoc(); - RegNo = tryParseRegister(isMips64()); - EndLoc = Parser.getTok().getLoc(); + SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> Operands; + OperandMatchResultTy ResTy = ParseAnyRegister(Operands); + if (ResTy == MatchOperand_Success) { + assert(Operands.size() == 1); + MipsOperand &Operand = static_cast<MipsOperand &>(*Operands.front()); + StartLoc = Operand.getStartLoc(); + EndLoc = Operand.getEndLoc(); + + // AFAIK, we only support numeric registers and named GPR's in CFI + // directives. + // Don't worry about eating tokens before failing. Using an unrecognised + // register is a parse error. + if (Operand.isGPRAsmReg()) { + // Resolve to GPR32 or GPR64 appropriately. + RegNo = isGP64bit() ? Operand.getGPR64Reg() : Operand.getGPR32Reg(); + } + + return (RegNo == (unsigned)-1); + } + + assert(Operands.size() == 0); return (RegNo == (unsigned)-1); } @@ -1382,10 +1848,10 @@ bool MipsAsmParser::parseMemOffset(const MCExpr *&Res, bool isParenExpr) { return Result; } -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - - const MCExpr *IdVal = 0; +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseMemOperand(OperandVector &Operands) { + DEBUG(dbgs() << "parseMemOperand\n"); + const MCExpr *IdVal = nullptr; SMLoc S; bool isParenExpr = false; MipsAsmParser::OperandMatchResultTy Res = MatchOperand_NoMatch; @@ -1403,11 +1869,11 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( 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") { + 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)); + Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this)); return MatchOperand_Success; } if (Tok.is(AsmToken::EndOfStatement)) { @@ -1415,8 +1881,11 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( 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)); + // "Base" will be managed by k_Memory. + auto Base = MipsOperand::CreateGPRReg(0, getContext().getRegisterInfo(), + S, E, *this); + Operands.push_back( + MipsOperand::CreateMem(std::move(Base), IdVal, S, E, *this)); return MatchOperand_Success; } Error(Parser.getTok().getLoc(), "'(' expected"); @@ -1426,8 +1895,7 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( Parser.Lex(); // Eat the '(' token. } - Res = parseRegs(Operands, isMips64() ? (int)MipsOperand::Kind_GPR64 - : (int)MipsOperand::Kind_GPR32); + Res = ParseAnyRegister(Operands); if (Res != MatchOperand_Success) return Res; @@ -1440,13 +1908,14 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( Parser.Lex(); // Eat the ')' token. - if (IdVal == 0) + if (!IdVal) IdVal = MCConstantExpr::Create(0, getContext()); // Replace the register operand with the memory operand. - MipsOperand *op = static_cast<MipsOperand *>(Operands.back()); - int RegNo = op->getReg(); + std::unique_ptr<MipsOperand> op( + static_cast<MipsOperand *>(Operands.back().release())); // Remove the register from the operands. + // "op" will be managed by k_Memory. Operands.pop_back(); // Add the memory operand. if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(IdVal)) { @@ -1458,603 +1927,195 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( getContext()); } - Operands.push_back(MipsOperand::CreateMem(RegNo, IdVal, S, E)); - delete op; + Operands.push_back(MipsOperand::CreateMem(std::move(op), IdVal, S, E, *this)); 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; +bool MipsAsmParser::searchSymbolAlias(OperandVector &Operands) { - 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) + 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; - Reg = getReg(regKindToRegClass(RegKind), Reg); - } else { - return false; + if (Expr->getKind() == MCExpr::SymbolRef) { + const MCSymbolRefExpr *Ref = static_cast<const MCSymbolRefExpr *>(Expr); + const StringRef DefSymbol = Ref->getSymbol().getName(); + if (DefSymbol.startswith("$")) { + OperandMatchResultTy ResTy = + MatchAnyRegisterNameWithoutDollar(Operands, DefSymbol.substr(1), S); + if (ResTy == MatchOperand_Success) { + Parser.Lex(); + return true; + } else if (ResTy == MatchOperand_ParseFail) + llvm_unreachable("Should never ParseFail"); + return false; + } + } else if (Expr->getKind() == MCExpr::Constant) { + Parser.Lex(); + const MCConstantExpr *Const = static_cast<const MCConstantExpr *>(Expr); + Operands.push_back( + MipsOperand::CreateImm(Const, S, Parser.getTok().getLoc(), *this)); + return true; + } } - - 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; + return false; } 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(); - } +MipsAsmParser::MatchAnyRegisterNameWithoutDollar(OperandVector &Operands, + StringRef Identifier, + SMLoc S) { + int Index = matchCPURegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::CreateGPRReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); 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; + Index = matchFPURegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::CreateFGRReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; } -} -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; + Index = matchFCCRegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::CreateFCCReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; } - 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)) + Index = matchACRegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::CreateACCReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); 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. - + Index = matchMSA128RegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::CreateMSA128Reg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); 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; + Index = matchMSA128CtrlRegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::CreateMSACtrlReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; } - 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); + return MatchOperand_NoMatch; } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseFGR32Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_FGR32Regs); -} +MipsAsmParser::MatchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S) { + auto Token = Parser.getLexer().peekTok(false); -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseFGRH32Regs( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_FGRH32Regs); -} + if (Token.is(AsmToken::Identifier)) { + DEBUG(dbgs() << ".. identifier\n"); + StringRef Identifier = Token.getIdentifier(); + OperandMatchResultTy ResTy = + MatchAnyRegisterNameWithoutDollar(Operands, Identifier, S); + return ResTy; + } else if (Token.is(AsmToken::Integer)) { + DEBUG(dbgs() << ".. integer\n"); + Operands.push_back(MipsOperand::CreateNumericReg( + Token.getIntVal(), getContext().getRegisterInfo(), S, Token.getLoc(), + *this)); + return MatchOperand_Success; + } -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseFCCRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_FCCRegs); -} + DEBUG(dbgs() << Parser.getTok().getKind() << "\n"); -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseACC64DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_ACC64DSP); + return MatchOperand_NoMatch; } 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; +MipsAsmParser::ParseAnyRegister(OperandVector &Operands) { + DEBUG(dbgs() << "ParseAnyRegister\n"); - 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; + auto Token = Parser.getTok(); - StringRef NumString = Tok.getIdentifier().substr(2); + SMLoc S = Token.getLoc(); - unsigned IntVal; - if (NumString.getAsInteger(10, IntVal)) + if (Token.isNot(AsmToken::Dollar)) { + DEBUG(dbgs() << ".. !$ -> try sym aliasing\n"); + if (Token.is(AsmToken::Identifier)) { + if (searchSymbolAlias(Operands)) + return MatchOperand_Success; + } + DEBUG(dbgs() << ".. !symalias -> NoMatch\n"); return MatchOperand_NoMatch; + } + DEBUG(dbgs() << ".. $\n"); - 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; + OperandMatchResultTy ResTy = MatchAnyRegisterWithoutDollar(Operands, S); + if (ResTy == MatchOperand_Success) { + Parser.Lex(); // $ + Parser.Lex(); // identifier + } + return ResTy; } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseHI32DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - // If the first token is not '$' we have an error. - if (Parser.getTok().isNot(AsmToken::Dollar)) +MipsAsmParser::ParseImm(OperandVector &Operands) { + switch (getLexer().getKind()) { + default: return MatchOperand_NoMatch; + case AsmToken::LParen: + case AsmToken::Minus: + case AsmToken::Plus: + case AsmToken::Integer: + case AsmToken::Tilde: + case AsmToken::String: + break; + } + const MCExpr *IdVal; SMLoc S = Parser.getTok().getLoc(); - 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); + if (getParser().parseExpression(IdVal)) + return MatchOperand_ParseFail; - Parser.Lex(); // Eat the register number. + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this)); 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::ParseJumpTarget(OperandVector &Operands) { + DEBUG(dbgs() << "ParseJumpTarget\n"); -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128WRegs( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128WRegs); -} + SMLoc S = getLexer().getLoc(); -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128DRegs( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128DRegs); -} + // Integers and expressions are acceptable + OperandMatchResultTy ResTy = ParseImm(Operands); + if (ResTy != MatchOperand_NoMatch) + return ResTy; -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128CtrlRegs( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseMSACtrlRegs(Operands, (int)MipsOperand::Kind_MSA128CtrlRegs); -} + // Registers are a valid target and have priority over symbols. + ResTy = ParseAnyRegister(Operands); + if (ResTy != MatchOperand_NoMatch) + return ResTy; -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; - } + const MCExpr *Expr = nullptr; + if (Parser.parseExpression(Expr)) { + // We have no way of knowing if a symbol was consumed so we must ParseFail + return MatchOperand_ParseFail; } - 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); + Operands.push_back( + MipsOperand::CreateImm(Expr, S, getLexer().getLoc(), *this)); + return MatchOperand_Success; } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseInvNum(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { +MipsAsmParser::parseInvNum(OperandVector &Operands) { const MCExpr *IdVal; // If the first token is '$' we may have register operand. if (Parser.getTok().is(AsmToken::Dollar)) @@ -2067,12 +2128,12 @@ MipsAsmParser::parseInvNum(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { 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)); + MCConstantExpr::Create(0 - Val, getContext()), S, E, *this)); return MatchOperand_Success; } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseLSAImm(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { +MipsAsmParser::ParseLSAImm(OperandVector &Operands) { switch (getLexer().getKind()) { default: return MatchOperand_NoMatch; @@ -2105,8 +2166,8 @@ MipsAsmParser::parseLSAImm(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { return MatchOperand_ParseFail; } - Operands.push_back(MipsOperand::CreateLSAImm(Expr, S, - Parser.getTok().getLoc())); + Operands.push_back( + MipsOperand::CreateImm(Expr, S, Parser.getTok().getLoc(), *this)); return MatchOperand_Success; } @@ -2131,21 +2192,90 @@ MCSymbolRefExpr::VariantKind MipsAsmParser::getVariantKind(StringRef Symbol) { .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) + .Case("got_hi", MCSymbolRefExpr::VK_Mips_GOT_HI16) + .Case("got_lo", MCSymbolRefExpr::VK_Mips_GOT_LO16) + .Case("call_hi", MCSymbolRefExpr::VK_Mips_CALL_HI16) + .Case("call_lo", MCSymbolRefExpr::VK_Mips_CALL_LO16) + .Case("higher", MCSymbolRefExpr::VK_Mips_HIGHER) + .Case("highest", MCSymbolRefExpr::VK_Mips_HIGHEST) + .Case("pcrel_hi", MCSymbolRefExpr::VK_Mips_PCREL_HI16) + .Case("pcrel_lo", MCSymbolRefExpr::VK_Mips_PCREL_LO16) .Default(MCSymbolRefExpr::VK_None); + assert(VK != MCSymbolRefExpr::VK_None); + return VK; } -bool MipsAsmParser::ParseInstruction( - ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { +/// Sometimes (i.e. load/stores) the operand may be followed immediately by +/// either this. +/// ::= '(', register, ')' +/// handle it before we iterate so we don't get tripped up by the lack of +/// a comma. +bool MipsAsmParser::ParseParenSuffix(StringRef Name, OperandVector &Operands) { + if (getLexer().is(AsmToken::LParen)) { + Operands.push_back( + MipsOperand::CreateToken("(", getLexer().getLoc(), *this)); + Parser.Lex(); + if (ParseOperand(Operands, Name)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + if (Parser.getTok().isNot(AsmToken::RParen)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token, expected ')'"); + } + Operands.push_back( + MipsOperand::CreateToken(")", getLexer().getLoc(), *this)); + Parser.Lex(); + } + return false; +} + +/// Sometimes (i.e. in MSA) the operand may be followed immediately by +/// either one of these. +/// ::= '[', register, ']' +/// ::= '[', integer, ']' +/// handle it before we iterate so we don't get tripped up by the lack of +/// a comma. +bool MipsAsmParser::ParseBracketSuffix(StringRef Name, + OperandVector &Operands) { + if (getLexer().is(AsmToken::LBrac)) { + Operands.push_back( + MipsOperand::CreateToken("[", getLexer().getLoc(), *this)); + Parser.Lex(); + if (ParseOperand(Operands, Name)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + if (Parser.getTok().isNot(AsmToken::RBrac)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token, expected ']'"); + } + Operands.push_back( + MipsOperand::CreateToken("]", getLexer().getLoc(), *this)); + Parser.Lex(); + } + return false; +} + +bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) { + DEBUG(dbgs() << "ParseInstruction\n"); + // We have reached first instruction, module directive after + // this is forbidden. + getTargetStreamer().setCanHaveModuleDir(false); // 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)); + Operands.push_back(MipsOperand::CreateToken(Name, NameLoc, *this)); // Read the remaining operands. if (getLexer().isNot(AsmToken::EndOfStatement)) { @@ -2155,6 +2285,9 @@ bool MipsAsmParser::ParseInstruction( Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token in argument list"); } + if (getLexer().is(AsmToken::LBrac) && ParseBracketSuffix(Name, Operands)) + return true; + // AFAIK, parenthesis suffixes are never on the first operand while (getLexer().is(AsmToken::Comma)) { Parser.Lex(); // Eat the comma. @@ -2164,6 +2297,13 @@ bool MipsAsmParser::ParseInstruction( Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token in argument list"); } + // Parse bracket and parenthesis suffixes before we iterate + if (getLexer().is(AsmToken::LBrac)) { + if (ParseBracketSuffix(Name, Operands)) + return true; + } else if (getLexer().is(AsmToken::LParen) && + ParseParenSuffix(Name, Operands)) + return true; } } if (getLexer().isNot(AsmToken::EndOfStatement)) { @@ -2175,12 +2315,16 @@ bool MipsAsmParser::ParseInstruction( return false; } -bool MipsAsmParser::reportParseError(StringRef ErrorMsg) { +bool MipsAsmParser::reportParseError(Twine ErrorMsg) { SMLoc Loc = getLexer().getLoc(); Parser.eatToEndOfStatement(); return Error(Loc, ErrorMsg); } +bool MipsAsmParser::reportParseError(SMLoc Loc, Twine ErrorMsg) { + return Error(Loc, ErrorMsg); +} + bool MipsAsmParser::parseSetNoAtDirective() { // Line should look like: ".set noat". // set at reg to 0. @@ -2222,7 +2366,7 @@ bool MipsAsmParser::parseSetAtDirective() { return false; } - if (AtRegNo < 1 || AtRegNo > 31) { + if (AtRegNo < 0 || AtRegNo > 31) { reportParseError("unexpected token in statement"); return false; } @@ -2253,6 +2397,7 @@ bool MipsAsmParser::parseSetReorderDirective() { return false; } Options.setReorder(); + getTargetStreamer().emitDirectiveSetReorder(); Parser.Lex(); // Consume the EndOfStatement. return false; } @@ -2265,6 +2410,7 @@ bool MipsAsmParser::parseSetNoReorderDirective() { return false; } Options.setNoreorder(); + getTargetStreamer().emitDirectiveSetNoReorder(); Parser.Lex(); // Consume the EndOfStatement. return false; } @@ -2297,6 +2443,44 @@ bool MipsAsmParser::parseSetNoMacroDirective() { return false; } +bool MipsAsmParser::parseSetNoMips16Directive() { + 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; + } + // For now do nothing. + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetFpDirective() { + MipsABIFlagsSection::FpABIKind FpAbiVal; + // Line can be: .set fp=32 + // .set fp=xx + // .set fp=64 + Parser.Lex(); // Eat fp token + AsmToken Tok = Parser.getTok(); + if (Tok.isNot(AsmToken::Equal)) { + reportParseError("unexpected token in statement"); + return false; + } + Parser.Lex(); // Eat '=' token. + Tok = Parser.getTok(); + + if (!parseFpABIValue(FpAbiVal, ".set")) + return false; + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token in statement"); + return false; + } + getTargetStreamer().emitDirectiveSetFp(FpAbiVal); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + bool MipsAsmParser::parseSetAssignment() { StringRef Name; const MCExpr *Value; @@ -2308,22 +2492,7 @@ bool MipsAsmParser::parseSetAssignment() { 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)) + if (Parser.parseExpression(Value)) return reportParseError("expected valid expression after comma"); // Check if the Name already exists as a symbol. @@ -2336,6 +2505,154 @@ bool MipsAsmParser::parseSetAssignment() { return false; } +bool MipsAsmParser::parseSetFeature(uint64_t Feature) { + Parser.Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token in .set directive"); + + switch (Feature) { + default: + llvm_unreachable("Unimplemented feature"); + case Mips::FeatureDSP: + setFeatureBits(Mips::FeatureDSP, "dsp"); + getTargetStreamer().emitDirectiveSetDsp(); + break; + case Mips::FeatureMicroMips: + getTargetStreamer().emitDirectiveSetMicroMips(); + break; + case Mips::FeatureMips16: + getTargetStreamer().emitDirectiveSetMips16(); + break; + case Mips::FeatureMips32r2: + setFeatureBits(Mips::FeatureMips32r2, "mips32r2"); + getTargetStreamer().emitDirectiveSetMips32R2(); + break; + case Mips::FeatureMips64: + setFeatureBits(Mips::FeatureMips64, "mips64"); + getTargetStreamer().emitDirectiveSetMips64(); + break; + case Mips::FeatureMips64r2: + setFeatureBits(Mips::FeatureMips64r2, "mips64r2"); + getTargetStreamer().emitDirectiveSetMips64R2(); + break; + } + return false; +} + +bool MipsAsmParser::eatComma(StringRef ErrorStr) { + if (getLexer().isNot(AsmToken::Comma)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, ErrorStr); + } + + Parser.Lex(); // Eat the comma. + return true; +} + +bool MipsAsmParser::parseDirectiveCPLoad(SMLoc Loc) { + if (Options.isReorder()) + Warning(Loc, ".cpload in reorder section"); + + // FIXME: Warn if cpload is used in Mips16 mode. + + SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> Reg; + OperandMatchResultTy ResTy = ParseAnyRegister(Reg); + if (ResTy == MatchOperand_NoMatch || ResTy == MatchOperand_ParseFail) { + reportParseError("expected register containing function address"); + return false; + } + + MipsOperand &RegOpnd = static_cast<MipsOperand &>(*Reg[0]); + if (!RegOpnd.isGPRAsmReg()) { + reportParseError(RegOpnd.getStartLoc(), "invalid register"); + return false; + } + + getTargetStreamer().emitDirectiveCpload(RegOpnd.getGPR32Reg()); + return false; +} + +bool MipsAsmParser::parseDirectiveCPSetup() { + unsigned FuncReg; + unsigned Save; + bool SaveIsReg = true; + + SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> TmpReg; + OperandMatchResultTy ResTy = ParseAnyRegister(TmpReg); + if (ResTy == MatchOperand_NoMatch) { + reportParseError("expected register containing function address"); + Parser.eatToEndOfStatement(); + return false; + } + + MipsOperand &FuncRegOpnd = static_cast<MipsOperand &>(*TmpReg[0]); + if (!FuncRegOpnd.isGPRAsmReg()) { + reportParseError(FuncRegOpnd.getStartLoc(), "invalid register"); + Parser.eatToEndOfStatement(); + return false; + } + + FuncReg = FuncRegOpnd.getGPR32Reg(); + TmpReg.clear(); + + if (!eatComma("expected comma parsing directive")) + return true; + + ResTy = ParseAnyRegister(TmpReg); + if (ResTy == MatchOperand_NoMatch) { + const AsmToken &Tok = Parser.getTok(); + if (Tok.is(AsmToken::Integer)) { + Save = Tok.getIntVal(); + SaveIsReg = false; + Parser.Lex(); + } else { + reportParseError("expected save register or stack offset"); + Parser.eatToEndOfStatement(); + return false; + } + } else { + MipsOperand &SaveOpnd = static_cast<MipsOperand &>(*TmpReg[0]); + if (!SaveOpnd.isGPRAsmReg()) { + reportParseError(SaveOpnd.getStartLoc(), "invalid register"); + Parser.eatToEndOfStatement(); + return false; + } + Save = SaveOpnd.getGPR32Reg(); + } + + if (!eatComma("expected comma parsing directive")) + return true; + + StringRef Name; + if (Parser.parseIdentifier(Name)) + reportParseError("expected identifier"); + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + + getTargetStreamer().emitDirectiveCpsetup(FuncReg, Save, *Sym, SaveIsReg); + return false; +} + +bool MipsAsmParser::parseDirectiveNaN() { + if (getLexer().isNot(AsmToken::EndOfStatement)) { + const AsmToken &Tok = Parser.getTok(); + + if (Tok.getString() == "2008") { + Parser.Lex(); + getTargetStreamer().emitDirectiveNaN2008(); + return false; + } else if (Tok.getString() == "legacy") { + Parser.Lex(); + getTargetStreamer().emitDirectiveNaNLegacy(); + return false; + } + } + // If we don't recognize the option passed to the .nan + // directive (e.g. no option or unknown option), emit an error. + reportParseError("invalid option in .nan directive"); + return false; +} + bool MipsAsmParser::parseDirectiveSet() { // Get the next token. @@ -2345,6 +2662,8 @@ bool MipsAsmParser::parseDirectiveSet() { return parseSetNoAtDirective(); } else if (Tok.getString() == "at") { return parseSetAtDirective(); + } else if (Tok.getString() == "fp") { + return parseSetFpDirective(); } else if (Tok.getString() == "reorder") { return parseSetReorderDirective(); } else if (Tok.getString() == "noreorder") { @@ -2353,14 +2672,24 @@ bool MipsAsmParser::parseDirectiveSet() { return parseSetMacroDirective(); } else if (Tok.getString() == "nomacro") { return parseSetNoMacroDirective(); + } else if (Tok.getString() == "mips16") { + return parseSetFeature(Mips::FeatureMips16); } else if (Tok.getString() == "nomips16") { - // Ignore this directive for now. - Parser.eatToEndOfStatement(); - return false; + return parseSetNoMips16Directive(); } else if (Tok.getString() == "nomicromips") { - // Ignore this directive for now. + getTargetStreamer().emitDirectiveSetNoMicroMips(); Parser.eatToEndOfStatement(); return false; + } else if (Tok.getString() == "micromips") { + return parseSetFeature(Mips::FeatureMicroMips); + } else if (Tok.getString() == "mips32r2") { + return parseSetFeature(Mips::FeatureMips32r2); + } else if (Tok.getString() == "mips64") { + return parseSetFeature(Mips::FeatureMips64); + } else if (Tok.getString() == "mips64r2") { + return parseSetFeature(Mips::FeatureMips64r2); + } else if (Tok.getString() == "dsp") { + return parseSetFeature(Mips::FeatureDSP); } else { // It is just an identifier, look for an assignment. parseSetAssignment(); @@ -2370,37 +2699,9 @@ bool MipsAsmParser::parseDirectiveSet() { 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 +/// parseDataDirective /// ::= .word [ expression (, expression)* ] -bool MipsAsmParser::parseDirectiveWord(unsigned Size, SMLoc L) { +bool MipsAsmParser::parseDataDirective(unsigned Size, SMLoc L) { if (getLexer().isNot(AsmToken::EndOfStatement)) { for (;;) { const MCExpr *Value; @@ -2439,10 +2740,200 @@ bool MipsAsmParser::parseDirectiveGpWord() { return false; } -bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { +/// parseDirectiveGpDWord +/// ::= .gpdword local_sym +bool MipsAsmParser::parseDirectiveGpDWord() { + const MCExpr *Value; + // EmitGPRel64Value requires an expression, so we are using base class + // method to evaluate the expression. + if (getParser().parseExpression(Value)) + return true; + getParser().getStreamer().EmitGPRel64Value(Value); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), "unexpected token in directive"); + Parser.Lex(); // Eat EndOfStatement token. + return false; +} + +bool MipsAsmParser::parseDirectiveOption() { + // Get the option token. + AsmToken Tok = Parser.getTok(); + // At the moment only identifiers are supported. + if (Tok.isNot(AsmToken::Identifier)) { + Error(Parser.getTok().getLoc(), "unexpected token in .option directive"); + Parser.eatToEndOfStatement(); + return false; + } + + StringRef Option = Tok.getIdentifier(); + + if (Option == "pic0") { + getTargetStreamer().emitDirectiveOptionPic0(); + Parser.Lex(); + if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { + Error(Parser.getTok().getLoc(), + "unexpected token in .option pic0 directive"); + Parser.eatToEndOfStatement(); + } + return false; + } + + if (Option == "pic2") { + getTargetStreamer().emitDirectiveOptionPic2(); + Parser.Lex(); + if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { + Error(Parser.getTok().getLoc(), + "unexpected token in .option pic2 directive"); + Parser.eatToEndOfStatement(); + } + return false; + } + + // Unknown option. + Warning(Parser.getTok().getLoc(), "unknown option in .option directive"); + Parser.eatToEndOfStatement(); + return false; +} + +/// parseDirectiveModule +/// ::= .module oddspreg +/// ::= .module nooddspreg +/// ::= .module fp=value +bool MipsAsmParser::parseDirectiveModule() { + MCAsmLexer &Lexer = getLexer(); + SMLoc L = Lexer.getLoc(); + + if (!getTargetStreamer().getCanHaveModuleDir()) { + // TODO : get a better message. + reportParseError(".module directive must appear before any code"); + return false; + } + + if (Lexer.is(AsmToken::Identifier)) { + StringRef Option = Parser.getTok().getString(); + Parser.Lex(); + + if (Option == "oddspreg") { + getTargetStreamer().emitDirectiveModuleOddSPReg(true, isABI_O32()); + clearFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("Expected end of statement"); + return false; + } + + return false; + } else if (Option == "nooddspreg") { + if (!isABI_O32()) { + Error(L, "'.module nooddspreg' requires the O32 ABI"); + return false; + } + getTargetStreamer().emitDirectiveModuleOddSPReg(false, isABI_O32()); + setFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("Expected end of statement"); + return false; + } + + return false; + } else if (Option == "fp") { + return parseDirectiveModuleFP(); + } + + return Error(L, "'" + Twine(Option) + "' is not a valid .module option."); + } + + return false; +} + +/// parseDirectiveModuleFP +/// ::= =32 +/// ::= =xx +/// ::= =64 +bool MipsAsmParser::parseDirectiveModuleFP() { + MCAsmLexer &Lexer = getLexer(); + + if (Lexer.isNot(AsmToken::Equal)) { + reportParseError("unexpected token in statement"); + return false; + } + Parser.Lex(); // Eat '=' token. + + MipsABIFlagsSection::FpABIKind FpABI; + if (!parseFpABIValue(FpABI, ".module")) + return false; + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token in statement"); + return false; + } + + // Emit appropriate flags. + getTargetStreamer().emitDirectiveModuleFP(FpABI, isABI_O32()); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI, + StringRef Directive) { + MCAsmLexer &Lexer = getLexer(); + + if (Lexer.is(AsmToken::Identifier)) { + StringRef Value = Parser.getTok().getString(); + Parser.Lex(); + + if (Value != "xx") { + reportParseError("unsupported value, expected 'xx', '32' or '64'"); + return false; + } + + if (!isABI_O32()) { + reportParseError("'" + Directive + " fp=xx' requires the O32 ABI"); + return false; + } + + FpABI = MipsABIFlagsSection::FpABIKind::XX; + return true; + } + + if (Lexer.is(AsmToken::Integer)) { + unsigned Value = Parser.getTok().getIntVal(); + Parser.Lex(); + + if (Value != 32 && Value != 64) { + reportParseError("unsupported value, expected 'xx', '32' or '64'"); + return false; + } + + if (Value == 32) { + if (!isABI_O32()) { + reportParseError("'" + Directive + " fp=32' requires the O32 ABI"); + return false; + } + + FpABI = MipsABIFlagsSection::FpABIKind::S32; + } else + FpABI = MipsABIFlagsSection::FpABIKind::S64; + + return true; + } + + return false; +} + +bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { StringRef IDVal = DirectiveID.getString(); + if (IDVal == ".cpload") + return parseDirectiveCPLoad(DirectiveID.getLoc()); + if (IDVal == ".dword") { + parseDataDirective(8, DirectiveID.getLoc()); + return false; + } + if (IDVal == ".ent") { // Ignore this directive for now. Parser.Lex(); @@ -2477,22 +2968,42 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { return false; } + if (IDVal == ".nan") + return parseDirectiveNaN(); + if (IDVal == ".gpword") { - // Ignore this directive for now. parseDirectiveGpWord(); return false; } + if (IDVal == ".gpdword") { + parseDirectiveGpDWord(); + return false; + } + if (IDVal == ".word") { - parseDirectiveWord(4, DirectiveID.getLoc()); + parseDataDirective(4, DirectiveID.getLoc()); + return false; + } + + if (IDVal == ".option") + return parseDirectiveOption(); + + if (IDVal == ".abicalls") { + getTargetStreamer().emitDirectiveAbiCalls(); + if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { + Error(Parser.getTok().getLoc(), "unexpected token in directive"); + // Clear line + Parser.eatToEndOfStatement(); + } return false; } - if (IDVal == ".mips_hack_stocg") - return parseDirectiveMipsHackStocg(); + if (IDVal == ".cpsetup") + return parseDirectiveCPSetup(); - if (IDVal == ".mips_hack_elf_flags") - return parseDirectiveMipsHackELFFlags(); + if (IDVal == ".module") + return parseDirectiveModule(); return true; } diff --git a/lib/Target/Mips/CMakeLists.txt b/lib/Target/Mips/CMakeLists.txt index 6acc9a88c06e..bf67d71b0a09 100644 --- a/lib/Target/Mips/CMakeLists.txt +++ b/lib/Target/Mips/CMakeLists.txt @@ -7,6 +7,7 @@ tablegen(LLVM MipsGenCodeEmitter.inc -gen-emitter) tablegen(LLVM MipsGenMCCodeEmitter.inc -gen-emitter -mc-emitter) tablegen(LLVM MipsGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM MipsGenDAGISel.inc -gen-dag-isel) +tablegen(LLVM MipsGenFastISel.inc -gen-fast-isel) tablegen(LLVM MipsGenCallingConv.inc -gen-callingconv) tablegen(LLVM MipsGenSubtargetInfo.inc -gen-subtarget) tablegen(LLVM MipsGenAsmMatcher.inc -gen-asm-matcher) @@ -16,6 +17,7 @@ add_public_tablegen_target(MipsCommonTableGen) add_llvm_target(MipsCodeGen Mips16FrameLowering.cpp Mips16HardFloat.cpp + Mips16HardFloatInfo.cpp Mips16InstrInfo.cpp Mips16ISelDAGToDAG.cpp Mips16ISelLowering.cpp @@ -25,6 +27,7 @@ add_llvm_target(MipsCodeGen MipsCodeEmitter.cpp MipsConstantIslandPass.cpp MipsDelaySlotFiller.cpp + MipsFastISel.cpp MipsJITInfo.cpp MipsInstrInfo.cpp MipsISelDAGToDAG.cpp @@ -34,6 +37,7 @@ add_llvm_target(MipsCodeGen MipsMCInstLower.cpp MipsMachineFunction.cpp MipsModuleISelDAGToDAG.cpp + MipsOptimizePICCall.cpp MipsOs16.cpp MipsRegisterInfo.cpp MipsSEFrameLowering.cpp @@ -47,8 +51,6 @@ add_llvm_target(MipsCodeGen MipsSelectionDAGInfo.cpp ) -add_dependencies(LLVMMipsCodeGen MipsCommonTableGen intrinsics_gen) - add_subdirectory(InstPrinter) add_subdirectory(Disassembler) add_subdirectory(TargetInfo) diff --git a/lib/Target/Mips/Disassembler/CMakeLists.txt b/lib/Target/Mips/Disassembler/CMakeLists.txt index fe1dc75776f1..a64d02c47406 100644 --- a/lib/Target/Mips/Disassembler/CMakeLists.txt +++ b/lib/Target/Mips/Disassembler/CMakeLists.txt @@ -1,15 +1,3 @@ -include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) - add_llvm_library(LLVMMipsDisassembler MipsDisassembler.cpp ) - -# workaround for hanging compilation on MSVC9 and 10 -if( MSVC_VERSION EQUAL 1400 OR MSVC_VERSION EQUAL 1500 OR MSVC_VERSION EQUAL 1600 ) -set_property( - SOURCE MipsDisassembler.cpp - PROPERTY COMPILE_FLAGS "/Od" - ) -endif() - -add_dependencies(LLVMMipsDisassembler MipsCommonTableGen) diff --git a/lib/Target/Mips/Disassembler/LLVMBuild.txt b/lib/Target/Mips/Disassembler/LLVMBuild.txt index 7101c06d12ac..bb70fd3378bc 100644 --- a/lib/Target/Mips/Disassembler/LLVMBuild.txt +++ b/lib/Target/Mips/Disassembler/LLVMBuild.txt @@ -19,5 +19,5 @@ type = Library name = MipsDisassembler parent = Mips -required_libraries = MC Support MipsInfo +required_libraries = MC MipsInfo Support add_to_library_groups = Mips diff --git a/lib/Target/Mips/Disassembler/MipsDisassembler.cpp b/lib/Target/Mips/Disassembler/MipsDisassembler.cpp index 60508a8c4fcb..f35a8deefcff 100644 --- a/lib/Target/Mips/Disassembler/MipsDisassembler.cpp +++ b/lib/Target/Mips/Disassembler/MipsDisassembler.cpp @@ -14,6 +14,7 @@ #include "Mips.h" #include "MipsRegisterInfo.h" #include "MipsSubtarget.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler.h" #include "llvm/MC/MCFixedLenDisassembler.h" #include "llvm/MC/MCInst.h" @@ -24,6 +25,8 @@ using namespace llvm; +#define DEBUG_TYPE "mips-disassembler" + typedef MCDisassembler::DecodeStatus DecodeStatus; namespace { @@ -33,19 +36,16 @@ class MipsDisassemblerBase : public MCDisassembler { public: /// Constructor - Initializes the disassembler. /// - MipsDisassemblerBase(const MCSubtargetInfo &STI, const MCRegisterInfo *Info, + MipsDisassemblerBase(const MCSubtargetInfo &STI, MCContext &Ctx, bool bigEndian) : - MCDisassembler(STI), RegInfo(Info), + MCDisassembler(STI, Ctx), 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; @@ -57,19 +57,31 @@ class MipsDisassembler : public MipsDisassemblerBase { public: /// Constructor - Initializes the disassembler. /// - MipsDisassembler(const MCSubtargetInfo &STI, const MCRegisterInfo *Info, - bool bigEndian) : - MipsDisassemblerBase(STI, Info, bigEndian) { - IsMicroMips = STI.getFeatureBits() & Mips::FeatureMicroMips; - } + MipsDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, bool bigEndian) + : MipsDisassemblerBase(STI, Ctx, bigEndian) { + IsMicroMips = STI.getFeatureBits() & Mips::FeatureMicroMips; + } + + bool hasMips3() const { return STI.getFeatureBits() & Mips::FeatureMips3; } + bool hasMips32() const { return STI.getFeatureBits() & Mips::FeatureMips32; } + bool hasMips32r6() const { + return STI.getFeatureBits() & Mips::FeatureMips32r6; + } + + bool isGP64() const { return STI.getFeatureBits() & Mips::FeatureGP64Bit; } + + bool hasCOP3() const { + // Only present in MIPS-I and MIPS-II + return !hasMips32() && !hasMips3(); + } /// getInstruction - See MCDisassembler. - virtual DecodeStatus getInstruction(MCInst &instr, - uint64_t &size, - const MemoryObject ®ion, - uint64_t address, - raw_ostream &vStream, - raw_ostream &cStream) const; + DecodeStatus getInstruction(MCInst &instr, + uint64_t &size, + const MemoryObject ®ion, + uint64_t address, + raw_ostream &vStream, + raw_ostream &cStream) const override; }; @@ -78,17 +90,17 @@ class Mips64Disassembler : public MipsDisassemblerBase { public: /// Constructor - Initializes the disassembler. /// - Mips64Disassembler(const MCSubtargetInfo &STI, const MCRegisterInfo *Info, + Mips64Disassembler(const MCSubtargetInfo &STI, MCContext &Ctx, bool bigEndian) : - MipsDisassemblerBase(STI, Info, bigEndian) {} + MipsDisassemblerBase(STI, Ctx, 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; + DecodeStatus getInstruction(MCInst &instr, + uint64_t &size, + const MemoryObject ®ion, + uint64_t address, + raw_ostream &vStream, + raw_ostream &cStream) const override; }; } // end anonymous namespace @@ -130,11 +142,6 @@ static DecodeStatus DecodeFGR32RegisterClass(MCInst &Inst, 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, @@ -145,6 +152,10 @@ static DecodeStatus DecodeFCCRegisterClass(MCInst &Inst, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeFGRCCRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, + const void *Decoder); + static DecodeStatus DecodeHWRegsRegisterClass(MCInst &Inst, unsigned Insn, uint64_t Address, @@ -195,6 +206,11 @@ static DecodeStatus DecodeMSACtrlRegisterClass(MCInst &Inst, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeCOP2RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + static DecodeStatus DecodeBranchTarget(MCInst &Inst, unsigned Offset, uint64_t Address, @@ -205,6 +221,16 @@ static DecodeStatus DecodeJumpTarget(MCInst &Inst, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeBranchTarget21(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeBranchTarget26(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder); + // DecodeBranchTargetMM - Decode microMIPS branch offset, which is // shifted left by 1 bit. static DecodeStatus DecodeBranchTargetMM(MCInst &Inst, @@ -241,6 +267,11 @@ static DecodeStatus DecodeFMem(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeSpecial3LlSc(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + static DecodeStatus DecodeSimm16(MCInst &Inst, unsigned Insn, uint64_t Address, @@ -263,6 +294,48 @@ static DecodeStatus DecodeExtSize(MCInst &Inst, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeSimm19Lsl2(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); + +static DecodeStatus DecodeSimm18Lsl3(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); + +/// INSVE_[BHWD] have an implicit operand that the generated decoder doesn't +/// handle. +template <typename InsnType> +static DecodeStatus DecodeINSVE_DF(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template <typename InsnType> +static DecodeStatus +DecodeAddiGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template <typename InsnType> +static DecodeStatus +DecodeDaddiGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template <typename InsnType> +static DecodeStatus +DecodeBlezlGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template <typename InsnType> +static DecodeStatus +DecodeBgtzlGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template <typename InsnType> +static DecodeStatus +DecodeBgtzGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template <typename InsnType> +static DecodeStatus +DecodeBlezGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + namespace llvm { extern Target TheMipselTarget, TheMipsTarget, TheMips64Target, TheMips64elTarget; @@ -270,26 +343,30 @@ extern Target TheMipselTarget, TheMipsTarget, TheMips64Target, static MCDisassembler *createMipsDisassembler( const Target &T, - const MCSubtargetInfo &STI) { - return new MipsDisassembler(STI, T.createMCRegInfo(""), true); + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new MipsDisassembler(STI, Ctx, true); } static MCDisassembler *createMipselDisassembler( const Target &T, - const MCSubtargetInfo &STI) { - return new MipsDisassembler(STI, T.createMCRegInfo(""), false); + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new MipsDisassembler(STI, Ctx, false); } static MCDisassembler *createMips64Disassembler( const Target &T, - const MCSubtargetInfo &STI) { - return new Mips64Disassembler(STI, T.createMCRegInfo(""), true); + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new Mips64Disassembler(STI, Ctx, true); } static MCDisassembler *createMips64elDisassembler( const Target &T, - const MCSubtargetInfo &STI) { - return new Mips64Disassembler(STI, T.createMCRegInfo(""), false); + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new Mips64Disassembler(STI, Ctx, false); } extern "C" void LLVMInitializeMipsDisassembler() { @@ -304,9 +381,316 @@ extern "C" void LLVMInitializeMipsDisassembler() { createMips64elDisassembler); } - #include "MipsGenDisassemblerTables.inc" +static unsigned getReg(const void *D, unsigned RC, unsigned RegNo) { + const MipsDisassemblerBase *Dis = static_cast<const MipsDisassemblerBase*>(D); + const MCRegisterInfo *RegInfo = Dis->getContext().getRegisterInfo(); + return *(RegInfo->getRegClass(RC).begin() + RegNo); +} + +template <typename InsnType> +static DecodeStatus DecodeINSVE_DF(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder) { + typedef DecodeStatus (*DecodeFN)(MCInst &, unsigned, uint64_t, const void *); + // The size of the n field depends on the element size + // The register class also depends on this. + InsnType tmp = fieldFromInstruction(insn, 17, 5); + unsigned NSize = 0; + DecodeFN RegDecoder = nullptr; + if ((tmp & 0x18) == 0x00) { // INSVE_B + NSize = 4; + RegDecoder = DecodeMSA128BRegisterClass; + } else if ((tmp & 0x1c) == 0x10) { // INSVE_H + NSize = 3; + RegDecoder = DecodeMSA128HRegisterClass; + } else if ((tmp & 0x1e) == 0x18) { // INSVE_W + NSize = 2; + RegDecoder = DecodeMSA128WRegisterClass; + } else if ((tmp & 0x1f) == 0x1c) { // INSVE_D + NSize = 1; + RegDecoder = DecodeMSA128DRegisterClass; + } else + llvm_unreachable("Invalid encoding"); + + assert(NSize != 0 && RegDecoder != nullptr); + + // $wd + tmp = fieldFromInstruction(insn, 6, 5); + if (RegDecoder(MI, tmp, Address, Decoder) == MCDisassembler::Fail) + return MCDisassembler::Fail; + // $wd_in + if (RegDecoder(MI, tmp, Address, Decoder) == MCDisassembler::Fail) + return MCDisassembler::Fail; + // $n + tmp = fieldFromInstruction(insn, 16, NSize); + MI.addOperand(MCOperand::CreateImm(tmp)); + // $ws + tmp = fieldFromInstruction(insn, 11, 5); + if (RegDecoder(MI, tmp, Address, Decoder) == MCDisassembler::Fail) + return MCDisassembler::Fail; + // $n2 + MI.addOperand(MCOperand::CreateImm(0)); + + return MCDisassembler::Success; +} + +template <typename InsnType> +static DecodeStatus DecodeAddiGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the ADDI instruction from the earlier + // ISA's instead). + // + // We have: + // 0b001000 sssss ttttt iiiiiiiiiiiiiiii + // BOVC if rs >= rt + // BEQZALC if rs == 0 && rt != 0 + // BEQC if rs < rt && rs != 0 + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) << 2; + bool HasRs = false; + + if (Rs >= Rt) { + MI.setOpcode(Mips::BOVC); + HasRs = true; + } else if (Rs != 0 && Rs < Rt) { + MI.setOpcode(Mips::BEQC); + HasRs = true; + } else + MI.setOpcode(Mips::BEQZALC); + + if (HasRs) + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + MI.addOperand(MCOperand::CreateImm(Imm)); + + return MCDisassembler::Success; +} + +template <typename InsnType> +static DecodeStatus DecodeDaddiGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the ADDI instruction from the earlier + // ISA's instead). + // + // We have: + // 0b011000 sssss ttttt iiiiiiiiiiiiiiii + // BNVC if rs >= rt + // BNEZALC if rs == 0 && rt != 0 + // BNEC if rs < rt && rs != 0 + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) << 2; + bool HasRs = false; + + if (Rs >= Rt) { + MI.setOpcode(Mips::BNVC); + HasRs = true; + } else if (Rs != 0 && Rs < Rt) { + MI.setOpcode(Mips::BNEC); + HasRs = true; + } else + MI.setOpcode(Mips::BNEZALC); + + if (HasRs) + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + MI.addOperand(MCOperand::CreateImm(Imm)); + + return MCDisassembler::Success; +} + +template <typename InsnType> +static DecodeStatus DecodeBlezlGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the BLEZL instruction from the earlier + // ISA's instead). + // + // We have: + // 0b010110 sssss ttttt iiiiiiiiiiiiiiii + // Invalid if rs == 0 + // BLEZC if rs == 0 && rt != 0 + // BGEZC if rs == rt && rt != 0 + // BGEC if rs != rt && rs != 0 && rt != 0 + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) << 2; + bool HasRs = false; + + if (Rt == 0) + return MCDisassembler::Fail; + else if (Rs == 0) + MI.setOpcode(Mips::BLEZC); + else if (Rs == Rt) + MI.setOpcode(Mips::BGEZC); + else { + HasRs = true; + MI.setOpcode(Mips::BGEC); + } + + if (HasRs) + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + + MI.addOperand(MCOperand::CreateImm(Imm)); + + return MCDisassembler::Success; +} + +template <typename InsnType> +static DecodeStatus DecodeBgtzlGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the BGTZL instruction from the earlier + // ISA's instead). + // + // We have: + // 0b010111 sssss ttttt iiiiiiiiiiiiiiii + // Invalid if rs == 0 + // BGTZC if rs == 0 && rt != 0 + // BLTZC if rs == rt && rt != 0 + // BLTC if rs != rt && rs != 0 && rt != 0 + + bool HasRs = false; + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) << 2; + + if (Rt == 0) + return MCDisassembler::Fail; + else if (Rs == 0) + MI.setOpcode(Mips::BGTZC); + else if (Rs == Rt) + MI.setOpcode(Mips::BLTZC); + else { + MI.setOpcode(Mips::BLTC); + HasRs = true; + } + + if (HasRs) + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + + MI.addOperand(MCOperand::CreateImm(Imm)); + + return MCDisassembler::Success; +} + +template <typename InsnType> +static DecodeStatus DecodeBgtzGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the BGTZ instruction from the earlier + // ISA's instead). + // + // We have: + // 0b000111 sssss ttttt iiiiiiiiiiiiiiii + // BGTZ if rt == 0 + // BGTZALC if rs == 0 && rt != 0 + // BLTZALC if rs != 0 && rs == rt + // BLTUC if rs != 0 && rs != rt + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) << 2; + bool HasRs = false; + bool HasRt = false; + + if (Rt == 0) { + MI.setOpcode(Mips::BGTZ); + HasRs = true; + } else if (Rs == 0) { + MI.setOpcode(Mips::BGTZALC); + HasRt = true; + } else if (Rs == Rt) { + MI.setOpcode(Mips::BLTZALC); + HasRs = true; + } else { + MI.setOpcode(Mips::BLTUC); + HasRs = true; + HasRt = true; + } + + if (HasRs) + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + + if (HasRt) + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + + MI.addOperand(MCOperand::CreateImm(Imm)); + + return MCDisassembler::Success; +} + +template <typename InsnType> +static DecodeStatus DecodeBlezGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the BLEZL instruction from the earlier + // ISA's instead). + // + // We have: + // 0b000110 sssss ttttt iiiiiiiiiiiiiiii + // Invalid if rs == 0 + // BLEZALC if rs == 0 && rt != 0 + // BGEZALC if rs == rt && rt != 0 + // BGEUC if rs != rt && rs != 0 && rt != 0 + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) << 2; + bool HasRs = false; + + if (Rt == 0) + return MCDisassembler::Fail; + else if (Rs == 0) + MI.setOpcode(Mips::BLEZALC); + else if (Rs == Rt) + MI.setOpcode(Mips::BGEZALC); + else { + HasRs = true; + MI.setOpcode(Mips::BGEUC); + } + + if (HasRs) + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + + MI.addOperand(MCOperand::CreateImm(Imm)); + + return MCDisassembler::Success; +} + /// readInstruction - read four bytes from the MemoryObject /// and return 32 bit word sorted according to the given endianess static DecodeStatus readInstruction32(const MemoryObject ®ion, @@ -366,6 +750,7 @@ MipsDisassembler::getInstruction(MCInst &instr, return MCDisassembler::Fail; if (IsMicroMips) { + DEBUG(dbgs() << "Trying MicroMips32 table (32-bit opcodes):\n"); // Calling the auto-generated decoder function. Result = decodeInstruction(DecoderTableMicroMips32, instr, Insn, Address, this, STI); @@ -376,6 +761,37 @@ MipsDisassembler::getInstruction(MCInst &instr, return MCDisassembler::Fail; } + if (hasCOP3()) { + DEBUG(dbgs() << "Trying COP3_ table (32-bit opcodes):\n"); + Result = + decodeInstruction(DecoderTableCOP3_32, instr, Insn, Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + } + + if (hasMips32r6() && isGP64()) { + DEBUG(dbgs() << "Trying Mips32r6_64r6 (GPR64) table (32-bit opcodes):\n"); + Result = decodeInstruction(DecoderTableMips32r6_64r6_GP6432, instr, Insn, + Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + } + + if (hasMips32r6()) { + DEBUG(dbgs() << "Trying Mips32r6_64r6 table (32-bit opcodes):\n"); + Result = decodeInstruction(DecoderTableMips32r6_64r632, instr, Insn, + Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + } + + DEBUG(dbgs() << "Trying Mips table (32-bit opcodes):\n"); // Calling the auto-generated decoder function. Result = decodeInstruction(DecoderTableMips32, instr, Insn, Address, this, STI); @@ -419,11 +835,6 @@ Mips64Disassembler::getInstruction(MCInst &instr, 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, @@ -498,18 +909,6 @@ static DecodeStatus DecodeFGR32RegisterClass(MCInst &Inst, 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, @@ -532,6 +931,17 @@ static DecodeStatus DecodeFCCRegisterClass(MCInst &Inst, return MCDisassembler::Success; } +static DecodeStatus DecodeFGRCCRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::FGRCCRegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + static DecodeStatus DecodeMem(MCInst &Inst, unsigned Insn, uint64_t Address, @@ -565,7 +975,37 @@ static DecodeStatus DecodeMSA128Mem(MCInst &Inst, unsigned Insn, Inst.addOperand(MCOperand::CreateReg(Reg)); Inst.addOperand(MCOperand::CreateReg(Base)); - Inst.addOperand(MCOperand::CreateImm(Offset)); + + // The immediate field of an LD/ST instruction is scaled which means it must + // be multiplied (when decoding) by the size (in bytes) of the instructions' + // data format. + // .b - 1 byte + // .h - 2 bytes + // .w - 4 bytes + // .d - 8 bytes + switch(Inst.getOpcode()) + { + default: + assert (0 && "Unexpected instruction"); + return MCDisassembler::Fail; + break; + case Mips::LD_B: + case Mips::ST_B: + Inst.addOperand(MCOperand::CreateImm(Offset)); + break; + case Mips::LD_H: + case Mips::ST_H: + Inst.addOperand(MCOperand::CreateImm(Offset << 1)); + break; + case Mips::LD_W: + case Mips::ST_W: + Inst.addOperand(MCOperand::CreateImm(Offset << 2)); + break; + case Mips::LD_D: + case Mips::ST_D: + Inst.addOperand(MCOperand::CreateImm(Offset << 3)); + break; + } return MCDisassembler::Success; } @@ -581,6 +1021,9 @@ static DecodeStatus DecodeMemMMImm12(MCInst &Inst, Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg); Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + if (Inst.getOpcode() == Mips::SC_MM) + Inst.addOperand(MCOperand::CreateReg(Reg)); + Inst.addOperand(MCOperand::CreateReg(Reg)); Inst.addOperand(MCOperand::CreateReg(Base)); Inst.addOperand(MCOperand::CreateImm(Offset)); @@ -624,6 +1067,27 @@ static DecodeStatus DecodeFMem(MCInst &Inst, return MCDisassembler::Success; } +static DecodeStatus DecodeSpecial3LlSc(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int64_t Offset = SignExtend64<9>((Insn >> 7) & 0x1ff); + unsigned Rt = fieldFromInstruction(Insn, 16, 5); + unsigned Base = fieldFromInstruction(Insn, 21, 5); + + Rt = getReg(Decoder, Mips::GPR32RegClassID, Rt); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + if(Inst.getOpcode() == Mips::SC_R6 || Inst.getOpcode() == Mips::SCD_R6){ + Inst.addOperand(MCOperand::CreateReg(Rt)); + } + + Inst.addOperand(MCOperand::CreateReg(Rt)); + Inst.addOperand(MCOperand::CreateReg(Base)); + Inst.addOperand(MCOperand::CreateImm(Offset)); + + return MCDisassembler::Success; +} static DecodeStatus DecodeHWRegsRegisterClass(MCInst &Inst, unsigned RegNo, @@ -745,12 +1209,23 @@ static DecodeStatus DecodeMSACtrlRegisterClass(MCInst &Inst, return MCDisassembler::Success; } +static DecodeStatus DecodeCOP2RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::COP2RegClassID, 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; + int32_t BranchOffset = (SignExtend32<16>(Offset) << 2) + 4; Inst.addOperand(MCOperand::CreateImm(BranchOffset)); return MCDisassembler::Success; } @@ -765,12 +1240,31 @@ static DecodeStatus DecodeJumpTarget(MCInst &Inst, return MCDisassembler::Success; } +static DecodeStatus DecodeBranchTarget21(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder) { + int32_t BranchOffset = SignExtend32<21>(Offset) << 2; + + Inst.addOperand(MCOperand::CreateImm(BranchOffset)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeBranchTarget26(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder) { + int32_t BranchOffset = SignExtend32<26>(Offset) << 2; + + Inst.addOperand(MCOperand::CreateImm(BranchOffset)); + 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); + int32_t BranchOffset = SignExtend32<16>(Offset) << 1; Inst.addOperand(MCOperand::CreateImm(BranchOffset)); return MCDisassembler::Success; } @@ -820,3 +1314,15 @@ static DecodeStatus DecodeExtSize(MCInst &Inst, Inst.addOperand(MCOperand::CreateImm(SignExtend32<16>(Size))); return MCDisassembler::Success; } + +static DecodeStatus DecodeSimm19Lsl2(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + Inst.addOperand(MCOperand::CreateImm(SignExtend32<19>(Insn) << 2)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeSimm18Lsl3(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + Inst.addOperand(MCOperand::CreateImm(SignExtend32<18>(Insn) << 3)); + return MCDisassembler::Success; +} diff --git a/lib/Target/Mips/InstPrinter/CMakeLists.txt b/lib/Target/Mips/InstPrinter/CMakeLists.txt index 3e9fbf1c5566..2a67fba796a6 100644 --- a/lib/Target/Mips/InstPrinter/CMakeLists.txt +++ b/lib/Target/Mips/InstPrinter/CMakeLists.txt @@ -1,7 +1,3 @@ -include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) - add_llvm_library(LLVMMipsAsmPrinter MipsInstPrinter.cpp ) - -add_dependencies(LLVMMipsAsmPrinter MipsCommonTableGen) diff --git a/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp b/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp index 78845898997c..8c797517e316 100644 --- a/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp +++ b/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "asm-printer" #include "MipsInstPrinter.h" +#include "MCTargetDesc/MipsMCExpr.h" #include "MipsInstrInfo.h" #include "llvm/ADT/StringExtras.h" #include "llvm/MC/MCExpr.h" @@ -23,6 +23,8 @@ #include "llvm/Support/raw_ostream.h" using namespace llvm; +#define DEBUG_TYPE "asm-printer" + #define PRINT_ALIAS_INSTR #include "MipsGenAsmWriter.inc" @@ -83,6 +85,27 @@ void MipsInstPrinter::printInst(const MCInst *MI, raw_ostream &O, case Mips::RDHWR64: O << "\t.set\tpush\n"; O << "\t.set\tmips32r2\n"; + break; + case Mips::Save16: + O << "\tsave\t"; + printSaveRestore(MI, O); + O << " # 16 bit inst\n"; + return; + case Mips::SaveX16: + O << "\tsave\t"; + printSaveRestore(MI, O); + O << "\n"; + return; + case Mips::Restore16: + O << "\trestore\t"; + printSaveRestore(MI, O); + O << " # 16 bit inst\n"; + return; + case Mips::RestoreX16: + O << "\trestore\t"; + printSaveRestore(MI, O); + O << "\n"; + return; } // Try to print any aliases first. @@ -108,8 +131,10 @@ static void printExpr(const MCExpr *Expr, raw_ostream &OS) { 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))) + } else if (const MipsMCExpr *ME = dyn_cast<MipsMCExpr>(Expr)) { + ME->print(OS); + return; + } else if (!(SRE = dyn_cast<MCSymbolRefExpr>(Expr))) assert(false && "Unexpected MCExpr type."); MCSymbolRefExpr::VariantKind Kind = SRE->getKind(); @@ -141,6 +166,8 @@ static void printExpr(const MCExpr *Expr, raw_ostream &OS) { 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; + case MCSymbolRefExpr::VK_Mips_PCREL_HI16: OS << "%pcrel_hi("; break; + case MCSymbolRefExpr::VK_Mips_PCREL_LO16: OS << "%pcrel_lo("; break; } OS << SRE->getSymbol(); @@ -286,3 +313,14 @@ bool MipsInstPrinter::printAlias(const MCInst &MI, raw_ostream &OS) { default: return false; } } + +void MipsInstPrinter::printSaveRestore(const MCInst *MI, raw_ostream &O) { + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + if (i != 0) O << ", "; + if (MI->getOperand(i).isReg()) + printRegName(O, MI->getOperand(i).getReg()); + else + printUnsignedImm(MI, i, O); + } +} + diff --git a/lib/Target/Mips/InstPrinter/MipsInstPrinter.h b/lib/Target/Mips/InstPrinter/MipsInstPrinter.h index f75ae249c3ee..550a0f10d1ba 100644 --- a/lib/Target/Mips/InstPrinter/MipsInstPrinter.h +++ b/lib/Target/Mips/InstPrinter/MipsInstPrinter.h @@ -85,10 +85,12 @@ public: 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); + void printRegName(raw_ostream &OS, unsigned RegNo) const override; + void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot) override; bool printAliasInstr(const MCInst *MI, raw_ostream &OS); + void printCustomAliasOperand(const MCInst *MI, unsigned OpIdx, + unsigned PrintMethodIdx, raw_ostream &O); private: void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); @@ -104,6 +106,7 @@ private: bool printAlias(const char *Str, const MCInst &MI, unsigned OpNo0, unsigned OpNo1, raw_ostream &OS); bool printAlias(const MCInst &MI, raw_ostream &OS); + void printSaveRestore(const MCInst *MI, raw_ostream &O); }; } // end namespace llvm diff --git a/lib/Target/Mips/LLVMBuild.txt b/lib/Target/Mips/LLVMBuild.txt index a95d6bc1352a..e6d3a426b2ea 100644 --- a/lib/Target/Mips/LLVMBuild.txt +++ b/lib/Target/Mips/LLVMBuild.txt @@ -31,5 +31,5 @@ has_jit = 1 type = Library name = MipsCodeGen parent = Mips -required_libraries = AsmPrinter CodeGen Core MC MipsAsmPrinter MipsDesc MipsInfo SelectionDAG Support Target +required_libraries = Analysis AsmPrinter CodeGen Core MC MipsAsmPrinter MipsDesc MipsInfo Scalar SelectionDAG Support Target add_to_library_groups = Mips diff --git a/lib/Target/Mips/MCTargetDesc/CMakeLists.txt b/lib/Target/Mips/MCTargetDesc/CMakeLists.txt index 911674890c73..6b3788ca515c 100644 --- a/lib/Target/Mips/MCTargetDesc/CMakeLists.txt +++ b/lib/Target/Mips/MCTargetDesc/CMakeLists.txt @@ -1,11 +1,13 @@ add_llvm_library(LLVMMipsDesc + MipsABIFlagsSection.cpp MipsAsmBackend.cpp + MipsELFObjectWriter.cpp + MipsELFStreamer.cpp MipsMCAsmInfo.cpp MipsMCCodeEmitter.cpp + MipsMCExpr.cpp MipsMCTargetDesc.cpp - MipsELFObjectWriter.cpp - MipsReginfo.cpp + MipsNaClELFStreamer.cpp + MipsOptionRecord.cpp MipsTargetStreamer.cpp ) - -add_dependencies(LLVMMipsDesc MipsCommonTableGen) diff --git a/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.cpp b/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.cpp new file mode 100644 index 000000000000..5b0f950b076e --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.cpp @@ -0,0 +1,66 @@ +//===-- MipsABIFlagsSection.cpp - Mips ELF ABI Flags Section ---*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsABIFlagsSection.h" + +using namespace llvm; + +uint8_t MipsABIFlagsSection::getFpABIValue() { + switch (FpABI) { + case FpABIKind::ANY: + return Val_GNU_MIPS_ABI_FP_ANY; + case FpABIKind::XX: + return Val_GNU_MIPS_ABI_FP_XX; + case FpABIKind::S32: + return Val_GNU_MIPS_ABI_FP_DOUBLE; + case FpABIKind::S64: + if (Is32BitABI) + return OddSPReg ? Val_GNU_MIPS_ABI_FP_64 : Val_GNU_MIPS_ABI_FP_64A; + return Val_GNU_MIPS_ABI_FP_DOUBLE; + } + + llvm_unreachable("unexpected fp abi value"); +} + +StringRef MipsABIFlagsSection::getFpABIString(FpABIKind Value) { + switch (Value) { + case FpABIKind::XX: + return "xx"; + case FpABIKind::S32: + return "32"; + case FpABIKind::S64: + return "64"; + default: + llvm_unreachable("unsupported fp abi value"); + } +} + +uint8_t MipsABIFlagsSection::getCPR1SizeValue() { + if (FpABI == FpABIKind::XX) + return (uint8_t)AFL_REG_32; + return (uint8_t)CPR1Size; +} + +namespace llvm { +MCStreamer &operator<<(MCStreamer &OS, MipsABIFlagsSection &ABIFlagsSection) { + // Write out a Elf_Internal_ABIFlags_v0 struct + OS.EmitIntValue(ABIFlagsSection.getVersionValue(), 2); // version + OS.EmitIntValue(ABIFlagsSection.getISALevelValue(), 1); // isa_level + OS.EmitIntValue(ABIFlagsSection.getISARevisionValue(), 1); // isa_rev + OS.EmitIntValue(ABIFlagsSection.getGPRSizeValue(), 1); // gpr_size + OS.EmitIntValue(ABIFlagsSection.getCPR1SizeValue(), 1); // cpr1_size + OS.EmitIntValue(ABIFlagsSection.getCPR2SizeValue(), 1); // cpr2_size + OS.EmitIntValue(ABIFlagsSection.getFpABIValue(), 1); // fp_abi + OS.EmitIntValue(ABIFlagsSection.getISAExtensionSetValue(), 4); // isa_ext + OS.EmitIntValue(ABIFlagsSection.getASESetValue(), 4); // ases + OS.EmitIntValue(ABIFlagsSection.getFlags1Value(), 4); // flags1 + OS.EmitIntValue(ABIFlagsSection.getFlags2Value(), 4); // flags2 + return OS; +} +} diff --git a/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h b/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h new file mode 100644 index 000000000000..ea5bc12b0740 --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h @@ -0,0 +1,238 @@ +//===-- MipsABIFlagsSection.h - Mips ELF ABI Flags Section -----*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSABIFLAGSSECTION_H +#define MIPSABIFLAGSSECTION_H + +#include "llvm/MC/MCStreamer.h" + +namespace llvm { + +class MCStreamer; + +struct MipsABIFlagsSection { + // Values for the xxx_size bytes of an ABI flags structure. + enum AFL_REG { + AFL_REG_NONE = 0x00, // No registers. + AFL_REG_32 = 0x01, // 32-bit registers. + AFL_REG_64 = 0x02, // 64-bit registers. + AFL_REG_128 = 0x03 // 128-bit registers. + }; + + // Masks for the ases word of an ABI flags structure. + enum AFL_ASE { + AFL_ASE_DSP = 0x00000001, // DSP ASE. + AFL_ASE_DSPR2 = 0x00000002, // DSP R2 ASE. + AFL_ASE_EVA = 0x00000004, // Enhanced VA Scheme. + AFL_ASE_MCU = 0x00000008, // MCU (MicroController) ASE. + AFL_ASE_MDMX = 0x00000010, // MDMX ASE. + AFL_ASE_MIPS3D = 0x00000020, // MIPS-3D ASE. + AFL_ASE_MT = 0x00000040, // MT ASE. + AFL_ASE_SMARTMIPS = 0x00000080, // SmartMIPS ASE. + AFL_ASE_VIRT = 0x00000100, // VZ ASE. + AFL_ASE_MSA = 0x00000200, // MSA ASE. + AFL_ASE_MIPS16 = 0x00000400, // MIPS16 ASE. + AFL_ASE_MICROMIPS = 0x00000800, // MICROMIPS ASE. + AFL_ASE_XPA = 0x00001000 // XPA ASE. + }; + + // Values for the isa_ext word of an ABI flags structure. + enum AFL_EXT { + AFL_EXT_XLR = 1, // RMI Xlr instruction. + AFL_EXT_OCTEON2 = 2, // Cavium Networks Octeon2. + AFL_EXT_OCTEONP = 3, // Cavium Networks OcteonP. + AFL_EXT_LOONGSON_3A = 4, // Loongson 3A. + AFL_EXT_OCTEON = 5, // Cavium Networks Octeon. + AFL_EXT_5900 = 6, // MIPS R5900 instruction. + AFL_EXT_4650 = 7, // MIPS R4650 instruction. + AFL_EXT_4010 = 8, // LSI R4010 instruction. + AFL_EXT_4100 = 9, // NEC VR4100 instruction. + AFL_EXT_3900 = 10, // Toshiba R3900 instruction. + AFL_EXT_10000 = 11, // MIPS R10000 instruction. + AFL_EXT_SB1 = 12, // Broadcom SB-1 instruction. + AFL_EXT_4111 = 13, // NEC VR4111/VR4181 instruction. + AFL_EXT_4120 = 14, // NEC VR4120 instruction. + AFL_EXT_5400 = 15, // NEC VR5400 instruction. + AFL_EXT_5500 = 16, // NEC VR5500 instruction. + AFL_EXT_LOONGSON_2E = 17, // ST Microelectronics Loongson 2E. + AFL_EXT_LOONGSON_2F = 18 // ST Microelectronics Loongson 2F. + }; + + // Values for the fp_abi word of an ABI flags structure. + enum Val_GNU_MIPS_ABI { + Val_GNU_MIPS_ABI_FP_ANY = 0, + Val_GNU_MIPS_ABI_FP_DOUBLE = 1, + Val_GNU_MIPS_ABI_FP_XX = 5, + Val_GNU_MIPS_ABI_FP_64 = 6, + Val_GNU_MIPS_ABI_FP_64A = 7 + }; + + enum AFL_FLAGS1 { + AFL_FLAGS1_ODDSPREG = 1 + }; + + // Internal representation of the values used in .module fp=value + enum class FpABIKind { ANY, XX, S32, S64 }; + + // Version of flags structure. + uint16_t Version; + // The level of the ISA: 1-5, 32, 64. + uint8_t ISALevel; + // The revision of ISA: 0 for MIPS V and below, 1-n otherwise. + uint8_t ISARevision; + // The size of general purpose registers. + AFL_REG GPRSize; + // The size of co-processor 1 registers. + AFL_REG CPR1Size; + // The size of co-processor 2 registers. + AFL_REG CPR2Size; + // Processor-specific extension. + uint32_t ISAExtensionSet; + // Mask of ASEs used. + uint32_t ASESet; + + bool OddSPReg; + + bool Is32BitABI; + +protected: + // The floating-point ABI. + FpABIKind FpABI; + +public: + MipsABIFlagsSection() + : Version(0), ISALevel(0), ISARevision(0), GPRSize(AFL_REG_NONE), + CPR1Size(AFL_REG_NONE), CPR2Size(AFL_REG_NONE), ISAExtensionSet(0), + ASESet(0), OddSPReg(false), Is32BitABI(false), FpABI(FpABIKind::ANY) {} + + uint16_t getVersionValue() { return (uint16_t)Version; } + uint8_t getISALevelValue() { return (uint8_t)ISALevel; } + uint8_t getISARevisionValue() { return (uint8_t)ISARevision; } + uint8_t getGPRSizeValue() { return (uint8_t)GPRSize; } + uint8_t getCPR1SizeValue(); + uint8_t getCPR2SizeValue() { return (uint8_t)CPR2Size; } + uint8_t getFpABIValue(); + uint32_t getISAExtensionSetValue() { return (uint32_t)ISAExtensionSet; } + uint32_t getASESetValue() { return (uint32_t)ASESet; } + + uint32_t getFlags1Value() { + uint32_t Value = 0; + + if (OddSPReg) + Value |= (uint32_t)AFL_FLAGS1_ODDSPREG; + + return Value; + } + + uint32_t getFlags2Value() { return 0; } + + FpABIKind getFpABI() { return FpABI; } + void setFpABI(FpABIKind Value, bool IsABI32Bit) { + FpABI = Value; + Is32BitABI = IsABI32Bit; + } + StringRef getFpABIString(FpABIKind Value); + + template <class PredicateLibrary> + void setISALevelAndRevisionFromPredicates(const PredicateLibrary &P) { + if (P.hasMips64()) { + ISALevel = 64; + if (P.hasMips64r6()) + ISARevision = 6; + else if (P.hasMips64r2()) + ISARevision = 2; + else + ISARevision = 1; + } else if (P.hasMips32()) { + ISALevel = 32; + if (P.hasMips32r6()) + ISARevision = 6; + else if (P.hasMips32r2()) + ISARevision = 2; + else + ISARevision = 1; + } else { + ISARevision = 0; + if (P.hasMips5()) + ISALevel = 5; + else if (P.hasMips4()) + ISALevel = 4; + else if (P.hasMips3()) + ISALevel = 3; + else if (P.hasMips2()) + ISALevel = 2; + else if (P.hasMips1()) + ISALevel = 1; + else + llvm_unreachable("Unknown ISA level!"); + } + } + + template <class PredicateLibrary> + void setGPRSizeFromPredicates(const PredicateLibrary &P) { + GPRSize = P.isGP64bit() ? AFL_REG_64 : AFL_REG_32; + } + + template <class PredicateLibrary> + void setCPR1SizeFromPredicates(const PredicateLibrary &P) { + if (P.abiUsesSoftFloat()) + CPR1Size = AFL_REG_NONE; + else if (P.hasMSA()) + CPR1Size = AFL_REG_128; + else + CPR1Size = P.isFP64bit() ? AFL_REG_64 : AFL_REG_32; + } + + template <class PredicateLibrary> + void setASESetFromPredicates(const PredicateLibrary &P) { + ASESet = 0; + if (P.hasDSP()) + ASESet |= AFL_ASE_DSP; + if (P.hasDSPR2()) + ASESet |= AFL_ASE_DSPR2; + if (P.hasMSA()) + ASESet |= AFL_ASE_MSA; + if (P.inMicroMipsMode()) + ASESet |= AFL_ASE_MICROMIPS; + if (P.inMips16Mode()) + ASESet |= AFL_ASE_MIPS16; + } + + template <class PredicateLibrary> + void setFpAbiFromPredicates(const PredicateLibrary &P) { + Is32BitABI = P.isABI_O32(); + + FpABI = FpABIKind::ANY; + if (P.isABI_N32() || P.isABI_N64()) + FpABI = FpABIKind::S64; + else if (P.isABI_O32()) { + if (P.isABI_FPXX()) + FpABI = FpABIKind::XX; + else if (P.isFP64bit()) + FpABI = FpABIKind::S64; + else + FpABI = FpABIKind::S32; + } + } + + template <class PredicateLibrary> + void setAllFromPredicates(const PredicateLibrary &P) { + setISALevelAndRevisionFromPredicates(P); + setGPRSizeFromPredicates(P); + setCPR1SizeFromPredicates(P); + setASESetFromPredicates(P); + setFpAbiFromPredicates(P); + OddSPReg = P.useOddSPReg(); + } +}; + +MCStreamer &operator<<(MCStreamer &OS, MipsABIFlagsSection &ABIFlagsSection); +} + +#endif diff --git a/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp index 3e70b23dccc6..d8e6128cd54d 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp @@ -1,4 +1,4 @@ -//===-- MipsASMBackend.cpp - Mips Asm Backend ----------------------------===// +//===-- MipsAsmBackend.cpp - Mips Asm Backend ----------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,32 +7,39 @@ // //===----------------------------------------------------------------------===// // -// This file implements the MipsAsmBackend and MipsELFObjectWriter classes. +// This file implements the MipsAsmBackend class. // //===----------------------------------------------------------------------===// // -#include "MipsFixupKinds.h" +#include "MCTargetDesc/MipsFixupKinds.h" +#include "MCTargetDesc/MipsAsmBackend.h" #include "MCTargetDesc/MipsMCTargetDesc.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.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/MathExtras.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) { +static unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value, + MCContext *Ctx = nullptr) { + + unsigned Kind = Fixup.getKind(); // Add/subtract and shift switch (Kind) { default: return 0; + case FK_Data_2: case FK_GPRel_4: case FK_Data_4: case FK_Data_8: @@ -49,6 +56,7 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { case Mips::fixup_MICROMIPS_GOT_PAGE: case Mips::fixup_MICROMIPS_GOT_OFST: case Mips::fixup_MICROMIPS_GOT_DISP: + case Mips::fixup_MIPS_PCLO16: break; case Mips::fixup_Mips_PC16: // So far we are only using this type for branches. @@ -56,8 +64,18 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { // 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; + // address range. Forcing a signed division because Value can be negative. + Value = (int64_t)Value / 4; + // We now check if Value can be encoded as a 16-bit signed immediate. + if (!isIntN(16, Value) && Ctx) + Ctx->FatalError(Fixup.getLoc(), "out of range PC16 fixup"); + break; + case Mips::fixup_MIPS_PC19_S2: + // Forcing a signed division because Value can be negative. + Value = (int64_t)Value / 4; + // We now check if Value can be encoded as a 19-bit signed immediate. + if (!isIntN(19, Value) && Ctx) + Ctx->FatalError(Fixup.getLoc(), "out of range PC19 fixup"); break; case Mips::fixup_Mips_26: // So far we are only using this type for jumps. @@ -70,6 +88,7 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { case Mips::fixup_Mips_GOT_HI16: case Mips::fixup_Mips_CALL_HI16: case Mips::fixup_MICROMIPS_HI16: + case Mips::fixup_MIPS_PCHI16: // Get the 2nd 16-bits. Also add 1 if bit 15 is 1. Value = ((Value + 0x8000) >> 16) & 0xffff; break; @@ -86,196 +105,291 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { break; case Mips::fixup_MICROMIPS_PC16_S1: Value -= 4; - Value >>= 1; + // Forcing a signed division because Value can be negative. + Value = (int64_t)Value / 2; + // We now check if Value can be encoded as a 16-bit signed immediate. + if (!isIntN(16, Value) && Ctx) + Ctx->FatalError(Fixup.getLoc(), "out of range PC16 fixup"); + break; + case Mips::fixup_MIPS_PC18_S3: + // Forcing a signed division because Value can be negative. + Value = (int64_t)Value / 8; + // We now check if Value can be encoded as a 18-bit signed immediate. + if (!isIntN(18, Value) && Ctx) + Ctx->FatalError(Fixup.getLoc(), "out of range PC18 fixup"); + break; + case Mips::fixup_MIPS_PC21_S2: + Value -= 4; + // Forcing a signed division because Value can be negative. + Value = (int64_t) Value / 4; + // We now check if Value can be encoded as a 21-bit signed immediate. + if (!isIntN(21, Value) && Ctx) + Ctx->FatalError(Fixup.getLoc(), "out of range PC21 fixup"); + break; + case Mips::fixup_MIPS_PC26_S2: + Value -= 4; + // Forcing a signed division because Value can be negative. + Value = (int64_t) Value / 4; + // We now check if Value can be encoded as a 26-bit signed immediate. + if (!isIntN(26, Value) && Ctx) + Ctx->FatalError(Fixup.getLoc(), "out of range PC26 fixup"); 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); - } +MCObjectWriter *MipsAsmBackend::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); +// Little-endian fixup data byte ordering: +// mips32r2: a | b | x | x +// microMIPS: x | x | a | b - if (!Value) - return; // Doesn't change encoding. +static bool needsMMLEByteOrder(unsigned Kind) { + return Kind >= Mips::fixup_MICROMIPS_26_S1 && + Kind < Mips::LastTargetFixupKind; +} - // 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; +// Calculate index for microMIPS specific little endian byte order +static unsigned calculateMMLEIndex(unsigned i) { + assert(i <= 3 && "Index out of range!"); - switch ((unsigned)Kind) { - case Mips::fixup_Mips_16: - FullSize = 2; - break; - case Mips::fixup_Mips_64: - FullSize = 8; - break; - default: - FullSize = 4; - break; - } + return (1 - i / 2) * 2 + i % 2; +} - // Grab current value, if any, from bits. - uint64_t CurVal = 0; +/// 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 MipsAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, + unsigned DataSize, uint64_t Value, + bool IsPCRel) const { + MCFixupKind Kind = Fixup.getKind(); + Value = adjustFixupValue(Fixup, Value); - for (unsigned i = 0; i != NumBytes; ++i) { - unsigned Idx = IsLittle ? i : (FullSize - 1 - i); - CurVal |= (uint64_t)((uint8_t)Data[Offset + Idx]) << (i*8); - } + if (!Value) + return; // Doesn't change encoding. - uint64_t Mask = ((uint64_t)(-1) >> - (64 - getFixupKindInfo(Kind).TargetSize)); - CurVal |= Value & Mask; + // 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; - // 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); - } + switch ((unsigned)Kind) { + case FK_Data_2: + case Mips::fixup_Mips_16: + FullSize = 2; + break; + case FK_Data_8: + case Mips::fixup_Mips_64: + FullSize = 8; + break; + case FK_Data_4: + default: + FullSize = 4; + break; } - 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 } - }; + // Grab current value, if any, from bits. + uint64_t CurVal = 0; - if (Kind < FirstTargetFixupKind) - return MCAsmBackend::getFixupKindInfo(Kind); + bool microMipsLEByteOrder = needsMMLEByteOrder((unsigned) Kind); - assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && - "Invalid kind!"); - return Infos[Kind - FirstTargetFixupKind]; + for (unsigned i = 0; i != NumBytes; ++i) { + unsigned Idx = IsLittle ? (microMipsLEByteOrder ? calculateMMLEIndex(i) + : i) + : (FullSize - 1 - i); + CurVal |= (uint64_t)((uint8_t)Data[Offset + Idx]) << (i*8); } - /// @name Target Relaxation Interfaces - /// @{ + uint64_t Mask = ((uint64_t)(-1) >> + (64 - getFixupKindInfo(Kind).TargetSize)); + CurVal |= Value & Mask; - /// MayNeedRelaxation - Check whether the given instruction may need - /// relaxation. - /// - /// \param Inst - The instruction to test. - bool mayNeedRelaxation(const MCInst &Inst) const { - return false; + // Write out the fixed up bytes back to the code/data bits. + for (unsigned i = 0; i != NumBytes; ++i) { + unsigned Idx = IsLittle ? (microMipsLEByteOrder ? calculateMMLEIndex(i) + : i) + : (FullSize - 1 - i); + Data[Offset + Idx] = (uint8_t)((CurVal >> (i*8)) & 0xff); } +} - /// 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; - } +const MCFixupKindInfo &MipsAsmBackend:: +getFixupKindInfo(MCFixupKind Kind) const { + const static MCFixupKindInfo LittleEndianInfos[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_Mips_PC18_S3", 0, 18, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PC19_S2", 0, 19, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PC21_S2", 0, 21, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PC26_S2", 0, 26, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PCHI16", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PCLO16", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "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_GD", 0, 16, 0 }, + { "fixup_MICROMIPS_TLS_LDM", 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 } + }; - /// 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 { - } + const static MCFixupKindInfo BigEndianInfos[Mips::NumTargetFixupKinds] = { + // This table *must* be in same the order of fixup_* kinds in + // MipsFixupKinds.h. + // + // name offset bits flags + { "fixup_Mips_16", 16, 16, 0 }, + { "fixup_Mips_32", 0, 32, 0 }, + { "fixup_Mips_REL32", 0, 32, 0 }, + { "fixup_Mips_26", 6, 26, 0 }, + { "fixup_Mips_HI16", 16, 16, 0 }, + { "fixup_Mips_LO16", 16, 16, 0 }, + { "fixup_Mips_GPREL16", 16, 16, 0 }, + { "fixup_Mips_LITERAL", 16, 16, 0 }, + { "fixup_Mips_GOT_Global", 16, 16, 0 }, + { "fixup_Mips_GOT_Local", 16, 16, 0 }, + { "fixup_Mips_PC16", 16, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_Mips_CALL16", 16, 16, 0 }, + { "fixup_Mips_GPREL32", 0, 32, 0 }, + { "fixup_Mips_SHIFT5", 21, 5, 0 }, + { "fixup_Mips_SHIFT6", 21, 5, 0 }, + { "fixup_Mips_64", 0, 64, 0 }, + { "fixup_Mips_TLSGD", 16, 16, 0 }, + { "fixup_Mips_GOTTPREL", 16, 16, 0 }, + { "fixup_Mips_TPREL_HI", 16, 16, 0 }, + { "fixup_Mips_TPREL_LO", 16, 16, 0 }, + { "fixup_Mips_TLSLDM", 16, 16, 0 }, + { "fixup_Mips_DTPREL_HI", 16, 16, 0 }, + { "fixup_Mips_DTPREL_LO", 16, 16, 0 }, + { "fixup_Mips_Branch_PCRel",16, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_Mips_GPOFF_HI", 16, 16, 0 }, + { "fixup_Mips_GPOFF_LO", 16, 16, 0 }, + { "fixup_Mips_GOT_PAGE", 16, 16, 0 }, + { "fixup_Mips_GOT_OFST", 16, 16, 0 }, + { "fixup_Mips_GOT_DISP", 16, 16, 0 }, + { "fixup_Mips_HIGHER", 16, 16, 0 }, + { "fixup_Mips_HIGHEST", 16, 16, 0 }, + { "fixup_Mips_GOT_HI16", 16, 16, 0 }, + { "fixup_Mips_GOT_LO16", 16, 16, 0 }, + { "fixup_Mips_CALL_HI16", 16, 16, 0 }, + { "fixup_Mips_CALL_LO16", 16, 16, 0 }, + { "fixup_Mips_PC18_S3", 14, 18, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PC19_S2", 13, 19, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PC21_S2", 11, 21, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PC26_S2", 6, 26, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PCHI16", 16, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PCLO16", 16, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MICROMIPS_26_S1", 6, 26, 0 }, + { "fixup_MICROMIPS_HI16", 16, 16, 0 }, + { "fixup_MICROMIPS_LO16", 16, 16, 0 }, + { "fixup_MICROMIPS_GOT16", 16, 16, 0 }, + { "fixup_MICROMIPS_PC16_S1",16, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MICROMIPS_CALL16", 16, 16, 0 }, + { "fixup_MICROMIPS_GOT_DISP", 16, 16, 0 }, + { "fixup_MICROMIPS_GOT_PAGE", 16, 16, 0 }, + { "fixup_MICROMIPS_GOT_OFST", 16, 16, 0 }, + { "fixup_MICROMIPS_TLS_GD", 16, 16, 0 }, + { "fixup_MICROMIPS_TLS_LDM", 16, 16, 0 }, + { "fixup_MICROMIPS_TLS_DTPREL_HI16", 16, 16, 0 }, + { "fixup_MICROMIPS_TLS_DTPREL_LO16", 16, 16, 0 }, + { "fixup_MICROMIPS_TLS_TPREL_HI16", 16, 16, 0 }, + { "fixup_MICROMIPS_TLS_TPREL_LO16", 16, 16, 0 } + }; - /// @} + if (Kind < FirstTargetFixupKind) + return MCAsmBackend::getFixupKindInfo(Kind); - /// 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; + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); - uint64_t NumNops = Count / 4; - for (uint64_t i = 0; i != NumNops; ++i) - OW->Write32(0); - return true; - } -}; // class MipsAsmBackend + if (IsLittle) + return LittleEndianInfos[Kind - FirstTargetFixupKind]; + return BigEndianInfos[Kind - FirstTargetFixupKind]; +} + +/// 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 MipsAsmBackend::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; -} // namespace + uint64_t NumNops = Count / 4; + for (uint64_t i = 0; i != NumNops; ++i) + OW->Write32(0); + return true; +} + +/// processFixupValue - Target hook to process the literal value of a fixup +/// if necessary. +void MipsAsmBackend::processFixupValue(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFixup &Fixup, + const MCFragment *DF, + const MCValue &Target, + uint64_t &Value, + bool &IsResolved) { + // At this point we'll ignore the value returned by adjustFixupValue as + // we are only checking if the fixup can be applied correctly. We have + // access to MCContext from here which allows us to report a fatal error + // with *possibly* a source code location. + (void)adjustFixupValue(Fixup, Value, &Asm.getContext()); +} // MCAsmBackend MCAsmBackend *llvm::createMipsAsmBackendEL32(const Target &T, @@ -309,4 +423,3 @@ MCAsmBackend *llvm::createMipsAsmBackendEB64(const Target &T, return new MipsAsmBackend(T, Triple(TT).getOS(), /*IsLittle*/false, /*Is64Bit*/true); } - diff --git a/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h b/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h new file mode 100644 index 000000000000..d5c3dbc47880 --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h @@ -0,0 +1,93 @@ +//===-- MipsAsmBackend.h - 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 defines the MipsAsmBackend class. +// +//===----------------------------------------------------------------------===// +// + +#ifndef MIPSASMBACKEND_H +#define MIPSASMBACKEND_H + +#include "MCTargetDesc/MipsFixupKinds.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/ADT/Triple.h" + +namespace llvm { + +class MCAssembler; +struct MCFixupKindInfo; +class Target; +class MCObjectWriter; + +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 override; + + void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, + uint64_t Value, bool IsPCRel) const override; + + const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; + + unsigned getNumFixupKinds() const override { + return Mips::NumTargetFixupKinds; + } + + /// @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 override { + return false; + } + + /// fixupNeedsRelaxation - Target specific predicate for whether a given + /// fixup requires the associated instruction to be relaxed. + bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const override { + // FIXME. + llvm_unreachable("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 override {} + + /// @} + + bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override; + + void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout, + const MCFixup &Fixup, const MCFragment *DF, + const MCValue &Target, uint64_t &Value, + bool &IsResolved) override; + +}; // class MipsAsmBackend + +} // namespace + +#endif diff --git a/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h b/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h index 7a55efd5c330..d2323dc1b47b 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h +++ b/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h @@ -120,34 +120,6 @@ namespace MipsII { 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/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp b/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp index 83c7d4bcc3c6..4ea7846f83f6 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp @@ -21,17 +21,6 @@ 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, @@ -39,16 +28,10 @@ namespace { 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); + unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel) const override; + bool needsRelocateWithSymbol(const MCSymbolData &SD, + unsigned Type) const override; }; } @@ -60,26 +43,9 @@ MipsELFObjectWriter::MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI, 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 { + bool IsPCRel) const { // determine the type of the relocation unsigned Type = (unsigned)ELF::R_MIPS_NONE; unsigned Kind = (unsigned)Fixup.getKind(); @@ -210,6 +176,12 @@ unsigned MipsELFObjectWriter::GetRelocType(const MCValue &Target, case Mips::fixup_MICROMIPS_GOT_OFST: Type = ELF::R_MICROMIPS_GOT_OFST; break; + case Mips::fixup_MICROMIPS_TLS_GD: + Type = ELF::R_MICROMIPS_TLS_GD; + break; + case Mips::fixup_MICROMIPS_TLS_LDM: + Type = ELF::R_MICROMIPS_TLS_LDM; + break; case Mips::fixup_MICROMIPS_TLS_DTPREL_HI16: Type = ELF::R_MICROMIPS_TLS_DTPREL_HI16; break; @@ -222,95 +194,62 @@ unsigned MipsELFObjectWriter::GetRelocType(const MCValue &Target, case Mips::fixup_MICROMIPS_TLS_TPREL_LO16: Type = ELF::R_MICROMIPS_TLS_TPREL_LO16; break; + case Mips::fixup_MIPS_PC19_S2: + Type = ELF::R_MIPS_PC19_S2; + break; + case Mips::fixup_MIPS_PC18_S3: + Type = ELF::R_MIPS_PC18_S3; + break; + case Mips::fixup_MIPS_PC21_S2: + Type = ELF::R_MIPS_PC21_S2; + break; + case Mips::fixup_MIPS_PC26_S2: + Type = ELF::R_MIPS_PC26_S2; + break; + case Mips::fixup_MIPS_PCHI16: + Type = ELF::R_MIPS_PCHI16; + break; + case Mips::fixup_MIPS_PCLO16: + Type = ELF::R_MIPS_PCLO16; + 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; +bool +MipsELFObjectWriter::needsRelocateWithSymbol(const MCSymbolData &SD, + unsigned Type) const { + // FIXME: This is extremelly conservative. This really needs to use a + // whitelist with a clear explanation for why each realocation needs to + // point to the symbol, not to the section. + switch (Type) { + default: + return true; - MCSymbolData &SD = Asm.getSymbolData(R.Sym->AliasedSymbol()); + case ELF::R_MIPS_GOT16: + case ELF::R_MIPS16_GOT16: + case ELF::R_MICROMIPS_GOT16: + llvm_unreachable("Should have been handled already"); - return ((R.Reloc.Type == ELF::R_MIPS_GOT16) && !SD.isExternal()) || - (R.Reloc.Type == ELF::R_MIPS_HI16); -} + // These relocations might be paired with another relocation. The pairing is + // done by the static linker by matching the symbol. Since we only see one + // relocation at a time, we have to force them to relocate with a symbol to + // avoid ending up with a pair where one points to a section and another + // points to a symbol. + case ELF::R_MIPS_HI16: + case ELF::R_MIPS16_HI16: + case ELF::R_MICROMIPS_HI16: + case ELF::R_MIPS_LO16: + case ELF::R_MIPS16_LO16: + case ELF::R_MICROMIPS_LO16: + return true; -static bool HasMatchingLo(const MCAssembler &Asm, RelLsIter I, RelLsIter Last) { - if (I == Last) + case ELF::R_MIPS_26: + case ELF::R_MIPS_32: + case ELF::R_MIPS_64: + case ELF::R_MIPS_GPREL16: 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, diff --git a/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp b/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp new file mode 100644 index 000000000000..803ab85657dc --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp @@ -0,0 +1,43 @@ +//===-------- MipsELFStreamer.cpp - ELF Object Output ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsELFStreamer.h" +#include "llvm/MC/MCInst.h" + +void MipsELFStreamer::EmitInstruction(const MCInst &Inst, + const MCSubtargetInfo &STI) { + MCELFStreamer::EmitInstruction(Inst, STI); + + MCContext &Context = getContext(); + const MCRegisterInfo *MCRegInfo = Context.getRegisterInfo(); + + for (unsigned OpIndex = 0; OpIndex < Inst.getNumOperands(); ++OpIndex) { + const MCOperand &Op = Inst.getOperand(OpIndex); + + if (!Op.isReg()) + continue; + + unsigned Reg = Op.getReg(); + RegInfoRecord->SetPhysRegUsed(Reg, MCRegInfo); + } +} + +void MipsELFStreamer::EmitMipsOptionRecords() { + for (const auto &I : MipsOptionRecords) + I->EmitMipsOptionRecord(); +} + +namespace llvm { +MCELFStreamer *createMipsELFStreamer(MCContext &Context, MCAsmBackend &MAB, + raw_ostream &OS, MCCodeEmitter *Emitter, + const MCSubtargetInfo &STI, bool RelaxAll, + bool NoExecStack) { + return new MipsELFStreamer(Context, MAB, OS, Emitter, STI); +} +} diff --git a/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.h b/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.h new file mode 100644 index 000000000000..58863be9cc23 --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.h @@ -0,0 +1,58 @@ +//===-------- MipsELFStreamer.h - ELF Object Output -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a custom MCELFStreamer which allows us to insert some hooks before +// emitting data into an actual object file. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSELFSTREAMER_H +#define MIPSELFSTREAMER_H + +#include "MipsOptionRecord.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/MC/MCELFStreamer.h" +#include <memory> + +namespace llvm { +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCSubtargetInfo; + +class MipsELFStreamer : public MCELFStreamer { + SmallVector<std::unique_ptr<MipsOptionRecord>, 8> MipsOptionRecords; + MipsRegInfoRecord *RegInfoRecord; + +public: + MipsELFStreamer(MCContext &Context, MCAsmBackend &MAB, raw_ostream &OS, + MCCodeEmitter *Emitter, const MCSubtargetInfo &STI) + : MCELFStreamer(Context, MAB, OS, Emitter) { + + RegInfoRecord = new MipsRegInfoRecord(this, Context, STI); + MipsOptionRecords.push_back( + std::unique_ptr<MipsRegInfoRecord>(RegInfoRecord)); + } + + /// Overriding this function allows us to add arbitrary behaviour before the + /// \p Inst is actually emitted. For example, we can inspect the operands and + /// gather sufficient information that allows us to reason about the register + /// usage for the translation unit. + void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override; + + /// Emits all the option records stored up until the point it's called. + void EmitMipsOptionRecords(); +}; + +MCELFStreamer *createMipsELFStreamer(MCContext &Context, MCAsmBackend &MAB, + raw_ostream &OS, MCCodeEmitter *Emitter, + const MCSubtargetInfo &STI, bool RelaxAll, + bool NoExecStack); +} // namespace llvm. +#endif diff --git a/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h b/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h index 6ed44b74cc4b..05080f046f89 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h +++ b/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h @@ -128,6 +128,24 @@ namespace Mips { // resulting in - R_MIPS_CALL_LO16 fixup_Mips_CALL_LO16, + // resulting in - R_MIPS_PC18_S3 + fixup_MIPS_PC18_S3, + + // resulting in - R_MIPS_PC19_S2 + fixup_MIPS_PC19_S2, + + // resulting in - R_MIPS_PC21_S2 + fixup_MIPS_PC21_S2, + + // resulting in - R_MIPS_PC26_S2 + fixup_MIPS_PC26_S2, + + // resulting in - R_MIPS_PCHI16 + fixup_MIPS_PCHI16, + + // resulting in - R_MIPS_PCLO16 + fixup_MIPS_PCLO16, + // resulting in - R_MICROMIPS_26_S1 fixup_MICROMIPS_26_S1, @@ -155,6 +173,12 @@ namespace Mips { // resulting in - R_MICROMIPS_GOT_OFST fixup_MICROMIPS_GOT_OFST, + // resulting in - R_MICROMIPS_TLS_GD + fixup_MICROMIPS_TLS_GD, + + // resulting in - R_MICROMIPS_TLS_LDM + fixup_MICROMIPS_TLS_LDM, + // resulting in - R_MICROMIPS_TLS_DTPREL_HI16 fixup_MICROMIPS_TLS_DTPREL_HI16, diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp index 6aa3c762d9db..e415412ab6cb 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp @@ -38,7 +38,7 @@ MipsMCAsmInfo::MipsMCAsmInfo(StringRef TT) { ZeroDirective = "\t.space\t"; GPRel32Directive = "\t.gpword\t"; GPRel64Directive = "\t.gpdword\t"; - DebugLabelSuffix = "=."; + UseAssignmentForEHBegin = true; SupportsDebugInformation = true; ExceptionsType = ExceptionHandling::DwarfCFI; HasLEB128 = true; diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h b/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h index 1000113351b4..37ba0c4aaa7b 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h +++ b/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h @@ -20,7 +20,7 @@ namespace llvm { class StringRef; class MipsMCAsmInfo : public MCAsmInfoELF { - virtual void anchor(); + void anchor() override; public: explicit MipsMCAsmInfo(StringRef TT); }; diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp index 66428bdfa747..43fc52136ddc 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -11,137 +11,42 @@ // //===----------------------------------------------------------------------===// // -#define DEBUG_TYPE "mccodeemitter" -#include "MCTargetDesc/MipsBaseInfo.h" + +#include "MipsMCCodeEmitter.h" #include "MCTargetDesc/MipsFixupKinds.h" +#include "MCTargetDesc/MipsMCExpr.h" #include "MCTargetDesc/MipsMCTargetDesc.h" #include "llvm/ADT/APFloat.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/ADT/SmallVector.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/MCFixup.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/raw_ostream.h" +#define DEBUG_TYPE "mccodeemitter" + #define GET_INSTRMAP_INFO #include "MipsGenInstrInfo.inc" +#undef GET_INSTRMAP_INFO -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); +namespace llvm { +MCCodeEmitter *createMipsMCCodeEmitterEB(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new MipsMCCodeEmitter(MCII, Ctx, false); } -MCCodeEmitter *llvm::createMipsMCCodeEmitterEL(const MCInstrInfo &MCII, - const MCRegisterInfo &MRI, - const MCSubtargetInfo &STI, - MCContext &Ctx) -{ - return new MipsMCCodeEmitter(MCII, Ctx, STI, true); +MCCodeEmitter *createMipsMCCodeEmitterEL(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new MipsMCCodeEmitter(MCII, Ctx, true); } - +} // End of namespace llvm. // 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 @@ -208,11 +113,38 @@ static void LowerDextDins(MCInst& InstIn) { return; } +bool MipsMCCodeEmitter::isMicroMips(const MCSubtargetInfo &STI) const { + return STI.getFeatureBits() & Mips::FeatureMicroMips; +} + +void MipsMCCodeEmitter::EmitByte(unsigned char C, raw_ostream &OS) const { + OS << (char)C; +} + +void MipsMCCodeEmitter::EmitInstruction(uint64_t Val, unsigned Size, + const MCSubtargetInfo &STI, + 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(STI)) { + EmitInstruction(Val >> 16, 2, STI, OS); + EmitInstruction(Val, 2, STI, OS); + } else { + for (unsigned i = 0; i < Size; ++i) { + unsigned Shift = IsLittleEndian ? i * 8 : (Size - 1 - i) * 8; + EmitByte((Val >> Shift) & 0xff, OS); + } + } +} + /// EncodeInstruction - Emit the instruction. /// Size the instruction with Desc.getSize(). void MipsMCCodeEmitter:: EncodeInstruction(const MCInst &MI, raw_ostream &OS, - SmallVectorImpl<MCFixup> &Fixups) const + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { // Non-pseudo instructions that get changed for direct object @@ -235,7 +167,7 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS, } unsigned long N = Fixups.size(); - uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups); + uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI); // Check for unimplemented opcodes. // Unfortunately in MIPS both NOP and SLL will come in with Binary == 0 @@ -251,7 +183,7 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS, Fixups.pop_back(); Opcode = NewOpcode; TmpInst.setOpcode (NewOpcode); - Binary = getBinaryCodeForInstr(TmpInst, Fixups); + Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI); } } @@ -262,7 +194,7 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS, if (!Size) llvm_unreachable("Desc.getSize() returns 0"); - EmitInstruction(Binary, Size, OS); + EmitInstruction(Binary, Size, STI, OS); } /// getBranchTargetOpValue - Return binary encoding of the branch @@ -270,7 +202,8 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS, /// record the relocation and return zero. unsigned MipsMCCodeEmitter:: getBranchTargetOpValue(const MCInst &MI, unsigned OpNo, - SmallVectorImpl<MCFixup> &Fixups) const { + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(OpNo); @@ -291,7 +224,8 @@ getBranchTargetOpValue(const MCInst &MI, unsigned OpNo, /// record the relocation and return zero. unsigned MipsMCCodeEmitter:: getBranchTargetOpValueMM(const MCInst &MI, unsigned OpNo, - SmallVectorImpl<MCFixup> &Fixups) const { + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(OpNo); @@ -308,12 +242,76 @@ getBranchTargetOpValueMM(const MCInst &MI, unsigned OpNo, return 0; } +/// getBranchTarget21OpValue - Return binary encoding of the branch +/// target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getBranchTarget21OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) 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() && + "getBranchTarget21OpValue expects only expressions or immediates"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::Create(0, Expr, + MCFixupKind(Mips::fixup_MIPS_PC21_S2))); + return 0; +} + +/// getBranchTarget26OpValue - Return binary encoding of the branch +/// target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getBranchTarget26OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) 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() && + "getBranchTarget26OpValue expects only expressions or immediates"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::Create(0, Expr, + MCFixupKind(Mips::fixup_MIPS_PC26_S2))); + return 0; +} + +/// getJumpOffset16OpValue - Return binary encoding of the jump +/// target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getJumpOffset16OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + + const MCOperand &MO = MI.getOperand(OpNo); + + if (MO.isImm()) return MO.getImm(); + + assert(MO.isExpr() && + "getJumpOffset16OpValue expects only expressions or an immediate"); + + // TODO: Push fixup. + 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 { + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(OpNo); // If the destination is an immediate, divide by 4. @@ -330,7 +328,8 @@ getJumpTargetOpValue(const MCInst &MI, unsigned OpNo, unsigned MipsMCCodeEmitter:: getJumpTargetOpValueMM(const MCInst &MI, unsigned OpNo, - SmallVectorImpl<MCFixup> &Fixups) const { + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(OpNo); // If the destination is an immediate, divide by 2. @@ -346,7 +345,8 @@ getJumpTargetOpValueMM(const MCInst &MI, unsigned OpNo, } unsigned MipsMCCodeEmitter:: -getExprOpValue(const MCExpr *Expr,SmallVectorImpl<MCFixup> &Fixups) const { +getExprOpValue(const MCExpr *Expr,SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { int64_t Res; if (Expr->EvaluateAsAbsolute(Res)) @@ -358,101 +358,135 @@ getExprOpValue(const MCExpr *Expr,SmallVectorImpl<MCFixup> &Fixups) const { } if (Kind == MCExpr::Binary) { - unsigned Res = getExprOpValue(cast<MCBinaryExpr>(Expr)->getLHS(), Fixups); - Res += getExprOpValue(cast<MCBinaryExpr>(Expr)->getRHS(), Fixups); + unsigned Res = getExprOpValue(cast<MCBinaryExpr>(Expr)->getLHS(), Fixups, STI); + Res += getExprOpValue(cast<MCBinaryExpr>(Expr)->getRHS(), Fixups, STI); return Res; } + + if (Kind == MCExpr::Target) { + const MipsMCExpr *MipsExpr = cast<MipsMCExpr>(Expr); + + Mips::Fixups FixupKind = Mips::Fixups(0); + switch (MipsExpr->getKind()) { + default: llvm_unreachable("Unsupported fixup kind for target expression!"); + case MipsMCExpr::VK_Mips_HIGHEST: + FixupKind = Mips::fixup_Mips_HIGHEST; + break; + case MipsMCExpr::VK_Mips_HIGHER: + FixupKind = Mips::fixup_Mips_HIGHER; + break; + case MipsMCExpr::VK_Mips_HI: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_HI16 + : Mips::fixup_Mips_HI16; + break; + case MipsMCExpr::VK_Mips_LO: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_LO16 + : Mips::fixup_Mips_LO16; + break; + } + Fixups.push_back(MCFixup::Create(0, MipsExpr, MCFixupKind(FixupKind))); + return 0; + } + if (Kind == MCExpr::SymbolRef) { - Mips::Fixups FixupKind = Mips::Fixups(0); + 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 + 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(STI) ? Mips::fixup_MICROMIPS_GOT_PAGE + : Mips::fixup_Mips_GOT_PAGE; + break; + case MCSymbolRefExpr::VK_Mips_GOT_OFST : + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_GOT_OFST + : Mips::fixup_Mips_GOT_OFST; + break; + case MCSymbolRefExpr::VK_Mips_GOT_DISP : + FixupKind = isMicroMips(STI) ? 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(STI) ? Mips::fixup_MICROMIPS_CALL16 + : Mips::fixup_Mips_CALL16; + break; + case MCSymbolRefExpr::VK_Mips_GOT16: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_GOT16 + : Mips::fixup_Mips_GOT_Global; + break; + case MCSymbolRefExpr::VK_Mips_GOT: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_GOT16 + : Mips::fixup_Mips_GOT_Local; + break; + case MCSymbolRefExpr::VK_Mips_ABS_HI: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_HI16 + : Mips::fixup_Mips_HI16; + break; + case MCSymbolRefExpr::VK_Mips_ABS_LO: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_LO16 + : Mips::fixup_Mips_LO16; + break; + case MCSymbolRefExpr::VK_Mips_TLSGD: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_GD + : Mips::fixup_Mips_TLSGD; + break; + case MCSymbolRefExpr::VK_Mips_TLSLDM: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_LDM + : Mips::fixup_Mips_TLSLDM; + break; + case MCSymbolRefExpr::VK_Mips_DTPREL_HI: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_DTPREL_HI16 + : Mips::fixup_Mips_DTPREL_HI; + break; + case MCSymbolRefExpr::VK_Mips_DTPREL_LO: + FixupKind = isMicroMips(STI) ? 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(STI) ? Mips::fixup_MICROMIPS_TLS_TPREL_HI16 + : Mips::fixup_Mips_TPREL_HI; + break; + case MCSymbolRefExpr::VK_Mips_TPREL_LO: + FixupKind = isMicroMips(STI) ? 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; + case MCSymbolRefExpr::VK_Mips_PCREL_HI16: + FixupKind = Mips::fixup_MIPS_PCHI16; + break; + case MCSymbolRefExpr::VK_Mips_PCREL_LO16: + FixupKind = Mips::fixup_MIPS_PCLO16; + break; + } // switch Fixups.push_back(MCFixup::Create(0, Expr, MCFixupKind(FixupKind))); return 0; @@ -464,7 +498,8 @@ getExprOpValue(const MCExpr *Expr,SmallVectorImpl<MCFixup> &Fixups) const { /// operand requires relocation, record the relocation and return zero. unsigned MipsMCCodeEmitter:: getMachineOpValue(const MCInst &MI, const MCOperand &MO, - SmallVectorImpl<MCFixup> &Fixups) const { + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { if (MO.isReg()) { unsigned Reg = MO.getReg(); unsigned RegNo = Ctx.getRegisterInfo()->getEncodingValue(Reg); @@ -477,38 +512,85 @@ getMachineOpValue(const MCInst &MI, const MCOperand &MO, } // MO must be an Expr. assert(MO.isExpr()); - return getExprOpValue(MO.getExpr(),Fixups); + return getExprOpValue(MO.getExpr(),Fixups, STI); +} + +/// getMSAMemEncoding - Return binary encoding of memory operand for LD/ST +/// instructions. +unsigned +MipsMCCodeEmitter::getMSAMemEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) 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, STI) << 16; + unsigned OffBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups, STI); + + // The immediate field of an LD/ST instruction is scaled which means it must + // be divided (when encoding) by the size (in bytes) of the instructions' + // data format. + // .b - 1 byte + // .h - 2 bytes + // .w - 4 bytes + // .d - 8 bytes + switch(MI.getOpcode()) + { + default: + assert (0 && "Unexpected instruction"); + break; + case Mips::LD_B: + case Mips::ST_B: + // We don't need to scale the offset in this case + break; + case Mips::LD_H: + case Mips::ST_H: + OffBits >>= 1; + break; + case Mips::LD_W: + case Mips::ST_W: + OffBits >>= 2; + break; + case Mips::LD_D: + case Mips::ST_D: + OffBits >>= 3; + break; + } + + return (OffBits & 0xFFFF) | RegBits; } /// 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 { + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) 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); + unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo),Fixups, STI) << 16; + unsigned OffBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups, STI); return (OffBits & 0xFFFF) | RegBits; } unsigned MipsMCCodeEmitter:: getMemEncodingMMImm12(const MCInst &MI, unsigned OpNo, - SmallVectorImpl<MCFixup> &Fixups) const { + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) 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); + unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI) << 16; + unsigned OffBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups, STI); return (OffBits & 0x0FFF) | RegBits; } unsigned MipsMCCodeEmitter::getSizeExtEncoding(const MCInst &MI, unsigned OpNo, - SmallVectorImpl<MCFixup> &Fixups) const { + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { assert(MI.getOperand(OpNo).isImm()); - unsigned SizeEncoding = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups); + unsigned SizeEncoding = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI); return SizeEncoding - 1; } @@ -516,22 +598,65 @@ MipsMCCodeEmitter::getSizeExtEncoding(const MCInst &MI, unsigned OpNo, // unsigned MipsMCCodeEmitter::getSizeInsEncoding(const MCInst &MI, unsigned OpNo, - SmallVectorImpl<MCFixup> &Fixups) const { + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) 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); + unsigned Position = getMachineOpValue(MI, MI.getOperand(OpNo-1), Fixups, STI); + unsigned Size = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI); return Position + Size - 1; } unsigned MipsMCCodeEmitter::getLSAImmEncoding(const MCInst &MI, unsigned OpNo, - SmallVectorImpl<MCFixup> &Fixups) const { + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { assert(MI.getOperand(OpNo).isImm()); // The immediate is encoded as 'immediate - 1'. - return getMachineOpValue(MI, MI.getOperand(OpNo), Fixups) - 1; + return getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI) - 1; } -#include "MipsGenMCCodeEmitter.inc" +unsigned +MipsMCCodeEmitter::getSimm19Lsl2Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isImm()) { + // The immediate is encoded as 'immediate << 2'. + unsigned Res = getMachineOpValue(MI, MO, Fixups, STI); + assert((Res & 3) == 0); + return Res >> 2; + } + assert(MO.isExpr() && + "getSimm19Lsl2Encoding expects only expressions or an immediate"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::Create(0, Expr, + MCFixupKind(Mips::fixup_MIPS_PC19_S2))); + return 0; +} + +unsigned +MipsMCCodeEmitter::getSimm18Lsl3Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isImm()) { + // The immediate is encoded as 'immediate << 3'. + unsigned Res = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI); + assert((Res & 7) == 0); + return Res >> 3; + } + + assert(MO.isExpr() && + "getSimm18Lsl2Encoding expects only expressions or an immediate"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::Create(0, Expr, + MCFixupKind(Mips::fixup_MIPS_PC18_S3))); + return 0; +} + +#include "MipsGenMCCodeEmitter.inc" diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h b/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h new file mode 100644 index 000000000000..304167fd03db --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h @@ -0,0 +1,154 @@ +//===-- MipsMCCodeEmitter.h - 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 defines the MipsMCCodeEmitter class. +// +//===----------------------------------------------------------------------===// +// + +#ifndef MIPS_MC_CODE_EMITTER_H +#define MIPS_MC_CODE_EMITTER_H + +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/Support/DataTypes.h" + +using namespace llvm; + +namespace llvm { +class MCContext; +class MCExpr; +class MCInst; +class MCInstrInfo; +class MCFixup; +class MCOperand; +class MCSubtargetInfo; +class raw_ostream; + +class MipsMCCodeEmitter : public MCCodeEmitter { + MipsMCCodeEmitter(const MipsMCCodeEmitter &) LLVM_DELETED_FUNCTION; + void operator=(const MipsMCCodeEmitter &) LLVM_DELETED_FUNCTION; + const MCInstrInfo &MCII; + MCContext &Ctx; + bool IsLittleEndian; + + bool isMicroMips(const MCSubtargetInfo &STI) const; + +public: + MipsMCCodeEmitter(const MCInstrInfo &mcii, MCContext &Ctx_, bool IsLittle) + : MCII(mcii), Ctx(Ctx_), IsLittleEndian(IsLittle) {} + + ~MipsMCCodeEmitter() {} + + void EmitByte(unsigned char C, raw_ostream &OS) const; + + void EmitInstruction(uint64_t Val, unsigned Size, const MCSubtargetInfo &STI, + raw_ostream &OS) const; + + void EncodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const override; + + // getBinaryCodeForInstr - TableGen'erated function for getting the + // binary encoding for an instruction. + uint64_t getBinaryCodeForInstr(const MCInst &MI, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) 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 MCSubtargetInfo &STI) 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 MCSubtargetInfo &STI) 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 MCSubtargetInfo &STI) 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 MCSubtargetInfo &STI) const; + + // getBranchTarget21OpValue - Return binary encoding of the branch + // offset operand. If the machine operand requires relocation, + // record the relocation and return zero. + unsigned getBranchTarget21OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + // getBranchTarget26OpValue - Return binary encoding of the branch + // offset operand. If the machine operand requires relocation, + // record the relocation and return zero. + unsigned getBranchTarget26OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + // getJumpOffset16OpValue - Return binary encoding of the jump + // offset operand. If the machine operand requires relocation, + // record the relocation and return zero. + unsigned getJumpOffset16OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) 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 MCSubtargetInfo &STI) const; + + unsigned getMSAMemEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getMemEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getMemEncodingMMImm12(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getSizeExtEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getSizeInsEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + // getLSAImmEncoding - Return binary encoding of LSA immediate. + unsigned getLSAImmEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getSimm19Lsl2Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getSimm18Lsl3Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getExprOpValue(const MCExpr *Expr, SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + +}; // class MipsMCCodeEmitter +} // namespace llvm. + +#endif diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp new file mode 100644 index 000000000000..5bba3e5b7ae2 --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp @@ -0,0 +1,89 @@ +//===-- MipsMCExpr.cpp - Mips specific MC expression classes --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsMCExpr.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectStreamer.h" + +using namespace llvm; + +#define DEBUG_TYPE "mipsmcexpr" + +bool MipsMCExpr::isSupportedBinaryExpr(MCSymbolRefExpr::VariantKind VK, + const MCBinaryExpr *BE) { + switch (VK) { + case MCSymbolRefExpr::VK_Mips_ABS_LO: + case MCSymbolRefExpr::VK_Mips_ABS_HI: + case MCSymbolRefExpr::VK_Mips_HIGHER: + case MCSymbolRefExpr::VK_Mips_HIGHEST: + break; + default: + return false; + } + + // We support expressions of the form "(sym1 binop1 sym2) binop2 const", + // where "binop2 const" is optional. + if (isa<MCBinaryExpr>(BE->getLHS())) { + if (!isa<MCConstantExpr>(BE->getRHS())) + return false; + BE = cast<MCBinaryExpr>(BE->getLHS()); + } + return (isa<MCSymbolRefExpr>(BE->getLHS()) + && isa<MCSymbolRefExpr>(BE->getRHS())); +} + +const MipsMCExpr* +MipsMCExpr::Create(MCSymbolRefExpr::VariantKind VK, const MCExpr *Expr, + MCContext &Ctx) { + VariantKind Kind; + switch (VK) { + case MCSymbolRefExpr::VK_Mips_ABS_LO: + Kind = VK_Mips_LO; + break; + case MCSymbolRefExpr::VK_Mips_ABS_HI: + Kind = VK_Mips_HI; + break; + case MCSymbolRefExpr::VK_Mips_HIGHER: + Kind = VK_Mips_HIGHER; + break; + case MCSymbolRefExpr::VK_Mips_HIGHEST: + Kind = VK_Mips_HIGHEST; + break; + default: + llvm_unreachable("Invalid kind!"); + } + + return new (Ctx) MipsMCExpr(Kind, Expr); +} + +void MipsMCExpr::PrintImpl(raw_ostream &OS) const { + switch (Kind) { + default: llvm_unreachable("Invalid kind!"); + case VK_Mips_LO: OS << "%lo"; break; + case VK_Mips_HI: OS << "%hi"; break; + case VK_Mips_HIGHER: OS << "%higher"; break; + case VK_Mips_HIGHEST: OS << "%highest"; break; + } + + OS << '('; + Expr->print(OS); + OS << ')'; +} + +bool +MipsMCExpr::EvaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout) const { + return getSubExpr()->EvaluateAsRelocatable(Res, Layout); +} + +void MipsMCExpr::visitUsedExpr(MCStreamer &Streamer) const { + Streamer.visitUsedExpr(*getSubExpr()); +} diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h b/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h new file mode 100644 index 000000000000..f193dc9b9d50 --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h @@ -0,0 +1,66 @@ +//===-- MipsMCExpr.h - Mips specific MC expression classes ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSMCEXPR_H +#define MIPSMCEXPR_H + +#include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCValue.h" + +namespace llvm { + +class MipsMCExpr : public MCTargetExpr { +public: + enum VariantKind { + VK_Mips_None, + VK_Mips_LO, + VK_Mips_HI, + VK_Mips_HIGHER, + VK_Mips_HIGHEST + }; + +private: + const VariantKind Kind; + const MCExpr *Expr; + + explicit MipsMCExpr(VariantKind Kind, const MCExpr *Expr) + : Kind(Kind), Expr(Expr) {} + +public: + static bool isSupportedBinaryExpr(MCSymbolRefExpr::VariantKind VK, + const MCBinaryExpr *BE); + + static const MipsMCExpr *Create(MCSymbolRefExpr::VariantKind VK, + const MCExpr *Expr, MCContext &Ctx); + + /// getOpcode - Get the kind of this expression. + VariantKind getKind() const { return Kind; } + + /// getSubExpr - Get the child of this expression. + const MCExpr *getSubExpr() const { return Expr; } + + void PrintImpl(raw_ostream &OS) const override; + bool EvaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout) const override; + void visitUsedExpr(MCStreamer &Streamer) const override; + const MCSection *FindAssociatedSection() const override { + return getSubExpr()->FindAssociatedSection(); + } + + // There are no TLS MipsMCExprs at the moment. + void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {} + + static bool classof(const MCExpr *E) { + return E->getKind() == MCExpr::Target; + } +}; +} // end namespace llvm + +#endif diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h b/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h new file mode 100644 index 000000000000..01d5363812ed --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h @@ -0,0 +1,33 @@ +//===-- MipsMCNaCl.h - NaCl-related declarations --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSMCNACL_H +#define MIPSMCNACL_H + +#include "llvm/MC/MCELFStreamer.h" + +namespace llvm { + +// Log2 of the NaCl MIPS sandbox's instruction bundle size. +static const unsigned MIPS_NACL_BUNDLE_ALIGN = 4u; + +bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx, + bool *IsStore = nullptr); +bool baseRegNeedsLoadStoreMask(unsigned Reg); + +// This function creates an MCELFStreamer for Mips NaCl. +MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, + raw_ostream &OS, + MCCodeEmitter *Emitter, + const MCSubtargetInfo &STI, + bool RelaxAll, bool NoExecStack); + +} + +#endif diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp index 5548aaa9a6d8..d2b929bea334 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp @@ -11,12 +11,14 @@ // //===----------------------------------------------------------------------===// -#include "MipsMCTargetDesc.h" #include "InstPrinter/MipsInstPrinter.h" +#include "MipsELFStreamer.h" #include "MipsMCAsmInfo.h" +#include "MipsMCNaCl.h" +#include "MipsMCTargetDesc.h" #include "MipsTargetStreamer.h" +#include "llvm/ADT/Triple.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" @@ -28,6 +30,8 @@ #include "llvm/Support/FormattedStream.h" #include "llvm/Support/TargetRegistry.h" +using namespace llvm; + #define GET_INSTRINFO_MC_DESC #include "MipsGenInstrInfo.inc" @@ -37,38 +41,18 @@ #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"; - } +/// Select the Mips CPU for the given triple and cpu name. +/// FIXME: Merge with the copy in MipsSubtarget.cpp +static inline StringRef selectMipsCPU(StringRef TT, StringRef CPU) { + if (CPU.empty() || CPU == "generic") { + Triple TheTriple(TT); + if (TheTriple.getArch() == Triple::mips || + TheTriple.getArch() == Triple::mipsel) + CPU = "mips32"; + else + CPU = "mips64"; } - return MipsArchFeature; + return CPU; } static MCInstrInfo *createMipsMCInstrInfo() { @@ -85,15 +69,9 @@ static MCRegisterInfo *createMipsMCRegisterInfo(StringRef TT) { 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; - } + CPU = selectMipsCPU(TT, CPU); MCSubtargetInfo *X = new MCSubtargetInfo(); - InitMipsMCSubtargetInfo(X, TT, CPU, ArchFS); + InitMipsMCSubtargetInfo(X, TT, CPU, FS); return X; } @@ -101,7 +79,7 @@ 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); + MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(nullptr, SP, 0); MAI->addInitialFrameState(Inst); return MAI; @@ -131,21 +109,34 @@ static MCInstPrinter *createMipsMCInstPrinter(const Target &T, static MCStreamer *createMCStreamer(const Target &T, StringRef TT, MCContext &Context, MCAsmBackend &MAB, raw_ostream &OS, MCCodeEmitter *Emitter, + const MCSubtargetInfo &STI, bool RelaxAll, bool NoExecStack) { - MipsTargetELFStreamer *S = new MipsTargetELFStreamer(); - return createELFStreamer(Context, S, MAB, OS, Emitter, RelaxAll, NoExecStack); + MCStreamer *S; + if (!Triple(TT).isOSNaCl()) + S = createMipsELFStreamer(Context, MAB, OS, Emitter, STI, RelaxAll, + NoExecStack); + else + S = createMipsNaClELFStreamer(Context, MAB, OS, Emitter, STI, RelaxAll, + NoExecStack); + new MipsTargetELFStreamer(*S, STI); + return S; } 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); + bool isVerboseAsm, bool useDwarfDirectory, + MCInstPrinter *InstPrint, MCCodeEmitter *CE, + MCAsmBackend *TAB, bool ShowInst) { + MCStreamer *S = llvm::createAsmStreamer( + Ctx, OS, isVerboseAsm, useDwarfDirectory, InstPrint, CE, TAB, ShowInst); + new MipsTargetAsmStreamer(*S, OS); + return S; +} - return llvm::createAsmStreamer(Ctx, S, OS, isVerboseAsm, useLoc, useCFI, - useDwarfDirectory, InstPrint, CE, TAB, - ShowInst); +static MCStreamer *createMipsNullStreamer(MCContext &Ctx) { + MCStreamer *S = llvm::createNullStreamer(Ctx); + new MipsTargetStreamer(*S); + return S; } extern "C" void LLVMInitializeMipsTargetMC() { @@ -202,6 +193,12 @@ extern "C" void LLVMInitializeMipsTargetMC() { TargetRegistry::RegisterAsmStreamer(TheMips64Target, createMCAsmStreamer); TargetRegistry::RegisterAsmStreamer(TheMips64elTarget, createMCAsmStreamer); + TargetRegistry::RegisterNullStreamer(TheMipsTarget, createMipsNullStreamer); + TargetRegistry::RegisterNullStreamer(TheMipselTarget, createMipsNullStreamer); + TargetRegistry::RegisterNullStreamer(TheMips64Target, createMipsNullStreamer); + TargetRegistry::RegisterNullStreamer(TheMips64elTarget, + createMipsNullStreamer); + // Register the asm backend. TargetRegistry::RegisterMCAsmBackend(TheMipsTarget, createMipsAsmBackendEB32); diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h b/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h index eabebfe1349e..161d1eae82b9 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h +++ b/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h @@ -42,14 +42,18 @@ MCCodeEmitter *createMipsMCCodeEmitterEL(const MCInstrInfo &MCII, 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); +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, diff --git a/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp b/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp new file mode 100644 index 000000000000..6cde8f9ae3e4 --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp @@ -0,0 +1,272 @@ +//===-- MipsNaClELFStreamer.cpp - ELF Object Output for Mips NaCl ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements MCELFStreamer for Mips NaCl. It emits .o object files +// as required by NaCl's SFI sandbox. It inserts address-masking instructions +// before dangerous control-flow and memory access instructions. It inserts +// address-masking instructions after instructions that change the stack +// pointer. It ensures that the mask and the dangerous instruction are always +// emitted in the same bundle. It aligns call + branch delay to the bundle end, +// so that return address is always aligned to the start of next bundle. +// +//===----------------------------------------------------------------------===// + +#include "Mips.h" +#include "MipsELFStreamer.h" +#include "MipsMCNaCl.h" +#include "llvm/MC/MCELFStreamer.h" + +using namespace llvm; + +#define DEBUG_TYPE "mips-mc-nacl" + +namespace { + +const unsigned IndirectBranchMaskReg = Mips::T6; +const unsigned LoadStoreStackMaskReg = Mips::T7; + +/// Extend the generic MCELFStreamer class so that it can mask dangerous +/// instructions. + +class MipsNaClELFStreamer : public MipsELFStreamer { +public: + MipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS, + MCCodeEmitter *Emitter, const MCSubtargetInfo &STI) + : MipsELFStreamer(Context, TAB, OS, Emitter, STI), PendingCall(false) {} + + ~MipsNaClELFStreamer() {} + +private: + // Whether we started the sandboxing sequence for calls. Calls are bundled + // with branch delays and aligned to the bundle end. + bool PendingCall; + + bool isIndirectJump(const MCInst &MI) { + if (MI.getOpcode() == Mips::JALR) { + // MIPS32r6/MIPS64r6 doesn't have a JR instruction and uses JALR instead. + // JALR is an indirect branch if the link register is $0. + assert(MI.getOperand(0).isReg()); + return MI.getOperand(0).getReg() == Mips::ZERO; + } + return MI.getOpcode() == Mips::JR; + } + + bool isStackPointerFirstOperand(const MCInst &MI) { + return (MI.getNumOperands() > 0 && MI.getOperand(0).isReg() + && MI.getOperand(0).getReg() == Mips::SP); + } + + bool isCall(const MCInst &MI, bool *IsIndirectCall) { + unsigned Opcode = MI.getOpcode(); + + *IsIndirectCall = false; + + switch (Opcode) { + default: + return false; + + case Mips::JAL: + case Mips::BAL: + case Mips::BAL_BR: + case Mips::BLTZAL: + case Mips::BGEZAL: + return true; + + case Mips::JALR: + // JALR is only a call if the link register is not $0. Otherwise it's an + // indirect branch. + assert(MI.getOperand(0).isReg()); + if (MI.getOperand(0).getReg() == Mips::ZERO) + return false; + + *IsIndirectCall = true; + return true; + } + } + + void emitMask(unsigned AddrReg, unsigned MaskReg, + const MCSubtargetInfo &STI) { + MCInst MaskInst; + MaskInst.setOpcode(Mips::AND); + MaskInst.addOperand(MCOperand::CreateReg(AddrReg)); + MaskInst.addOperand(MCOperand::CreateReg(AddrReg)); + MaskInst.addOperand(MCOperand::CreateReg(MaskReg)); + MipsELFStreamer::EmitInstruction(MaskInst, STI); + } + + // Sandbox indirect branch or return instruction by inserting mask operation + // before it. + void sandboxIndirectJump(const MCInst &MI, const MCSubtargetInfo &STI) { + unsigned AddrReg = MI.getOperand(0).getReg(); + + EmitBundleLock(false); + emitMask(AddrReg, IndirectBranchMaskReg, STI); + MipsELFStreamer::EmitInstruction(MI, STI); + EmitBundleUnlock(); + } + + // Sandbox memory access or SP change. Insert mask operation before and/or + // after the instruction. + void sandboxLoadStoreStackChange(const MCInst &MI, unsigned AddrIdx, + const MCSubtargetInfo &STI, bool MaskBefore, + bool MaskAfter) { + EmitBundleLock(false); + if (MaskBefore) { + // Sandbox memory access. + unsigned BaseReg = MI.getOperand(AddrIdx).getReg(); + emitMask(BaseReg, LoadStoreStackMaskReg, STI); + } + MipsELFStreamer::EmitInstruction(MI, STI); + if (MaskAfter) { + // Sandbox SP change. + unsigned SPReg = MI.getOperand(0).getReg(); + assert((Mips::SP == SPReg) && "Unexpected stack-pointer register."); + emitMask(SPReg, LoadStoreStackMaskReg, STI); + } + EmitBundleUnlock(); + } + +public: + /// This function is the one used to emit instruction data into the ELF + /// streamer. We override it to mask dangerous instructions. + void EmitInstruction(const MCInst &Inst, + const MCSubtargetInfo &STI) override { + // Sandbox indirect jumps. + if (isIndirectJump(Inst)) { + if (PendingCall) + report_fatal_error("Dangerous instruction in branch delay slot!"); + sandboxIndirectJump(Inst, STI); + return; + } + + // Sandbox loads, stores and SP changes. + unsigned AddrIdx; + bool IsStore; + bool IsMemAccess = isBasePlusOffsetMemoryAccess(Inst.getOpcode(), &AddrIdx, + &IsStore); + bool IsSPFirstOperand = isStackPointerFirstOperand(Inst); + if (IsMemAccess || IsSPFirstOperand) { + bool MaskBefore = (IsMemAccess + && baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx) + .getReg())); + bool MaskAfter = IsSPFirstOperand && !IsStore; + if (MaskBefore || MaskAfter) { + if (PendingCall) + report_fatal_error("Dangerous instruction in branch delay slot!"); + sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter); + return; + } + // fallthrough + } + + // Sandbox calls by aligning call and branch delay to the bundle end. + // For indirect calls, emit the mask before the call. + bool IsIndirectCall; + if (isCall(Inst, &IsIndirectCall)) { + if (PendingCall) + report_fatal_error("Dangerous instruction in branch delay slot!"); + + // Start the sandboxing sequence by emitting call. + EmitBundleLock(true); + if (IsIndirectCall) { + unsigned TargetReg = Inst.getOperand(1).getReg(); + emitMask(TargetReg, IndirectBranchMaskReg, STI); + } + MipsELFStreamer::EmitInstruction(Inst, STI); + PendingCall = true; + return; + } + if (PendingCall) { + // Finish the sandboxing sequence by emitting branch delay. + MipsELFStreamer::EmitInstruction(Inst, STI); + EmitBundleUnlock(); + PendingCall = false; + return; + } + + // None of the sandboxing applies, just emit the instruction. + MipsELFStreamer::EmitInstruction(Inst, STI); + } +}; + +} // end anonymous namespace + +namespace llvm { + +bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx, + bool *IsStore) { + if (IsStore) + *IsStore = false; + + switch (Opcode) { + default: + return false; + + // Load instructions with base address register in position 1. + case Mips::LB: + case Mips::LBu: + case Mips::LH: + case Mips::LHu: + case Mips::LW: + case Mips::LWC1: + case Mips::LDC1: + case Mips::LL: + case Mips::LL_R6: + case Mips::LWL: + case Mips::LWR: + *AddrIdx = 1; + return true; + + // Store instructions with base address register in position 1. + case Mips::SB: + case Mips::SH: + case Mips::SW: + case Mips::SWC1: + case Mips::SDC1: + case Mips::SWL: + case Mips::SWR: + *AddrIdx = 1; + if (IsStore) + *IsStore = true; + return true; + + // Store instructions with base address register in position 2. + case Mips::SC: + case Mips::SC_R6: + *AddrIdx = 2; + if (IsStore) + *IsStore = true; + return true; + } +} + +bool baseRegNeedsLoadStoreMask(unsigned Reg) { + // The contents of SP and thread pointer register do not require masking. + return Reg != Mips::SP && Reg != Mips::T8; +} + +MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, + raw_ostream &OS, + MCCodeEmitter *Emitter, + const MCSubtargetInfo &STI, + bool RelaxAll, bool NoExecStack) { + MipsNaClELFStreamer *S = new MipsNaClELFStreamer(Context, TAB, OS, Emitter, + STI); + if (RelaxAll) + S->getAssembler().setRelaxAll(true); + if (NoExecStack) + S->getAssembler().setNoExecStack(true); + + // Set bundle-alignment as required by the NaCl ABI for the target. + S->EmitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN); + + return S; +} + +} diff --git a/lib/Target/Mips/MCTargetDesc/MipsOptionRecord.cpp b/lib/Target/Mips/MCTargetDesc/MipsOptionRecord.cpp new file mode 100644 index 000000000000..0ef220821320 --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsOptionRecord.cpp @@ -0,0 +1,92 @@ +//===-- MipsOptionRecord.cpp - Abstraction for storing information --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsOptionRecord.h" +#include "MipsELFStreamer.h" +#include "llvm/MC/MCSectionELF.h" + +using namespace llvm; + +void MipsRegInfoRecord::EmitMipsOptionRecord() { + MCAssembler &MCA = Streamer->getAssembler(); + Triple T(STI.getTargetTriple()); + uint64_t Features = STI.getFeatureBits(); + + Streamer->PushSection(); + + // We need to distinguish between N64 and the rest because at the moment + // we don't emit .Mips.options for other ELFs other than N64. + // Since .reginfo has the same information as .Mips.options (ODK_REGINFO), + // we can use the same abstraction (MipsRegInfoRecord class) to handle both. + if (Features & Mips::FeatureN64) { + // The EntrySize value of 1 seems strange since the records are neither + // 1-byte long nor fixed length but it matches the value GAS emits. + const MCSectionELF *Sec = + Context.getELFSection(".MIPS.options", ELF::SHT_MIPS_OPTIONS, + ELF::SHF_ALLOC | ELF::SHF_MIPS_NOSTRIP, + SectionKind::getMetadata(), 1, ""); + MCA.getOrCreateSectionData(*Sec).setAlignment(8); + Streamer->SwitchSection(Sec); + + Streamer->EmitIntValue(1, 1); // kind + Streamer->EmitIntValue(40, 1); // size + Streamer->EmitIntValue(0, 2); // section + Streamer->EmitIntValue(0, 4); // info + Streamer->EmitIntValue(ri_gprmask, 4); + Streamer->EmitIntValue(0, 4); // pad + Streamer->EmitIntValue(ri_cprmask[0], 4); + Streamer->EmitIntValue(ri_cprmask[1], 4); + Streamer->EmitIntValue(ri_cprmask[2], 4); + Streamer->EmitIntValue(ri_cprmask[3], 4); + Streamer->EmitIntValue(ri_gp_value, 8); + } else { + const MCSectionELF *Sec = + Context.getELFSection(".reginfo", ELF::SHT_MIPS_REGINFO, ELF::SHF_ALLOC, + SectionKind::getMetadata(), 24, ""); + MCA.getOrCreateSectionData(*Sec) + .setAlignment(Features & Mips::FeatureN32 ? 8 : 4); + Streamer->SwitchSection(Sec); + + Streamer->EmitIntValue(ri_gprmask, 4); + Streamer->EmitIntValue(ri_cprmask[0], 4); + Streamer->EmitIntValue(ri_cprmask[1], 4); + Streamer->EmitIntValue(ri_cprmask[2], 4); + Streamer->EmitIntValue(ri_cprmask[3], 4); + assert((ri_gp_value & 0xffffffff) == ri_gp_value); + Streamer->EmitIntValue(ri_gp_value, 4); + } + + Streamer->PopSection(); +} + +void MipsRegInfoRecord::SetPhysRegUsed(unsigned Reg, + const MCRegisterInfo *MCRegInfo) { + unsigned Value = 0; + + for (MCSubRegIterator SubRegIt(Reg, MCRegInfo, true); SubRegIt.isValid(); + ++SubRegIt) { + unsigned CurrentSubReg = *SubRegIt; + + unsigned EncVal = MCRegInfo->getEncodingValue(CurrentSubReg); + Value |= 1 << EncVal; + + if (GPR32RegClass->contains(CurrentSubReg) || + GPR64RegClass->contains(CurrentSubReg)) + ri_gprmask |= Value; + else if (FGR32RegClass->contains(CurrentSubReg) || + FGR64RegClass->contains(CurrentSubReg) || + AFGR64RegClass->contains(CurrentSubReg) || + MSA128BRegClass->contains(CurrentSubReg)) + ri_cprmask[1] |= Value; + else if (COP2RegClass->contains(CurrentSubReg)) + ri_cprmask[2] |= Value; + else if (COP3RegClass->contains(CurrentSubReg)) + ri_cprmask[3] |= Value; + } +} diff --git a/lib/Target/Mips/MCTargetDesc/MipsReginfo.cpp b/lib/Target/Mips/MCTargetDesc/MipsReginfo.cpp deleted file mode 100644 index 1dc9bcb36a5f..000000000000 --- a/lib/Target/Mips/MCTargetDesc/MipsReginfo.cpp +++ /dev/null @@ -1,80 +0,0 @@ -//===-- 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/lib/Target/Mips/MCTargetDesc/MipsReginfo.h b/lib/Target/Mips/MCTargetDesc/MipsReginfo.h deleted file mode 100644 index 039b8eaaf287..000000000000 --- a/lib/Target/Mips/MCTargetDesc/MipsReginfo.h +++ /dev/null @@ -1,31 +0,0 @@ -//=== 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/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp b/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp index 5e90bbc635a5..4a178e2df7a9 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -11,57 +11,632 @@ // //===----------------------------------------------------------------------===// +#include "InstPrinter/MipsInstPrinter.h" +#include "MipsELFStreamer.h" +#include "MipsMCTargetDesc.h" +#include "MipsTargetObjectFile.h" #include "MipsTargetStreamer.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCELF.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/ELF.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); +MipsTargetStreamer::MipsTargetStreamer(MCStreamer &S) + : MCTargetStreamer(S), canHaveModuleDirective(true) {} +void MipsTargetStreamer::emitDirectiveSetMicroMips() {} +void MipsTargetStreamer::emitDirectiveSetNoMicroMips() {} +void MipsTargetStreamer::emitDirectiveSetMips16() {} +void MipsTargetStreamer::emitDirectiveSetNoMips16() {} +void MipsTargetStreamer::emitDirectiveSetReorder() {} +void MipsTargetStreamer::emitDirectiveSetNoReorder() {} +void MipsTargetStreamer::emitDirectiveSetMacro() {} +void MipsTargetStreamer::emitDirectiveSetNoMacro() {} +void MipsTargetStreamer::emitDirectiveSetAt() {} +void MipsTargetStreamer::emitDirectiveSetNoAt() {} +void MipsTargetStreamer::emitDirectiveEnd(StringRef Name) {} +void MipsTargetStreamer::emitDirectiveEnt(const MCSymbol &Symbol) {} +void MipsTargetStreamer::emitDirectiveAbiCalls() {} +void MipsTargetStreamer::emitDirectiveNaN2008() {} +void MipsTargetStreamer::emitDirectiveNaNLegacy() {} +void MipsTargetStreamer::emitDirectiveOptionPic0() {} +void MipsTargetStreamer::emitDirectiveOptionPic2() {} +void MipsTargetStreamer::emitFrame(unsigned StackReg, unsigned StackSize, + unsigned ReturnReg) {} +void MipsTargetStreamer::emitMask(unsigned CPUBitmask, int CPUTopSavedRegOff) {} +void MipsTargetStreamer::emitFMask(unsigned FPUBitmask, int FPUTopSavedRegOff) { +} +void MipsTargetStreamer::emitDirectiveSetMips32R2() {} +void MipsTargetStreamer::emitDirectiveSetMips64() {} +void MipsTargetStreamer::emitDirectiveSetMips64R2() {} +void MipsTargetStreamer::emitDirectiveSetDsp() {} +void MipsTargetStreamer::emitDirectiveCpload(unsigned RegNo) {} +void MipsTargetStreamer::emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, + const MCSymbol &Sym, bool IsReg) { +} +void MipsTargetStreamer::emitDirectiveModuleOddSPReg(bool Enabled, + bool IsO32ABI) { + if (!Enabled && !IsO32ABI) + report_fatal_error("+nooddspreg is only valid for O32"); +} -// pin vtable to this file -void MipsTargetStreamer::anchor() {} +MipsTargetAsmStreamer::MipsTargetAsmStreamer(MCStreamer &S, + formatted_raw_ostream &OS) + : MipsTargetStreamer(S), OS(OS) {} -MipsTargetAsmStreamer::MipsTargetAsmStreamer(formatted_raw_ostream &OS) - : OS(OS) {} +void MipsTargetAsmStreamer::emitDirectiveSetMicroMips() { + OS << "\t.set\tmicromips\n"; + setCanHaveModuleDir(false); +} -void MipsTargetAsmStreamer::emitMipsHackELFFlags(unsigned Flags) { - if (!PrintHackDirectives) - return; +void MipsTargetAsmStreamer::emitDirectiveSetNoMicroMips() { + OS << "\t.set\tnomicromips\n"; + setCanHaveModuleDir(false); +} - OS << "\t.mips_hack_elf_flags 0x"; - OS.write_hex(Flags); - OS << '\n'; +void MipsTargetAsmStreamer::emitDirectiveSetMips16() { + OS << "\t.set\tmips16\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoMips16() { + OS << "\t.set\tnomips16\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveSetReorder() { + OS << "\t.set\treorder\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoReorder() { + OS << "\t.set\tnoreorder\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMacro() { + OS << "\t.set\tmacro\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoMacro() { + OS << "\t.set\tnomacro\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveSetAt() { + OS << "\t.set\tat\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoAt() { + OS << "\t.set\tnoat\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveEnd(StringRef Name) { + OS << "\t.end\t" << Name << '\n'; +} + +void MipsTargetAsmStreamer::emitDirectiveEnt(const MCSymbol &Symbol) { + OS << "\t.ent\t" << Symbol.getName() << '\n'; +} + +void MipsTargetAsmStreamer::emitDirectiveAbiCalls() { OS << "\t.abicalls\n"; } + +void MipsTargetAsmStreamer::emitDirectiveNaN2008() { OS << "\t.nan\t2008\n"; } + +void MipsTargetAsmStreamer::emitDirectiveNaNLegacy() { + OS << "\t.nan\tlegacy\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveOptionPic0() { + OS << "\t.option\tpic0\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveOptionPic2() { + OS << "\t.option\tpic2\n"; +} + +void MipsTargetAsmStreamer::emitFrame(unsigned StackReg, unsigned StackSize, + unsigned ReturnReg) { + OS << "\t.frame\t$" + << StringRef(MipsInstPrinter::getRegisterName(StackReg)).lower() << "," + << StackSize << ",$" + << StringRef(MipsInstPrinter::getRegisterName(ReturnReg)).lower() << '\n'; +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips32R2() { + OS << "\t.set\tmips32r2\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips64() { + OS << "\t.set\tmips64\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips64R2() { + OS << "\t.set\tmips64r2\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveSetDsp() { + OS << "\t.set\tdsp\n"; + setCanHaveModuleDir(false); +} +// Print a 32 bit hex number with all numbers. +static void printHex32(unsigned Value, raw_ostream &OS) { + OS << "0x"; + for (int i = 7; i >= 0; i--) + OS.write_hex((Value & (0xF << (i * 4))) >> (i * 4)); +} + +void MipsTargetAsmStreamer::emitMask(unsigned CPUBitmask, + int CPUTopSavedRegOff) { + OS << "\t.mask \t"; + printHex32(CPUBitmask, OS); + OS << ',' << CPUTopSavedRegOff << '\n'; } -void MipsTargetAsmStreamer::emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val) { - if (!PrintHackDirectives) - return; - OS << "\t.mips_hack_stocg "; - OS << Sym->getName(); +void MipsTargetAsmStreamer::emitFMask(unsigned FPUBitmask, + int FPUTopSavedRegOff) { + OS << "\t.fmask\t"; + printHex32(FPUBitmask, OS); + OS << "," << FPUTopSavedRegOff << '\n'; +} + +void MipsTargetAsmStreamer::emitDirectiveCpload(unsigned RegNo) { + OS << "\t.cpload\t$" + << StringRef(MipsInstPrinter::getRegisterName(RegNo)).lower() << "\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveCpsetup(unsigned RegNo, + int RegOrOffset, + const MCSymbol &Sym, + bool IsReg) { + OS << "\t.cpsetup\t$" + << StringRef(MipsInstPrinter::getRegisterName(RegNo)).lower() << ", "; + + if (IsReg) + OS << "$" + << StringRef(MipsInstPrinter::getRegisterName(RegOrOffset)).lower(); + else + OS << RegOrOffset; + OS << ", "; - OS << Val; - OS << '\n'; + + OS << Sym.getName() << "\n"; + setCanHaveModuleDir(false); } -MCELFStreamer &MipsTargetELFStreamer::getStreamer() { - return static_cast<MCELFStreamer &>(*Streamer); +void MipsTargetAsmStreamer::emitDirectiveModuleFP( + MipsABIFlagsSection::FpABIKind Value, bool Is32BitABI) { + MipsTargetStreamer::emitDirectiveModuleFP(Value, Is32BitABI); + + StringRef ModuleValue; + OS << "\t.module\tfp="; + OS << ABIFlagsSection.getFpABIString(Value) << "\n"; } -void MipsTargetELFStreamer::emitMipsHackELFFlags(unsigned Flags) { +void MipsTargetAsmStreamer::emitDirectiveSetFp( + MipsABIFlagsSection::FpABIKind Value) { + StringRef ModuleValue; + OS << "\t.set\tfp="; + OS << ABIFlagsSection.getFpABIString(Value) << "\n"; +} + +void MipsTargetAsmStreamer::emitMipsAbiFlags() { + // No action required for text output. +} + +void MipsTargetAsmStreamer::emitDirectiveModuleOddSPReg(bool Enabled, + bool IsO32ABI) { + MipsTargetStreamer::emitDirectiveModuleOddSPReg(Enabled, IsO32ABI); + + OS << "\t.module\t" << (Enabled ? "" : "no") << "oddspreg\n"; +} + +// This part is for ELF object output. +MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S, + const MCSubtargetInfo &STI) + : MipsTargetStreamer(S), MicroMipsEnabled(false), STI(STI) { MCAssembler &MCA = getStreamer().getAssembler(); - MCA.setELFHeaderEFlags(Flags); + uint64_t Features = STI.getFeatureBits(); + Triple T(STI.getTargetTriple()); + Pic = (MCA.getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_) + ? true + : false; + + // Update e_header flags + unsigned EFlags = 0; + + // Architecture + if (Features & Mips::FeatureMips64r6) + EFlags |= ELF::EF_MIPS_ARCH_64R6; + else if (Features & Mips::FeatureMips64r2) + EFlags |= ELF::EF_MIPS_ARCH_64R2; + else if (Features & Mips::FeatureMips64) + EFlags |= ELF::EF_MIPS_ARCH_64; + else if (Features & Mips::FeatureMips5) + EFlags |= ELF::EF_MIPS_ARCH_5; + else if (Features & Mips::FeatureMips4) + EFlags |= ELF::EF_MIPS_ARCH_4; + else if (Features & Mips::FeatureMips3) + EFlags |= ELF::EF_MIPS_ARCH_3; + else if (Features & Mips::FeatureMips32r6) + EFlags |= ELF::EF_MIPS_ARCH_32R6; + else if (Features & Mips::FeatureMips32r2) + EFlags |= ELF::EF_MIPS_ARCH_32R2; + else if (Features & Mips::FeatureMips32) + EFlags |= ELF::EF_MIPS_ARCH_32; + else if (Features & Mips::FeatureMips2) + EFlags |= ELF::EF_MIPS_ARCH_2; + else + EFlags |= ELF::EF_MIPS_ARCH_1; + + // ABI + // N64 does not require any ABI bits. + if (Features & Mips::FeatureO32) + EFlags |= ELF::EF_MIPS_ABI_O32; + else if (Features & Mips::FeatureN32) + EFlags |= ELF::EF_MIPS_ABI2; + + if (Features & Mips::FeatureGP64Bit) { + if (Features & Mips::FeatureO32) + EFlags |= ELF::EF_MIPS_32BITMODE; /* Compatibility Mode */ + } else if (Features & Mips::FeatureMips64r2 || Features & Mips::FeatureMips64) + EFlags |= ELF::EF_MIPS_32BITMODE; + + // Other options. + if (Features & Mips::FeatureNaN2008) + EFlags |= ELF::EF_MIPS_NAN2008; + + // -mabicalls and -mplt are not implemented but we should act as if they were + // given. + EFlags |= ELF::EF_MIPS_CPIC; + if (Features & Mips::FeatureN64) + EFlags |= ELF::EF_MIPS_PIC; + + MCA.setELFHeaderEFlags(EFlags); } -// Set a symbol's STO flags -void MipsTargetELFStreamer::emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val) { - MCSymbolData &Data = getStreamer().getOrCreateSymbolData(Sym); +void MipsTargetELFStreamer::emitLabel(MCSymbol *Symbol) { + if (!isMicroMipsEnabled()) + return; + MCSymbolData &Data = getStreamer().getOrCreateSymbolData(Symbol); + uint8_t Type = MCELF::GetType(Data); + if (Type != ELF::STT_FUNC) + return; + // 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); + MCELF::setOther(Data, ELF::STO_MIPS_MICROMIPS >> 2); +} + +void MipsTargetELFStreamer::finish() { + MCAssembler &MCA = getStreamer().getAssembler(); + const MCObjectFileInfo &OFI = *MCA.getContext().getObjectFileInfo(); + + // .bss, .text and .data are always at least 16-byte aligned. + MCSectionData &TextSectionData = + MCA.getOrCreateSectionData(*OFI.getTextSection()); + MCSectionData &DataSectionData = + MCA.getOrCreateSectionData(*OFI.getDataSection()); + MCSectionData &BSSSectionData = + MCA.getOrCreateSectionData(*OFI.getBSSSection()); + + TextSectionData.setAlignment(std::max(16u, TextSectionData.getAlignment())); + DataSectionData.setAlignment(std::max(16u, DataSectionData.getAlignment())); + BSSSectionData.setAlignment(std::max(16u, BSSSectionData.getAlignment())); + + // Emit all the option records. + // At the moment we are only emitting .Mips.options (ODK_REGINFO) and + // .reginfo. + MipsELFStreamer &MEF = static_cast<MipsELFStreamer &>(Streamer); + MEF.EmitMipsOptionRecords(); + + emitMipsAbiFlags(); +} + +void MipsTargetELFStreamer::emitAssignment(MCSymbol *Symbol, + const MCExpr *Value) { + // If on rhs is micromips symbol then mark Symbol as microMips. + if (Value->getKind() != MCExpr::SymbolRef) + return; + const MCSymbol &RhsSym = + static_cast<const MCSymbolRefExpr *>(Value)->getSymbol(); + MCSymbolData &Data = getStreamer().getOrCreateSymbolData(&RhsSym); + uint8_t Type = MCELF::GetType(Data); + if ((Type != ELF::STT_FUNC) || + !(MCELF::getOther(Data) & (ELF::STO_MIPS_MICROMIPS >> 2))) + return; + + MCSymbolData &SymbolData = getStreamer().getOrCreateSymbolData(Symbol); + // 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(SymbolData, ELF::STO_MIPS_MICROMIPS >> 2); +} + +MCELFStreamer &MipsTargetELFStreamer::getStreamer() { + return static_cast<MCELFStreamer &>(Streamer); +} + +void MipsTargetELFStreamer::emitDirectiveSetMicroMips() { + MicroMipsEnabled = true; + + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags |= ELF::EF_MIPS_MICROMIPS; + MCA.setELFHeaderEFlags(Flags); +} + +void MipsTargetELFStreamer::emitDirectiveSetNoMicroMips() { + MicroMipsEnabled = false; + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveSetMips16() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags |= ELF::EF_MIPS_ARCH_ASE_M16; + MCA.setELFHeaderEFlags(Flags); + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveSetNoMips16() { + // FIXME: implement. + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveSetReorder() { + // FIXME: implement. + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveSetNoReorder() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags |= ELF::EF_MIPS_NOREORDER; + MCA.setELFHeaderEFlags(Flags); + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveSetMacro() { + // FIXME: implement. + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveSetNoMacro() { + // FIXME: implement. + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveSetAt() { + // FIXME: implement. + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveSetNoAt() { + // FIXME: implement. + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveEnd(StringRef Name) { + // FIXME: implement. +} + +void MipsTargetELFStreamer::emitDirectiveEnt(const MCSymbol &Symbol) { + // FIXME: implement. +} + +void MipsTargetELFStreamer::emitDirectiveAbiCalls() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags |= ELF::EF_MIPS_CPIC | ELF::EF_MIPS_PIC; + MCA.setELFHeaderEFlags(Flags); +} + +void MipsTargetELFStreamer::emitDirectiveNaN2008() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags |= ELF::EF_MIPS_NAN2008; + MCA.setELFHeaderEFlags(Flags); +} + +void MipsTargetELFStreamer::emitDirectiveNaNLegacy() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags &= ~ELF::EF_MIPS_NAN2008; + MCA.setELFHeaderEFlags(Flags); +} + +void MipsTargetELFStreamer::emitDirectiveOptionPic0() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + // This option overrides other PIC options like -KPIC. + Pic = false; + Flags &= ~ELF::EF_MIPS_PIC; + MCA.setELFHeaderEFlags(Flags); +} + +void MipsTargetELFStreamer::emitDirectiveOptionPic2() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Pic = true; + // NOTE: We are following the GAS behaviour here which means the directive + // 'pic2' also sets the CPIC bit in the ELF header. This is different from + // what is stated in the SYSV ABI which consider the bits EF_MIPS_PIC and + // EF_MIPS_CPIC to be mutually exclusive. + Flags |= ELF::EF_MIPS_PIC | ELF::EF_MIPS_CPIC; + MCA.setELFHeaderEFlags(Flags); +} + +void MipsTargetELFStreamer::emitFrame(unsigned StackReg, unsigned StackSize, + unsigned ReturnReg) { + // FIXME: implement. +} + +void MipsTargetELFStreamer::emitMask(unsigned CPUBitmask, + int CPUTopSavedRegOff) { + // FIXME: implement. +} + +void MipsTargetELFStreamer::emitFMask(unsigned FPUBitmask, + int FPUTopSavedRegOff) { + // FIXME: implement. +} + +void MipsTargetELFStreamer::emitDirectiveSetMips32R2() { + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveSetMips64() { + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveSetMips64R2() { + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveSetDsp() { + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveCpload(unsigned RegNo) { + // .cpload $reg + // This directive expands to: + // lui $gp, %hi(_gp_disp) + // addui $gp, $gp, %lo(_gp_disp) + // addu $gp, $gp, $reg + // when support for position independent code is enabled. + if (!Pic || (isN32() || isN64())) + return; + + // There's a GNU extension controlled by -mno-shared that allows + // locally-binding symbols to be accessed using absolute addresses. + // This is currently not supported. When supported -mno-shared makes + // .cpload expand to: + // lui $gp, %hi(__gnu_local_gp) + // addiu $gp, $gp, %lo(__gnu_local_gp) + + StringRef SymName("_gp_disp"); + MCAssembler &MCA = getStreamer().getAssembler(); + MCSymbol *GP_Disp = MCA.getContext().GetOrCreateSymbol(SymName); + MCA.getOrCreateSymbolData(*GP_Disp); + + MCInst TmpInst; + TmpInst.setOpcode(Mips::LUi); + TmpInst.addOperand(MCOperand::CreateReg(Mips::GP)); + const MCSymbolRefExpr *HiSym = MCSymbolRefExpr::Create( + "_gp_disp", MCSymbolRefExpr::VK_Mips_ABS_HI, MCA.getContext()); + TmpInst.addOperand(MCOperand::CreateExpr(HiSym)); + getStreamer().EmitInstruction(TmpInst, STI); + + TmpInst.clear(); + + TmpInst.setOpcode(Mips::ADDiu); + TmpInst.addOperand(MCOperand::CreateReg(Mips::GP)); + TmpInst.addOperand(MCOperand::CreateReg(Mips::GP)); + const MCSymbolRefExpr *LoSym = MCSymbolRefExpr::Create( + "_gp_disp", MCSymbolRefExpr::VK_Mips_ABS_LO, MCA.getContext()); + TmpInst.addOperand(MCOperand::CreateExpr(LoSym)); + getStreamer().EmitInstruction(TmpInst, STI); + + TmpInst.clear(); + + TmpInst.setOpcode(Mips::ADDu); + TmpInst.addOperand(MCOperand::CreateReg(Mips::GP)); + TmpInst.addOperand(MCOperand::CreateReg(Mips::GP)); + TmpInst.addOperand(MCOperand::CreateReg(RegNo)); + getStreamer().EmitInstruction(TmpInst, STI); + + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo, + int RegOrOffset, + const MCSymbol &Sym, + bool IsReg) { + // Only N32 and N64 emit anything for .cpsetup iff PIC is set. + if (!Pic || !(isN32() || isN64())) + return; + + MCAssembler &MCA = getStreamer().getAssembler(); + MCInst Inst; + + // Either store the old $gp in a register or on the stack + if (IsReg) { + // move $save, $gpreg + Inst.setOpcode(Mips::DADDu); + Inst.addOperand(MCOperand::CreateReg(RegOrOffset)); + Inst.addOperand(MCOperand::CreateReg(Mips::GP)); + Inst.addOperand(MCOperand::CreateReg(Mips::ZERO)); + } else { + // sd $gpreg, offset($sp) + Inst.setOpcode(Mips::SD); + Inst.addOperand(MCOperand::CreateReg(Mips::GP)); + Inst.addOperand(MCOperand::CreateReg(Mips::SP)); + Inst.addOperand(MCOperand::CreateImm(RegOrOffset)); + } + getStreamer().EmitInstruction(Inst, STI); + Inst.clear(); + + const MCSymbolRefExpr *HiExpr = MCSymbolRefExpr::Create( + Sym.getName(), MCSymbolRefExpr::VK_Mips_GPOFF_HI, MCA.getContext()); + const MCSymbolRefExpr *LoExpr = MCSymbolRefExpr::Create( + Sym.getName(), MCSymbolRefExpr::VK_Mips_GPOFF_LO, MCA.getContext()); + // lui $gp, %hi(%neg(%gp_rel(funcSym))) + Inst.setOpcode(Mips::LUi); + Inst.addOperand(MCOperand::CreateReg(Mips::GP)); + Inst.addOperand(MCOperand::CreateExpr(HiExpr)); + getStreamer().EmitInstruction(Inst, STI); + Inst.clear(); + + // addiu $gp, $gp, %lo(%neg(%gp_rel(funcSym))) + Inst.setOpcode(Mips::ADDiu); + Inst.addOperand(MCOperand::CreateReg(Mips::GP)); + Inst.addOperand(MCOperand::CreateReg(Mips::GP)); + Inst.addOperand(MCOperand::CreateExpr(LoExpr)); + getStreamer().EmitInstruction(Inst, STI); + Inst.clear(); + + // daddu $gp, $gp, $funcreg + Inst.setOpcode(Mips::DADDu); + Inst.addOperand(MCOperand::CreateReg(Mips::GP)); + Inst.addOperand(MCOperand::CreateReg(Mips::GP)); + Inst.addOperand(MCOperand::CreateReg(RegNo)); + getStreamer().EmitInstruction(Inst, STI); + + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitMipsAbiFlags() { + MCAssembler &MCA = getStreamer().getAssembler(); + MCContext &Context = MCA.getContext(); + MCStreamer &OS = getStreamer(); + const MCSectionELF *Sec = + Context.getELFSection(".MIPS.abiflags", ELF::SHT_MIPS_ABIFLAGS, + ELF::SHF_ALLOC, SectionKind::getMetadata(), 24, ""); + MCSectionData &ABIShndxSD = MCA.getOrCreateSectionData(*Sec); + ABIShndxSD.setAlignment(8); + OS.SwitchSection(Sec); + + OS << ABIFlagsSection; +} + +void MipsTargetELFStreamer::emitDirectiveModuleOddSPReg(bool Enabled, + bool IsO32ABI) { + MipsTargetStreamer::emitDirectiveModuleOddSPReg(Enabled, IsO32ABI); + + ABIFlagsSection.OddSPReg = Enabled; } diff --git a/lib/Target/Mips/MSA.txt b/lib/Target/Mips/MSA.txt index d1c41932fcb5..113375fa7f2f 100644 --- a/lib/Target/Mips/MSA.txt +++ b/lib/Target/Mips/MSA.txt @@ -62,11 +62,16 @@ binsri.[bhwd], binsli.[bhwd]: bmnz.v, bmz.v, bsel.v: These three operations differ only in the operand that is tied to the - result. + result and the order of the operands. 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. + These three operations can be very confusing so here is a mapping + between the instructions and the vselect node in one place: + bmz.v wd, ws, wt/i8 -> (vselect wt/i8, wd, ws) + bmnz.v wd, ws, wt/i8 -> (vselect wt/i8, ws, wd) + bsel.v wd, ws, wt/i8 -> (vselect wd, wt/i8, ws) bmnzi.b, bmzi.b: Like their non-immediate counterparts, bmnzi.v and bmzi.v are the same diff --git a/lib/Target/Mips/Makefile b/lib/Target/Mips/Makefile index bcf951e861b0..41efa470e42a 100644 --- a/lib/Target/Mips/Makefile +++ b/lib/Target/Mips/Makefile @@ -13,7 +13,7 @@ TARGET = Mips # Make sure that tblgen is run, first thing. BUILT_SOURCES = MipsGenRegisterInfo.inc MipsGenInstrInfo.inc \ - MipsGenAsmWriter.inc MipsGenCodeEmitter.inc \ + MipsGenAsmWriter.inc MipsGenFastISel.inc MipsGenCodeEmitter.inc \ MipsGenDAGISel.inc MipsGenCallingConv.inc \ MipsGenSubtargetInfo.inc MipsGenMCCodeEmitter.inc \ MipsGenDisassemblerTables.inc \ diff --git a/lib/Target/Mips/MicroMipsInstrFPU.td b/lib/Target/Mips/MicroMipsInstrFPU.td new file mode 100644 index 000000000000..b93017a7400a --- /dev/null +++ b/lib/Target/Mips/MicroMipsInstrFPU.td @@ -0,0 +1,148 @@ +let isCodeGenOnly = 1, Predicates = [InMicroMips] in { +def FADD_S_MM : MMRel, ADDS_FT<"add.s", FGR32Opnd, II_ADD_S, 1, fadd>, + ADDS_FM_MM<0, 0x30>; +def FDIV_S_MM : MMRel, ADDS_FT<"div.s", FGR32Opnd, II_DIV_S, 0, fdiv>, + ADDS_FM_MM<0, 0xf0>; +def FMUL_S_MM : MMRel, ADDS_FT<"mul.s", FGR32Opnd, II_MUL_S, 1, fmul>, + ADDS_FM_MM<0, 0xb0>; +def FSUB_S_MM : MMRel, ADDS_FT<"sub.s", FGR32Opnd, II_SUB_S, 0, fsub>, + ADDS_FM_MM<0, 0x70>; + +def FADD_MM : MMRel, ADDS_FT<"add.d", AFGR64Opnd, II_ADD_D, 1, fadd>, + ADDS_FM_MM<1, 0x30>; +def FDIV_MM : MMRel, ADDS_FT<"div.d", AFGR64Opnd, II_DIV_D, 0, fdiv>, + ADDS_FM_MM<1, 0xf0>; +def FMUL_MM : MMRel, ADDS_FT<"mul.d", AFGR64Opnd, II_MUL_D, 1, fmul>, + ADDS_FM_MM<1, 0xb0>; +def FSUB_MM : MMRel, ADDS_FT<"sub.d", AFGR64Opnd, II_SUB_D, 0, fsub>, + ADDS_FM_MM<1, 0x70>; + +def LWC1_MM : MMRel, LW_FT<"lwc1", FGR32Opnd, II_LWC1, load>, LW_FM_MM<0x27>; +def SWC1_MM : MMRel, SW_FT<"swc1", FGR32Opnd, II_SWC1, store>, + LW_FM_MM<0x26>; +def LDC1_MM : MMRel, LW_FT<"ldc1", AFGR64Opnd, II_LDC1, load>, LW_FM_MM<0x2f>; +def SDC1_MM : MMRel, SW_FT<"sdc1", AFGR64Opnd, II_SDC1, store>, + LW_FM_MM<0x2e>; +def LWXC1_MM : MMRel, LWXC1_FT<"lwxc1", FGR32Opnd, II_LWXC1, load>, + LWXC1_FM_MM<0x48>, INSN_MIPS4_32R2_NOT_32R6_64R6; +def SWXC1_MM : MMRel, SWXC1_FT<"swxc1", FGR32Opnd, II_SWXC1, store>, + SWXC1_FM_MM<0x88>, INSN_MIPS4_32R2_NOT_32R6_64R6; +def LUXC1_MM : MMRel, LWXC1_FT<"luxc1", AFGR64Opnd, II_LUXC1>, + LWXC1_FM_MM<0x148>, INSN_MIPS5_32R2_NOT_32R6_64R6; +def SUXC1_MM : MMRel, SWXC1_FT<"suxc1", AFGR64Opnd, II_SUXC1>, + SWXC1_FM_MM<0x188>, INSN_MIPS5_32R2_NOT_32R6_64R6; + +def FCMP_S32_MM : MMRel, CEQS_FT<"s", FGR32, II_C_CC_S, MipsFPCmp>, + CEQS_FM_MM<0>; +def FCMP_D32_MM : MMRel, CEQS_FT<"d", AFGR64, II_C_CC_D, MipsFPCmp>, + CEQS_FM_MM<1>; + +def BC1F_MM : MMRel, BC1F_FT<"bc1f", brtarget_mm, IIBranch, MIPS_BRANCH_F>, + BC1F_FM_MM<0x1c>, ISA_MIPS1_NOT_32R6_64R6; +def BC1T_MM : MMRel, BC1F_FT<"bc1t", brtarget_mm, IIBranch, MIPS_BRANCH_T>, + BC1F_FM_MM<0x1d>, ISA_MIPS1_NOT_32R6_64R6; + +def CEIL_W_S_MM : MMRel, ABSS_FT<"ceil.w.s", FGR32Opnd, FGR32Opnd, II_CEIL>, + ROUND_W_FM_MM<0, 0x6c>; +def CVT_W_S_MM : MMRel, ABSS_FT<"cvt.w.s", FGR32Opnd, FGR32Opnd, II_CVT>, + ROUND_W_FM_MM<0, 0x24>; +def FLOOR_W_S_MM : MMRel, ABSS_FT<"floor.w.s", FGR32Opnd, FGR32Opnd, II_FLOOR>, + ROUND_W_FM_MM<0, 0x2c>; +def ROUND_W_S_MM : MMRel, ABSS_FT<"round.w.s", FGR32Opnd, FGR32Opnd, II_ROUND>, + ROUND_W_FM_MM<0, 0xec>; +def TRUNC_W_S_MM : MMRel, ABSS_FT<"trunc.w.s", FGR32Opnd, FGR32Opnd, II_TRUNC>, + ROUND_W_FM_MM<0, 0xac>; +def FSQRT_S_MM : MMRel, ABSS_FT<"sqrt.s", FGR32Opnd, FGR32Opnd, II_SQRT_S, + fsqrt>, ROUND_W_FM_MM<0, 0x28>; + +def CEIL_W_MM : MMRel, ABSS_FT<"ceil.w.d", FGR32Opnd, AFGR64Opnd, II_CEIL>, + ROUND_W_FM_MM<1, 0x6c>; +def CVT_W_MM : MMRel, ABSS_FT<"cvt.w.d", FGR32Opnd, AFGR64Opnd, II_CVT>, + ROUND_W_FM_MM<1, 0x24>; +def FLOOR_W_MM : MMRel, ABSS_FT<"floor.w.d", FGR32Opnd, AFGR64Opnd, II_FLOOR>, + ROUND_W_FM_MM<1, 0x2c>; +def ROUND_W_MM : MMRel, ABSS_FT<"round.w.d", FGR32Opnd, AFGR64Opnd, II_ROUND>, + ROUND_W_FM_MM<1, 0xec>; +def TRUNC_W_MM : MMRel, ABSS_FT<"trunc.w.d", FGR32Opnd, AFGR64Opnd, II_TRUNC>, + ROUND_W_FM_MM<1, 0xac>; + +def FSQRT_MM : MMRel, ABSS_FT<"sqrt.d", AFGR64Opnd, AFGR64Opnd, II_SQRT_D, + fsqrt>, ROUND_W_FM_MM<1, 0x28>; + +def CVT_L_S_MM : MMRel, ABSS_FT<"cvt.l.s", FGR64Opnd, FGR32Opnd, II_CVT>, + ROUND_W_FM_MM<0, 0x4>, INSN_MIPS3_32R2; +def CVT_L_D64_MM : MMRel, ABSS_FT<"cvt.l.d", FGR64Opnd, FGR64Opnd, II_CVT>, + ROUND_W_FM_MM<1, 0x4>, INSN_MIPS3_32R2; + +def FABS_S_MM : MMRel, ABSS_FT<"abs.s", FGR32Opnd, FGR32Opnd, II_ABS, fabs>, + ABS_FM_MM<0, 0xd>; +def FMOV_S_MM : MMRel, ABSS_FT<"mov.s", FGR32Opnd, FGR32Opnd, II_MOV_S>, + ABS_FM_MM<0, 0x1>; +def FNEG_S_MM : MMRel, ABSS_FT<"neg.s", FGR32Opnd, FGR32Opnd, II_NEG, fneg>, + ABS_FM_MM<0, 0x2d>; +def CVT_D_S_MM : MMRel, ABSS_FT<"cvt.d.s", AFGR64Opnd, FGR32Opnd, II_CVT>, + ABS_FM_MM<0, 0x4d>; +def CVT_D32_W_MM : MMRel, ABSS_FT<"cvt.d.w", AFGR64Opnd, FGR32Opnd, II_CVT>, + ABS_FM_MM<1, 0x4d>; +def CVT_S_D32_MM : MMRel, ABSS_FT<"cvt.s.d", FGR32Opnd, AFGR64Opnd, II_CVT>, + ABS_FM_MM<0, 0x6d>; +def CVT_S_W_MM : MMRel, ABSS_FT<"cvt.s.w", FGR32Opnd, FGR32Opnd, II_CVT>, + ABS_FM_MM<1, 0x6d>; + +def FABS_MM : MMRel, ABSS_FT<"abs.d", AFGR64Opnd, AFGR64Opnd, II_ABS, fabs>, + ABS_FM_MM<1, 0xd>; +def FNEG_MM : MMRel, ABSS_FT<"neg.d", AFGR64Opnd, AFGR64Opnd, II_NEG, fneg>, + ABS_FM_MM<1, 0x2d>; + +def FMOV_D32_MM : MMRel, ABSS_FT<"mov.d", AFGR64Opnd, AFGR64Opnd, II_MOV_D>, + ABS_FM_MM<1, 0x1>, AdditionalRequires<[NotFP64bit]>; + +def MOVZ_I_S_MM : MMRel, CMov_I_F_FT<"movz.s", GPR32Opnd, FGR32Opnd, + II_MOVZ_S>, CMov_I_F_FM_MM<0x78, 0>; +def MOVN_I_S_MM : MMRel, CMov_I_F_FT<"movn.s", GPR32Opnd, FGR32Opnd, + II_MOVN_S>, CMov_I_F_FM_MM<0x38, 0>; +def MOVZ_I_D32_MM : MMRel, CMov_I_F_FT<"movz.d", GPR32Opnd, AFGR64Opnd, + II_MOVZ_D>, CMov_I_F_FM_MM<0x78, 1>; +def MOVN_I_D32_MM : MMRel, CMov_I_F_FT<"movn.d", GPR32Opnd, AFGR64Opnd, + II_MOVN_D>, CMov_I_F_FM_MM<0x38, 1>; + +def MOVT_S_MM : MMRel, CMov_F_F_FT<"movt.s", FGR32Opnd, II_MOVT_S, + MipsCMovFP_T>, CMov_F_F_FM_MM<0x60, 0>; +def MOVF_S_MM : MMRel, CMov_F_F_FT<"movf.s", FGR32Opnd, II_MOVF_S, + MipsCMovFP_F>, CMov_F_F_FM_MM<0x20, 0>; +def MOVT_D32_MM : MMRel, CMov_F_F_FT<"movt.d", AFGR64Opnd, II_MOVT_D, + MipsCMovFP_T>, CMov_F_F_FM_MM<0x60, 1>; +def MOVF_D32_MM : MMRel, CMov_F_F_FT<"movf.d", AFGR64Opnd, II_MOVF_D, + MipsCMovFP_F>, CMov_F_F_FM_MM<0x20, 1>; + +def CFC1_MM : MMRel, MFC1_FT<"cfc1", GPR32Opnd, CCROpnd, II_CFC1>, + MFC1_FM_MM<0x40>; +def CTC1_MM : MMRel, MTC1_FT<"ctc1", CCROpnd, GPR32Opnd, II_CTC1>, + MFC1_FM_MM<0x60>; +def MFC1_MM : MMRel, MFC1_FT<"mfc1", GPR32Opnd, FGR32Opnd, + II_MFC1, bitconvert>, MFC1_FM_MM<0x80>; +def MTC1_MM : MMRel, MTC1_FT<"mtc1", FGR32Opnd, GPR32Opnd, + II_MTC1, bitconvert>, MFC1_FM_MM<0xa0>; +def MFHC1_MM : MMRel, MFC1_FT<"mfhc1", GPR32Opnd, FGRH32Opnd, II_MFHC1>, + MFC1_FM_MM<3>, ISA_MIPS32R2; +def MTHC1_MM : MMRel, MTC1_FT<"mthc1", FGRH32Opnd, GPR32Opnd, II_MTHC1>, + MFC1_FM_MM<7>, ISA_MIPS32R2; + +def MADD_S_MM : MMRel, MADDS_FT<"madd.s", FGR32Opnd, II_MADD_S, fadd>, + MADDS_FM_MM<0x1>; +def MSUB_S_MM : MMRel, MADDS_FT<"msub.s", FGR32Opnd, II_MSUB_S, fsub>, + MADDS_FM_MM<0x21>; +def NMADD_S_MM : MMRel, NMADDS_FT<"nmadd.s", FGR32Opnd, II_NMADD_S, fadd>, + MADDS_FM_MM<0x2>; +def NMSUB_S_MM : MMRel, NMADDS_FT<"nmsub.s", FGR32Opnd, II_NMSUB_S, fsub>, + MADDS_FM_MM<0x22>; + +def MADD_D32_MM : MMRel, MADDS_FT<"madd.d", AFGR64Opnd, II_MADD_D, fadd>, + MADDS_FM_MM<0x9>; +def MSUB_D32_MM : MMRel, MADDS_FT<"msub.d", AFGR64Opnd, II_MSUB_D, fsub>, + MADDS_FM_MM<0x29>; +def NMADD_D32_MM : MMRel, NMADDS_FT<"nmadd.d", AFGR64Opnd, II_NMADD_D, fadd>, + MADDS_FM_MM<0xa>; +def NMSUB_D32_MM : MMRel, NMADDS_FT<"nmsub.d", AFGR64Opnd, II_NMSUB_D, fsub>, + MADDS_FM_MM<0x2a>; +} diff --git a/lib/Target/Mips/MicroMipsInstrFormats.td b/lib/Target/Mips/MicroMipsInstrFormats.td index c12a32e3d803..15b951d98c52 100644 --- a/lib/Target/Mips/MicroMipsInstrFormats.td +++ b/lib/Target/Mips/MicroMipsInstrFormats.td @@ -1,3 +1,81 @@ +//===----------------------------------------------------------------------===// +// MicroMIPS Base Classes +//===----------------------------------------------------------------------===// + +// +// Base class for MicroMips instructions. +// This class does not depend on the instruction size. +// +class MicroMipsInstBase<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin, Format f> : Instruction +{ + let Namespace = "Mips"; + let DecoderNamespace = "MicroMips"; + + let OutOperandList = outs; + let InOperandList = ins; + + let AsmString = asmstr; + let Pattern = pattern; + let Itinerary = itin; + + let Predicates = [InMicroMips]; + + Format Form = f; +} + +// +// Base class for MicroMIPS 16-bit instructions. +// +class MicroMipsInst16<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin, Format f> : + MicroMipsInstBase<outs, ins, asmstr, pattern, itin, f> +{ + let Size = 2; + field bits<16> Inst; + field bits<16> SoftFail = 0; + bits<6> Opcode = 0x0; +} + +//===----------------------------------------------------------------------===// +// MicroMIPS 16-bit Instruction Formats +//===----------------------------------------------------------------------===// + +class MOVE_FM_MM16<bits<6> funct> { + bits<5> rs; + bits<5> rd; + + bits<16> Inst; + + let Inst{15-10} = funct; + let Inst{9-5} = rd; + let Inst{4-0} = rs; +} + +class JALR_FM_MM16<bits<5> op> { + bits<5> rs; + + bits<16> Inst; + + let Inst{15-10} = 0x11; + let Inst{9-5} = op; + let Inst{4-0} = rs; +} + +class MFHILO_FM_MM16<bits<5> funct> { + bits<5> rd; + + bits<16> Inst; + + let Inst{15-10} = 0x11; + let Inst{9-5} = funct; + let Inst{4-0} = rd; +} + +//===----------------------------------------------------------------------===// +// MicroMIPS 32-bit Instruction Formats +//===----------------------------------------------------------------------===// + class MMArch { string Arch = "micromips"; list<dag> Pattern = []; @@ -226,7 +304,7 @@ class JR_FM_MM<bits<8> funct> : MMArch { let Inst{5-0} = 0x3c; } -class JALR_FM_MM<bits<10> funct> : MMArch { +class JALR_FM_MM<bits<10> funct> { bits<5> rs; bits<5> rd; @@ -276,6 +354,67 @@ class BGEZAL_FM_MM<bits<5> funct> : MMArch { let Inst{15-0} = offset; } +class SYNC_FM_MM : MMArch { + bits<5> stype; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = 0x0; + let Inst{20-16} = stype; + let Inst{15-6} = 0x1ad; + let Inst{5-0} = 0x3c; +} + +class BRK_FM_MM : MMArch { + 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} = 0x07; +} + +class SYS_FM_MM : MMArch { + bits<10> code_; + bits<32> Inst; + let Inst{31-26} = 0x0; + let Inst{25-16} = code_; + let Inst{15-6} = 0x22d; + let Inst{5-0} = 0x3c; +} + +class WAIT_FM_MM { + bits<10> code_; + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-16} = code_; + let Inst{15-6} = 0x24d; + let Inst{5-0} = 0x3c; +} + +class ER_FM_MM<bits<10> funct> : MMArch { + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-16} = 0x00; + let Inst{15-6} = funct; + let Inst{5-0} = 0x3c; +} + +class EI_FM_MM<bits<10> funct> : MMArch { + bits<32> Inst; + bits<5> rt; + + let Inst{31-26} = 0x00; + let Inst{25-21} = 0x00; + let Inst{20-16} = rt; + let Inst{15-6} = funct; + let Inst{5-0} = 0x3c; +} + class TEQ_FM_MM<bits<6> funct> : MMArch { bits<5> rs; bits<5> rt; @@ -302,3 +441,183 @@ class TEQI_FM_MM<bits<5> funct> : MMArch { let Inst{20-16} = rs; let Inst{15-0} = imm16; } + +class LL_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 ADDS_FM_MM<bits<2> fmt, bits<8> funct> : MMArch { + bits<5> ft; + bits<5> fs; + bits<5> fd; + + bits<32> Inst; + + let Inst{31-26} = 0x15; + let Inst{25-21} = ft; + let Inst{20-16} = fs; + let Inst{15-11} = fd; + let Inst{10} = 0; + let Inst{9-8} = fmt; + let Inst{7-0} = funct; + + list<dag> Pattern = []; +} + +class LWXC1_FM_MM<bits<9> funct> : MMArch { + bits<5> fd; + bits<5> base; + bits<5> index; + + bits<32> Inst; + + let Inst{31-26} = 0x15; + let Inst{25-21} = index; + let Inst{20-16} = base; + let Inst{15-11} = fd; + let Inst{10-9} = 0x0; + let Inst{8-0} = funct; +} + +class SWXC1_FM_MM<bits<9> funct> : MMArch { + bits<5> fs; + bits<5> base; + bits<5> index; + + bits<32> Inst; + + let Inst{31-26} = 0x15; + let Inst{25-21} = index; + let Inst{20-16} = base; + let Inst{15-11} = fs; + let Inst{10-9} = 0x0; + let Inst{8-0} = funct; +} + +class CEQS_FM_MM<bits<2> fmt> : MMArch { + bits<5> fs; + bits<5> ft; + bits<4> cond; + + bits<32> Inst; + + let Inst{31-26} = 0x15; + let Inst{25-21} = ft; + let Inst{20-16} = fs; + let Inst{15-13} = 0x0; // cc + let Inst{12} = 0; + let Inst{11-10} = fmt; + let Inst{9-6} = cond; + let Inst{5-0} = 0x3c; +} + +class BC1F_FM_MM<bits<5> tf> : MMArch { + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = 0x10; + let Inst{25-21} = tf; + let Inst{20-18} = 0x0; // cc + let Inst{17-16} = 0x0; + let Inst{15-0} = offset; +} + +class ROUND_W_FM_MM<bits<1> fmt, bits<8> funct> : MMArch { + bits<5> fd; + bits<5> fs; + + bits<32> Inst; + + let Inst{31-26} = 0x15; + let Inst{25-21} = fd; + let Inst{20-16} = fs; + let Inst{15} = 0; + let Inst{14} = fmt; + let Inst{13-6} = funct; + let Inst{5-0} = 0x3b; +} + +class ABS_FM_MM<bits<2> fmt, bits<7> funct> : MMArch { + bits<5> fd; + bits<5> fs; + + bits<32> Inst; + + let Inst{31-26} = 0x15; + let Inst{25-21} = fd; + let Inst{20-16} = fs; + let Inst{15} = 0; + let Inst{14-13} = fmt; + let Inst{12-6} = funct; + let Inst{5-0} = 0x3b; +} + +class CMov_F_F_FM_MM<bits<9> func, bits<2> fmt> : MMArch { + bits<5> fd; + bits<5> fs; + + bits<32> Inst; + + let Inst{31-26} = 0x15; + let Inst{25-21} = fd; + let Inst{20-16} = fs; + let Inst{15-13} = 0x0; //cc + let Inst{12-11} = 0x0; + let Inst{10-9} = fmt; + let Inst{8-0} = func; +} + +class CMov_I_F_FM_MM<bits<8> funct, bits<2> fmt> : MMArch { + bits<5> fd; + bits<5> fs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0x15; + let Inst{25-21} = rt; + let Inst{20-16} = fs; + let Inst{15-11} = fd; + let Inst{9-8} = fmt; + let Inst{7-0} = funct; +} + +class MFC1_FM_MM<bits<8> funct> : MMArch { + bits<5> rt; + bits<5> fs; + + bits<32> Inst; + + let Inst{31-26} = 0x15; + let Inst{25-21} = rt; + let Inst{20-16} = fs; + let Inst{15-14} = 0x0; + let Inst{13-6} = funct; + let Inst{5-0} = 0x3b; +} + +class MADDS_FM_MM<bits<6> funct>: MMArch { + bits<5> ft; + bits<5> fs; + bits<5> fd; + bits<5> fr; + + bits<32> Inst; + + let Inst{31-26} = 0x15; + let Inst{25-21} = ft; + let Inst{20-16} = fs; + let Inst{15-11} = fd; + let Inst{10-6} = fr; + let Inst{5-0} = funct; +} diff --git a/lib/Target/Mips/MicroMipsInstrInfo.td b/lib/Target/Mips/MicroMipsInstrInfo.td index d9507fa88ebc..87a3a3e29ca2 100644 --- a/lib/Target/Mips/MicroMipsInstrInfo.td +++ b/lib/Target/Mips/MicroMipsInstrInfo.td @@ -45,6 +45,64 @@ class StoreLeftRightMM<string opstr, SDNode OpNode, RegisterOperand RO, let DecoderMethod = "DecodeMemMMImm12"; } +class LLBaseMM<string opstr, RegisterOperand RO> : + InstSE<(outs RO:$rt), (ins mem_mm_12:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], NoItinerary, FrmI> { + let DecoderMethod = "DecodeMemMMImm12"; + let mayLoad = 1; +} + +class SCBaseMM<string opstr, RegisterOperand RO> : + InstSE<(outs RO:$dst), (ins RO:$rt, mem_mm_12:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], NoItinerary, FrmI> { + let DecoderMethod = "DecodeMemMMImm12"; + let mayStore = 1; + let Constraints = "$rt = $dst"; +} + +class LoadMM<string opstr, DAGOperand RO, SDPatternOperator OpNode = null_frag, + InstrItinClass Itin = NoItinerary> : + InstSE<(outs RO:$rt), (ins mem_mm_12:$addr), + !strconcat(opstr, "\t$rt, $addr"), + [(set RO:$rt, (OpNode addrimm12:$addr))], Itin, FrmI> { + let DecoderMethod = "DecodeMemMMImm12"; + let canFoldAsLoad = 1; + let mayLoad = 1; +} + +class MoveFromHILOMM<string opstr, RegisterOperand RO, Register UseReg> : + MicroMipsInst16<(outs RO:$rd), (ins), !strconcat(opstr, "\t$rd"), + [], II_MFHI_MFLO, FrmR> { + let Uses = [UseReg]; + let hasSideEffects = 0; +} + +class MoveMM16<string opstr, RegisterOperand RO, bit isComm = 0, + InstrItinClass Itin = NoItinerary> : + MicroMipsInst16<(outs RO:$rd), (ins RO:$rs), + !strconcat(opstr, "\t$rd, $rs"), [], Itin, FrmR> { + let isCommutable = isComm; + let isReMaterializable = 1; +} + +// 16-bit Jump and Link (Call) +class JumpLinkRegMM16<string opstr, RegisterOperand RO> : + MicroMipsInst16<(outs), (ins RO:$rs), !strconcat(opstr, "\t$rs"), + [(MipsJmpLink RO:$rs)], IIBranch, FrmR> { + let isCall = 1; + let hasDelaySlot = 1; + let Defs = [RA]; +} + +def MFHI16_MM : MoveFromHILOMM<"mfhi", GPR32Opnd, AC0>, MFHILO_FM_MM16<0x10>; +def MFLO16_MM : MoveFromHILOMM<"mflo", GPR32Opnd, AC0>, MFHILO_FM_MM16<0x12>; +def MOVE16_MM : MoveMM16<"move", GPR32Opnd>, MOVE_FM_MM16<0x03>; +def JALR16_MM : JumpLinkRegMM16<"jalr", GPR32Opnd>, JALR_FM_MM16<0x0e>; + +class WaitMM<string opstr> : + InstSE<(outs), (ins uimm10:$code_), !strconcat(opstr, "\t$code_"), [], + NoItinerary, FrmOther, opstr>; + let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in { /// Arithmetic Instructions (ALU Immediate) def ADDiu_MM : MMRel, ArithLogicI<"addiu", simm16, GPR32Opnd>, @@ -63,6 +121,9 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in { ADDI_FM_MM<0x1c>; def LUi_MM : MMRel, LoadUpper<"lui", GPR32Opnd, uimm16>, LUI_FM_MM; + def LEA_ADDiu_MM : MMRel, EffectiveAddress<"addiu", GPR32Opnd>, + LW_FM_MM<0xc>; + /// 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>; @@ -72,38 +133,38 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in { 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>, + def AND_MM : MMRel, ArithLogicR<"and", GPR32Opnd, 1, II_AND, and>, ADD_FM_MM<0, 0x250>; - def OR_MM : MMRel, ArithLogicR<"or", GPR32Opnd, 1, IIAlu, or>, + def OR_MM : MMRel, ArithLogicR<"or", GPR32Opnd, 1, II_OR, or>, ADD_FM_MM<0, 0x290>; - def XOR_MM : MMRel, ArithLogicR<"xor", GPR32Opnd, 1, IIAlu, xor>, + def XOR_MM : MMRel, ArithLogicR<"xor", GPR32Opnd, 1, II_XOR, 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]>, + def MULT_MM : MMRel, Mult<"mult", II_MULT, GPR32Opnd, [HI0, LO0]>, MULT_FM_MM<0x22c>; - def MULTu_MM : MMRel, Mult<"multu", IIImul, GPR32Opnd, [HI0, LO0]>, + def MULTu_MM : MMRel, Mult<"multu", II_MULTU, GPR32Opnd, [HI0, LO0]>, MULT_FM_MM<0x26c>; - def SDIV_MM : MMRel, Div<"div", IIIdiv, GPR32Opnd, [HI0, LO0]>, + def SDIV_MM : MMRel, Div<"div", II_DIV, GPR32Opnd, [HI0, LO0]>, MULT_FM_MM<0x2ac>; - def UDIV_MM : MMRel, Div<"divu", IIIdiv, GPR32Opnd, [HI0, LO0]>, + def UDIV_MM : MMRel, Div<"divu", II_DIVU, GPR32Opnd, [HI0, LO0]>, MULT_FM_MM<0x2ec>; /// Shift Instructions - def SLL_MM : MMRel, shift_rotate_imm<"sll", uimm5, GPR32Opnd>, + def SLL_MM : MMRel, shift_rotate_imm<"sll", uimm5, GPR32Opnd, II_SLL>, SRA_FM_MM<0, 0>; - def SRL_MM : MMRel, shift_rotate_imm<"srl", uimm5, GPR32Opnd>, + def SRL_MM : MMRel, shift_rotate_imm<"srl", uimm5, GPR32Opnd, II_SRL>, SRA_FM_MM<0x40, 0>; - def SRA_MM : MMRel, shift_rotate_imm<"sra", uimm5, GPR32Opnd>, + def SRA_MM : MMRel, shift_rotate_imm<"sra", uimm5, GPR32Opnd, II_SRA>, SRA_FM_MM<0x80, 0>; - def SLLV_MM : MMRel, shift_rotate_reg<"sllv", GPR32Opnd>, + def SLLV_MM : MMRel, shift_rotate_reg<"sllv", GPR32Opnd, II_SLLV>, SRLV_FM_MM<0x10, 0>; - def SRLV_MM : MMRel, shift_rotate_reg<"srlv", GPR32Opnd>, + def SRLV_MM : MMRel, shift_rotate_reg<"srlv", GPR32Opnd, II_SRLV>, SRLV_FM_MM<0x50, 0>; - def SRAV_MM : MMRel, shift_rotate_reg<"srav", GPR32Opnd>, + def SRAV_MM : MMRel, shift_rotate_reg<"srav", GPR32Opnd, II_SRAV>, SRLV_FM_MM<0x90, 0>; - def ROTR_MM : MMRel, shift_rotate_imm<"rotr", uimm5, GPR32Opnd>, + def ROTR_MM : MMRel, shift_rotate_imm<"rotr", uimm5, GPR32Opnd, II_ROTR>, SRA_FM_MM<0xc0, 0>; - def ROTRV_MM : MMRel, shift_rotate_reg<"rotrv", GPR32Opnd>, + def ROTRV_MM : MMRel, shift_rotate_reg<"rotrv", GPR32Opnd, II_ROTRV>, SRLV_FM_MM<0xd0, 0>; /// Load and Store Instructions - aligned @@ -118,6 +179,8 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in { def SW_MM : Store<"sw", GPR32Opnd>, MMRel, LW_FM_MM<0x3e>; } + def LWU_MM : LoadMM<"lwu", GPR32Opnd, zextloadi32, II_LWU>, LL_FM_MM<0xe>; + /// Load and Store Instructions - unaligned def LWL_MM : LoadLeftRightMM<"lwl", MipsLWL, GPR32Opnd, mem_mm_12>, LWL_FM_MM<0x0>; @@ -133,9 +196,9 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in { 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>, + def MOVT_I_MM : MMRel, CMov_F_I_FT<"movt", GPR32Opnd, II_MOVT>, CMov_F_I_FM_MM<0x25>; - def MOVF_I_MM : MMRel, CMov_F_I_FT<"movf", GPR32Opnd, IIAlu>, + def MOVF_I_MM : MMRel, CMov_F_I_FT<"movf", GPR32Opnd, II_MOVF>, CMov_F_I_FM_MM<0x5>; /// Move to/from HI/LO @@ -149,21 +212,26 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in { 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>; + def MADD_MM : MMRel, MArithR<"madd", II_MADD, 1>, MULT_FM_MM<0x32c>; + def MADDU_MM : MMRel, MArithR<"maddu", II_MADDU, 1>, MULT_FM_MM<0x36c>; + def MSUB_MM : MMRel, MArithR<"msub", II_MSUB>, MULT_FM_MM<0x3ac>; + def MSUBU_MM : MMRel, MArithR<"msubu", II_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>; + def CLZ_MM : MMRel, CountLeading0<"clz", GPR32Opnd>, CLO_FM_MM<0x16c>, + ISA_MIPS32; + def CLO_MM : MMRel, CountLeading1<"clo", GPR32Opnd>, CLO_FM_MM<0x12c>, + ISA_MIPS32; /// 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>; + def SEB_MM : MMRel, SignExtInReg<"seb", i8, GPR32Opnd, II_SEB>, + SEB_FM_MM<0x0ac>, ISA_MIPS32R2; + def SEH_MM : MMRel, SignExtInReg<"seh", i16, GPR32Opnd, II_SEH>, + SEB_FM_MM<0x0ec>, ISA_MIPS32R2; /// Word Swap Bytes Within Halfwords - def WSBH_MM : MMRel, SubwordSwap<"wsbh", GPR32Opnd>, SEB_FM_MM<0x1ec>; + def WSBH_MM : MMRel, SubwordSwap<"wsbh", GPR32Opnd>, SEB_FM_MM<0x1ec>, + ISA_MIPS32R2; def EXT_MM : MMRel, ExtBase<"ext", GPR32Opnd, uimm5, MipsExt>, EXT_FM_MM<0x2c>; @@ -175,14 +243,9 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] 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>; + def JALR_MM : JumpLinkReg<"jalr", GPR32Opnd>, JALR_FM_MM<0x03c>; /// Branch Instructions def BEQ_MM : MMRel, CBranch<"beq", brtarget_mm, seteq, GPR32Opnd>, @@ -202,6 +265,18 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in { def BLTZAL_MM : MMRel, BGEZAL_FT<"bltzal", brtarget_mm, GPR32Opnd>, BGEZAL_FM_MM<0x01>; + /// Control Instructions + def SYNC_MM : MMRel, SYNC_FT<"sync">, SYNC_FM_MM; + def BREAK_MM : MMRel, BRK_FT<"break">, BRK_FM_MM; + def SYSCALL_MM : MMRel, SYS_FT<"syscall">, SYS_FM_MM; + def WAIT_MM : WaitMM<"wait">, WAIT_FM_MM; + def ERET_MM : MMRel, ER_FT<"eret">, ER_FM_MM<0x3cd>; + def DERET_MM : MMRel, ER_FT<"deret">, ER_FM_MM<0x38d>; + def EI_MM : MMRel, DEI_FT<"ei", GPR32Opnd>, EI_FM_MM<0x15d>, + ISA_MIPS32R2; + def DI_MM : MMRel, DEI_FT<"di", GPR32Opnd>, EI_FM_MM<0x11d>, + ISA_MIPS32R2; + /// 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>; @@ -216,4 +291,16 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in { 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>; + + /// Load-linked, Store-conditional + def LL_MM : LLBaseMM<"ll", GPR32Opnd>, LL_FM_MM<0x3>; + def SC_MM : SCBaseMM<"sc", GPR32Opnd>, LL_FM_MM<0xb>; +} + +//===----------------------------------------------------------------------===// +// MicroMips instruction aliases +//===----------------------------------------------------------------------===// + +let Predicates = [InMicroMips] in { + def : MipsInstAlias<"wait", (WAIT_MM 0x0), 1>; } diff --git a/lib/Target/Mips/Mips.h b/lib/Target/Mips/Mips.h index e796debd79b6..d512d6589c40 100644 --- a/lib/Target/Mips/Mips.h +++ b/lib/Target/Mips/Mips.h @@ -23,6 +23,7 @@ namespace llvm { class FunctionPass; FunctionPass *createMipsISelDag(MipsTargetMachine &TM); + FunctionPass *createMipsOptimizePICCallPass(MipsTargetMachine &TM); FunctionPass *createMipsDelaySlotFillerPass(MipsTargetMachine &TM); FunctionPass *createMipsLongBranchPass(MipsTargetMachine &TM); FunctionPass *createMipsJITCodeEmitterPass(MipsTargetMachine &TM, diff --git a/lib/Target/Mips/Mips.td b/lib/Target/Mips/Mips.td index b8e3f39256da..dd3bc9b08fc8 100644 --- a/lib/Target/Mips/Mips.td +++ b/lib/Target/Mips/Mips.td @@ -15,6 +15,33 @@ include "llvm/Target/Target.td" +// The overall idea of the PredicateControl class is to chop the Predicates list +// into subsets that are usually overridden independently. This allows +// subclasses to partially override the predicates of their superclasses without +// having to re-add all the existing predicates. +class PredicateControl { + // Predicates for the encoding scheme in use such as HasStdEnc + list<Predicate> EncodingPredicates = []; + // Predicates for the GPR size such as IsGP64bit + list<Predicate> GPRPredicates = []; + // Predicates for the FGR size and layout such as IsFP64bit + list<Predicate> FGRPredicates = []; + // Predicates for the instruction group membership such as ISA's and ASE's + list<Predicate> InsnPredicates = []; + // Predicates for anything else + list<Predicate> AdditionalPredicates = []; + list<Predicate> Predicates = !listconcat(EncodingPredicates, + GPRPredicates, + FGRPredicates, + InsnPredicates, + AdditionalPredicates); +} + +// Like Requires<> but for the AdditionalPredicates list +class AdditionalRequires<list<Predicate> preds> { + list<Predicate> AdditionalPredicates = preds; +} + //===----------------------------------------------------------------------===// // Register File, Calling Conv, Instruction Descriptions //===----------------------------------------------------------------------===// @@ -34,6 +61,10 @@ 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 FeatureFPXX : SubtargetFeature<"fpxx", "IsFPXX", "true", + "Support for FPXX.">; +def FeatureNaN2008 : SubtargetFeature<"nan2008", "IsNaN2008bit", "true", + "IEEE 754-2008 NaN encoding.">; def FeatureSingleFloat : SubtargetFeature<"single-float", "IsSingleFloat", "true", "Only supports single precision float">; def FeatureO32 : SubtargetFeature<"o32", "MipsABI", "O32", @@ -44,32 +75,67 @@ def FeatureN64 : SubtargetFeature<"n64", "MipsABI", "N64", "Enable n64 ABI">; def FeatureEABI : SubtargetFeature<"eabi", "MipsABI", "EABI", "Enable eabi ABI">; +def FeatureNoOddSPReg : SubtargetFeature<"nooddspreg", "UseOddSPReg", "false", + "Disable odd numbered single-precision " + "registers">; 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 FeatureMips1 : SubtargetFeature<"mips1", "MipsArchVersion", "Mips1", + "Mips I ISA Support [highly experimental]">; +def FeatureMips2 : SubtargetFeature<"mips2", "MipsArchVersion", "Mips2", + "Mips II ISA Support [highly experimental]", + [FeatureMips1]>; +def FeatureMips3_32 : SubtargetFeature<"mips3_32", "HasMips3_32", "true", + "Subset of MIPS-III that is also in MIPS32 " + "[highly experimental]">; +def FeatureMips3_32r2 : SubtargetFeature<"mips3_32r2", "HasMips3_32r2", "true", + "Subset of MIPS-III that is also in MIPS32r2 " + "[highly experimental]">; +def FeatureMips3 : SubtargetFeature<"mips3", "MipsArchVersion", "Mips3", + "MIPS III ISA Support [highly experimental]", + [FeatureMips2, FeatureMips3_32, + FeatureMips3_32r2, FeatureGP64Bit, + FeatureFP64Bit]>; +def FeatureMips4_32 : SubtargetFeature<"mips4_32", "HasMips4_32", "true", + "Subset of MIPS-IV that is also in MIPS32 " + "[highly experimental]">; +def FeatureMips4_32r2 : SubtargetFeature<"mips4_32r2", "HasMips4_32r2", "true", + "Subset of MIPS-IV that is also in MIPS32r2 " + "[highly experimental]">; +def FeatureMips4 : SubtargetFeature<"mips4", "MipsArchVersion", + "Mips4", "MIPS IV ISA Support", + [FeatureMips3, FeatureMips4_32, + FeatureMips4_32r2]>; +def FeatureMips5_32r2 : SubtargetFeature<"mips5_32r2", "HasMips5_32r2", "true", + "Subset of MIPS-V that is also in MIPS32r2 " + "[highly experimental]">; +def FeatureMips5 : SubtargetFeature<"mips5", "MipsArchVersion", "Mips5", + "MIPS V ISA Support [highly experimental]", + [FeatureMips4, FeatureMips5_32r2]>; def FeatureMips32 : SubtargetFeature<"mips32", "MipsArchVersion", "Mips32", "Mips32 ISA Support", - [FeatureCondMov, FeatureBitCount]>; + [FeatureMips2, FeatureMips3_32, + FeatureMips4_32]>; def FeatureMips32r2 : SubtargetFeature<"mips32r2", "MipsArchVersion", "Mips32r2", "Mips32r2 ISA Support", - [FeatureMips32, FeatureSEInReg, FeatureSwap, - FeatureFPIdx]>; + [FeatureMips3_32r2, FeatureMips4_32r2, + FeatureMips5_32r2, FeatureMips32]>; +def FeatureMips32r6 : SubtargetFeature<"mips32r6", "MipsArchVersion", + "Mips32r6", + "Mips32r6 ISA Support [experimental]", + [FeatureMips32r2, FeatureFP64Bit, + FeatureNaN2008]>; def FeatureMips64 : SubtargetFeature<"mips64", "MipsArchVersion", "Mips64", "Mips64 ISA Support", - [FeatureGP64Bit, FeatureFP64Bit, - FeatureMips32, FeatureFPIdx]>; + [FeatureMips5, FeatureMips32]>; def FeatureMips64r2 : SubtargetFeature<"mips64r2", "MipsArchVersion", "Mips64r2", "Mips64r2 ISA Support", [FeatureMips64, FeatureMips32r2]>; +def FeatureMips64r6 : SubtargetFeature<"mips64r6", "MipsArchVersion", + "Mips64r6", + "Mips64r6 ISA Support [experimental]", + [FeatureMips32r6, FeatureMips64r2, + FeatureNaN2008]>; def FeatureMips16 : SubtargetFeature<"mips16", "InMips16Mode", "true", "Mips16 mode">; @@ -83,6 +149,10 @@ def FeatureMSA : SubtargetFeature<"msa", "HasMSA", "true", "Mips MSA ASE">; def FeatureMicroMips : SubtargetFeature<"micromips", "InMicroMipsMode", "true", "microMips mode">; +def FeatureCnMips : SubtargetFeature<"cnmips", "HasCnMips", + "true", "Octeon cnMIPS Support", + [FeatureMips64r2]>; + //===----------------------------------------------------------------------===// // Mips processors supported. //===----------------------------------------------------------------------===// @@ -90,16 +160,20 @@ def FeatureMicroMips : SubtargetFeature<"micromips", "InMicroMipsMode", "true", 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 : Proc<"mips1", [FeatureMips1, FeatureO32]>; +def : Proc<"mips2", [FeatureMips2, FeatureO32]>; +def : Proc<"mips32", [FeatureMips32, FeatureO32]>; +def : Proc<"mips32r2", [FeatureMips32r2, FeatureO32]>; +def : Proc<"mips32r6", [FeatureMips32r6, FeatureO32]>; -def MipsAsmWriter : AsmWriter { - string AsmWriterClassName = "InstPrinter"; - bit isMCAsmWriter = 1; -} +def : Proc<"mips3", [FeatureMips3, FeatureN64]>; +def : Proc<"mips4", [FeatureMips4, FeatureN64]>; +def : Proc<"mips5", [FeatureMips5, FeatureN64]>; +def : Proc<"mips64", [FeatureMips64, FeatureN64]>; +def : Proc<"mips64r2", [FeatureMips64r2, FeatureN64]>; +def : Proc<"mips64r6", [FeatureMips64r6, FeatureN64]>; +def : Proc<"mips16", [FeatureMips16, FeatureO32]>; +def : Proc<"octeon", [FeatureMips64r2, FeatureN64, FeatureCnMips]>; def MipsAsmParser : AsmParser { let ShouldEmitMatchRegisterName = 0; @@ -116,6 +190,5 @@ def MipsAsmParserVariant : AsmParserVariant { def Mips : Target { let InstructionSet = MipsInstrInfo; let AssemblyParsers = [MipsAsmParser]; - let AssemblyWriters = [MipsAsmWriter]; let AssemblyParserVariants = [MipsAsmParserVariant]; } diff --git a/lib/Target/Mips/Mips16FrameLowering.cpp b/lib/Target/Mips/Mips16FrameLowering.cpp index 6655ff98e033..93706c2c3fcc 100644 --- a/lib/Target/Mips/Mips16FrameLowering.cpp +++ b/lib/Target/Mips/Mips16FrameLowering.cpp @@ -15,6 +15,8 @@ #include "MCTargetDesc/MipsBaseInfo.h" #include "Mips16InstrInfo.h" #include "MipsInstrInfo.h" +#include "MipsRegisterInfo.h" +#include "MipsSubtarget.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" @@ -27,6 +29,9 @@ using namespace llvm; +Mips16FrameLowering::Mips16FrameLowering(const MipsSubtarget &STI) + : MipsFrameLowering(STI, STI.stackAlignment()) {} + void Mips16FrameLowering::emitPrologue(MachineFunction &MF) const { MachineBasicBlock &MBB = MF.front(); MachineFrameInfo *MFI = MF.getFrameInfo(); @@ -47,30 +52,30 @@ void Mips16FrameLowering::emitPrologue(MachineFunction &MF) const { 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 CFIIndex = MMI.addFrameInst( + MCCFIInstruction::createDefCfaOffset(nullptr, -StackSize)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); - unsigned S1 = MRI->getDwarfRegNum(Mips::S1, true); - MMI.addFrameInst(MCCFIInstruction::createOffset(CSLabel, S1, -12)); + const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); - 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 (CSI.size()) { + const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); + 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(); + unsigned DReg = MRI->getDwarfRegNum(Reg, true); + unsigned CFIIndex = MMI.addFrameInst( + MCCFIInstruction::createOffset(nullptr, DReg, Offset)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } + } if (hasFP(MF)) BuildMI(MBB, MBBI, dl, TII.get(Mips::MoveR3216), Mips::S0) - .addReg(Mips::SP); + .addReg(Mips::SP).setMIFlag(MachineInstr::FrameSetup); } @@ -168,10 +173,15 @@ Mips16FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { 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 Mips16InstrInfo &TII = + *static_cast<const Mips16InstrInfo*>(MF.getTarget().getInstrInfo()); + const MipsRegisterInfo &RI = TII.getRegisterInfo(); + const BitVector Reserved = RI.getReservedRegs(MF); + bool SaveS2 = Reserved[Mips::S2]; + if (SaveS2) + MF.getRegInfo().setPhysRegUsed(Mips::S2); + if (hasFP(MF)) + MF.getRegInfo().setPhysRegUsed(Mips::S0); } const MipsFrameLowering * diff --git a/lib/Target/Mips/Mips16FrameLowering.h b/lib/Target/Mips/Mips16FrameLowering.h index 8ce2ceda7c74..1fb7eda0e915 100644 --- a/lib/Target/Mips/Mips16FrameLowering.h +++ b/lib/Target/Mips/Mips16FrameLowering.h @@ -19,32 +19,31 @@ namespace llvm { class Mips16FrameLowering : public MipsFrameLowering { public: - explicit Mips16FrameLowering(const MipsSubtarget &STI) - : MipsFrameLowering(STI, STI.stackAlignment()) {} + explicit Mips16FrameLowering(const MipsSubtarget &STI); /// 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 emitPrologue(MachineFunction &MF) const override; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override; void eliminateCallFramePseudoInstr(MachineFunction &MF, - MachineBasicBlock &MBB, - MachineBasicBlock::iterator I) const; + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const override; bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, const std::vector<CalleeSavedInfo> &CSI, - const TargetRegisterInfo *TRI) const; + const TargetRegisterInfo *TRI) const override; bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - const std::vector<CalleeSavedInfo> &CSI, - const TargetRegisterInfo *TRI) const; + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const override; - bool hasReservedCallFrame(const MachineFunction &MF) const; + bool hasReservedCallFrame(const MachineFunction &MF) const override; void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, - RegScavenger *RS) const; + RegScavenger *RS) const override; }; } // End llvm namespace diff --git a/lib/Target/Mips/Mips16HardFloat.cpp b/lib/Target/Mips/Mips16HardFloat.cpp index 81bf18cd09d9..14055d608e11 100644 --- a/lib/Target/Mips/Mips16HardFloat.cpp +++ b/lib/Target/Mips/Mips16HardFloat.cpp @@ -11,14 +11,16 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "mips16-hard-float" #include "Mips16HardFloat.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Value.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <string> +#define DEBUG_TYPE "mips16-hard-float" + static void inlineAsmOut (LLVMContext &C, StringRef AsmString, BasicBlock *BB ) { std::vector<llvm::Type *> AsmArgTypes; @@ -167,6 +169,11 @@ static bool needsFPReturnHelper(Function &F) { return whichFPReturnVariant(RetType) != NoFPRet; } +static bool needsFPReturnHelper(const FunctionType &FT) { + Type* RetType = FT.getReturnType(); + return whichFPReturnVariant(RetType) != NoFPRet; +} + static bool needsFPHelperFromSig(Function &F) { return needsFPStubFromParams(F) || needsFPReturnHelper(F); } @@ -239,8 +246,8 @@ static void swapFPIntParams // 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){ +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; @@ -348,9 +355,8 @@ static const char *IntrinsicInline[] = }; static bool isIntrinsicInline(Function *F) { - return std::binary_search( - IntrinsicInline, array_endof(IntrinsicInline), - F->getName()); + return std::binary_search(std::begin(IntrinsicInline), + std::end(IntrinsicInline), F->getName()); } // // Returns of float, double and complex need to be handled with a helper @@ -400,13 +406,31 @@ static bool fixupFPReturnAndCall Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T, NULL)); CallInst::Create(F, Params, "", &Inst ); } else if (const CallInst *CI = dyn_cast<CallInst>(I)) { + const Value* V = CI->getCalledValue(); + const Type* T = nullptr; + if (V) T = V->getType(); + const PointerType *PFT=nullptr; + if (T) PFT = dyn_cast<PointerType>(T); + const FunctionType *FT=nullptr; + if (PFT) FT = dyn_cast<FunctionType>(PFT->getElementType()); + Function *F_ = CI->getCalledFunction(); + if (FT && needsFPReturnHelper(*FT) && + !(F_ && isIntrinsicInline(F_))) { + Modified=true; + F.addFnAttr("saveS2"); + } + if (F_ && !isIntrinsicInline(F_)) { // 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); + if (needsFPReturnHelper(*F_)) { Modified=true; + F.addFnAttr("saveS2"); + } + if (Subtarget.getRelocationModel() != Reloc::PIC_ ) { + if (needsFPHelperFromSig(*F_)) { + assureFPCallStub(*F_, M, Subtarget); + Modified=true; + } } } } @@ -476,8 +500,9 @@ namespace llvm { // 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 +// 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 diff --git a/lib/Target/Mips/Mips16HardFloat.h b/lib/Target/Mips/Mips16HardFloat.h index b7f712af5b28..826887ea5ebe 100644 --- a/lib/Target/Mips/Mips16HardFloat.h +++ b/lib/Target/Mips/Mips16HardFloat.h @@ -34,11 +34,11 @@ public: TM(TM_), Subtarget(TM.getSubtarget<MipsSubtarget>()) { } - virtual const char *getPassName() const { + const char *getPassName() const override { return "MIPS16 Hard Float Pass"; } - virtual bool runOnModule(Module &M); + bool runOnModule(Module &M) override; protected: /// Keep a pointer to the MipsSubtarget around so that we can make the right diff --git a/lib/Target/Mips/Mips16HardFloatInfo.cpp b/lib/Target/Mips/Mips16HardFloatInfo.cpp new file mode 100644 index 000000000000..2eb6e5ddd2d9 --- /dev/null +++ b/lib/Target/Mips/Mips16HardFloatInfo.cpp @@ -0,0 +1,50 @@ +//===---- Mips16HardFloatInfo.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 contains the Mips16 implementation of Mips16HardFloatInfo +// namespace. +// +//===----------------------------------------------------------------------===// + +#include "Mips16HardFloatInfo.h" +#include <string.h> + +namespace llvm { + +namespace Mips16HardFloatInfo { + +const FuncNameSignature PredefinedFuncs[] = { + { "__floatdidf", { NoSig, DRet } }, + { "__floatdisf", { NoSig, FRet } }, + { "__floatundidf", { NoSig, DRet } }, + { "__fixsfdi", { FSig, NoFPRet } }, + { "__fixunsdfsi", { DSig, NoFPRet } }, + { "__fixunsdfdi", { DSig, NoFPRet } }, + { "__fixdfdi", { DSig, NoFPRet } }, + { "__fixunssfsi", { FSig, NoFPRet } }, + { "__fixunssfdi", { FSig, NoFPRet } }, + { "__floatundisf", { NoSig, FRet } }, + { nullptr, { NoSig, NoFPRet } } +}; + +// just do a search for now. there are very few of these special cases. +// +extern FuncSignature const *findFuncSignature(const char *name) { + const char *name_; + int i = 0; + while (PredefinedFuncs[i].Name) { + name_ = PredefinedFuncs[i].Name; + if (strcmp(name, name_) == 0) + return &PredefinedFuncs[i].Signature; + i++; + } + return nullptr; +} +} +} diff --git a/lib/Target/Mips/Mips16HardFloatInfo.h b/lib/Target/Mips/Mips16HardFloatInfo.h new file mode 100644 index 000000000000..02444d98c140 --- /dev/null +++ b/lib/Target/Mips/Mips16HardFloatInfo.h @@ -0,0 +1,50 @@ +//===---- Mips16HardFloatInfo.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 some data structures relevant to the implementation of +// Mips16 hard float. +// +// +//===----------------------------------------------------------------------===// + +#ifndef MIPS16HARDFLOATINFO_H +#define MIPS16HARDFLOATINFO_H + +namespace llvm { + +namespace Mips16HardFloatInfo { + +// Return types that matter for hard float are: +// float, double, complex float, and complex double +// +enum FPReturnVariant { FRet, DRet, CFRet, CDRet, 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 }; + +struct FuncSignature { + FPParamVariant ParamSig; + FPReturnVariant RetSig; +}; + +struct FuncNameSignature { + const char *Name; + FuncSignature Signature; +}; + +extern const FuncNameSignature PredefinedFuncs[]; + +extern FuncSignature const *findFuncSignature(const char *name); +} +} + +#endif diff --git a/lib/Target/Mips/Mips16ISelDAGToDAG.cpp b/lib/Target/Mips/Mips16ISelDAGToDAG.cpp index 4948f40734c8..7b0584255542 100644 --- a/lib/Target/Mips/Mips16ISelDAGToDAG.cpp +++ b/lib/Target/Mips/Mips16ISelDAGToDAG.cpp @@ -11,10 +11,9 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "mips-isel" #include "Mips16ISelDAGToDAG.h" -#include "Mips.h" #include "MCTargetDesc/MipsBaseInfo.h" +#include "Mips.h" #include "MipsAnalyzeImmediate.h" #include "MipsMachineFunction.h" #include "MipsRegisterInfo.h" @@ -24,19 +23,22 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/IR/CFG.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; +#define DEBUG_TYPE "mips-isel" + bool Mips16DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { - if (!Subtarget.inMips16Mode()) + Subtarget = &TM.getSubtarget<MipsSubtarget>(); + if (!Subtarget->inMips16Mode()) return false; return MipsDAGToDAGISel::runOnMachineFunction(MF); } @@ -44,7 +46,7 @@ bool Mips16DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { std::pair<SDNode*, SDNode*> Mips16DAGToDAGISel::selectMULT(SDNode *N, unsigned Opc, SDLoc DL, EVT Ty, bool HasLo, bool HasHi) { - SDNode *Lo = 0, *Hi = 0; + SDNode *Lo = nullptr, *Hi = nullptr; SDNode *Mul = CurDAG->getMachineNode(Opc, DL, MVT::Glue, N->getOperand(0), N->getOperand(1)); SDValue InFlag = SDValue(Mul, 0); @@ -224,10 +226,12 @@ bool Mips16DAGToDAGISel::selectAddr16( // 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; + if (LS) { + if (LS->getMemoryVT() == MVT::f32 && Subtarget->hasMips4_32r2()) + return false; + if (LS->getMemoryVT() == MVT::f64 && Subtarget->hasMips4_32r2()) + return false; + } } Base = Addr; Offset = CurDAG->getTargetConstant(0, ValTy); @@ -297,7 +301,7 @@ std::pair<bool, SDNode*> Mips16DAGToDAGISel::selectNode(SDNode *Node) { if (!SDValue(Node, 1).use_empty()) ReplaceUses(SDValue(Node, 1), SDValue(LoHi.second, 0)); - return std::make_pair(true, (SDNode*)NULL); + return std::make_pair(true, nullptr); } case ISD::MULHS: @@ -308,7 +312,7 @@ std::pair<bool, SDNode*> Mips16DAGToDAGISel::selectNode(SDNode *Node) { } } - return std::make_pair(false, (SDNode*)NULL); + return std::make_pair(false, nullptr); } FunctionPass *llvm::createMips16ISelDag(MipsTargetMachine &TM) { diff --git a/lib/Target/Mips/Mips16ISelDAGToDAG.h b/lib/Target/Mips/Mips16ISelDAGToDAG.h index 49dc6e587b62..e653b3910306 100644 --- a/lib/Target/Mips/Mips16ISelDAGToDAG.h +++ b/lib/Target/Mips/Mips16ISelDAGToDAG.h @@ -28,16 +28,16 @@ private: SDValue getMips16SPAliasReg(); - virtual bool runOnMachineFunction(MachineFunction &MF); + bool runOnMachineFunction(MachineFunction &MF) override; void getMips16SPRefReg(SDNode *Parent, SDValue &AliasReg); - virtual bool selectAddr16(SDNode *Parent, SDValue N, SDValue &Base, - SDValue &Offset, SDValue &Alias); + bool selectAddr16(SDNode *Parent, SDValue N, SDValue &Base, + SDValue &Offset, SDValue &Alias) override; - virtual std::pair<bool, SDNode*> selectNode(SDNode *Node); + std::pair<bool, SDNode*> selectNode(SDNode *Node) override; - virtual void processFunctionAfterISel(MachineFunction &MF); + void processFunctionAfterISel(MachineFunction &MF) override; // Insert instructions to initialize the global base register in the // first MBB of the function. diff --git a/lib/Target/Mips/Mips16ISelLowering.cpp b/lib/Target/Mips/Mips16ISelLowering.cpp index 61d8bb8e5582..587925df946b 100644 --- a/lib/Target/Mips/Mips16ISelLowering.cpp +++ b/lib/Target/Mips/Mips16ISelLowering.cpp @@ -10,17 +10,20 @@ // Subclass of MipsTargetLowering specialized for mips16. // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "mips-lower" #include "Mips16ISelLowering.h" +#include "MCTargetDesc/MipsBaseInfo.h" #include "MipsRegisterInfo.h" #include "MipsTargetMachine.h" -#include "MCTargetDesc/MipsBaseInfo.h" +#include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/Support/CommandLine.h" #include "llvm/Target/TargetInstrInfo.h" +#include <string> using namespace llvm; +#define DEBUG_TYPE "mips-lower" + static cl::opt<bool> DontExpandCondPseudos16( "mips16-dont-expand-cond-pseudo", cl::init(false), @@ -115,20 +118,14 @@ static const Mips16IntrinsicHelperType Mips16IntrinsicHelper[] = { {"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(); +Mips16TargetLowering::Mips16TargetLowering(MipsTargetMachine &TM, + const MipsSubtarget &STI) + : MipsTargetLowering(TM, STI) { // Set up the register classes addRegisterClass(MVT::i32, &Mips::CPU16RegsRegClass); - if (Subtarget->inMips16HardFloat()) + if (!TM.Options.UseSoftFloat) setMips16HardFloatLibCalls(); setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Expand); @@ -154,12 +151,15 @@ Mips16TargetLowering::Mips16TargetLowering(MipsTargetMachine &TM) } const MipsTargetLowering * -llvm::createMips16TargetLowering(MipsTargetMachine &TM) { - return new Mips16TargetLowering(TM); +llvm::createMips16TargetLowering(MipsTargetMachine &TM, + const MipsSubtarget &STI) { + return new Mips16TargetLowering(TM, STI); } bool -Mips16TargetLowering::allowsUnalignedMemoryAccesses(EVT VT, bool *Fast) const { +Mips16TargetLowering::allowsUnalignedMemoryAccesses(EVT VT, + unsigned, + bool *Fast) const { return false; } @@ -349,7 +349,7 @@ unsigned int Mips16TargetLowering::getMips16HelperFunctionStubNumber #define T P "0" , T1 #define P P_ static char const * vMips16Helper[MAX_STUB_NUMBER+1] = - {0, T1 }; + {nullptr, T1 }; #undef P #define P P_ "sf_" static char const * sfMips16Helper[MAX_STUB_NUMBER+1] = @@ -426,11 +426,10 @@ getOpndList(SmallVectorImpl<SDValue> &Ops, SelectionDAG &DAG = CLI.DAG; MachineFunction &MF = DAG.getMachineFunction(); MipsFunctionInfo *FuncInfo = MF.getInfo<MipsFunctionInfo>(); - const char* Mips16HelperFunction = 0; + const char* Mips16HelperFunction = nullptr; bool NeedMips16Helper = false; - if (getTargetMachine().Options.UseSoftFloat && - Subtarget->inMips16HardFloat()) { + if (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. @@ -440,19 +439,40 @@ getOpndList(SmallVectorImpl<SDValue> &Ops, if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(CLI.Callee)) { Mips16Libcall Find = { RTLIB::UNKNOWN_LIBCALL, S->getSymbol() }; - if (std::binary_search(HardFloatLibCalls, array_endof(HardFloatLibCalls), - Find)) + if (std::binary_search(std::begin(HardFloatLibCalls), + std::end(HardFloatLibCalls), Find)) LookupHelper = false; else { - Mips16IntrinsicHelperType IntrinsicFind = {S->getSymbol(), ""}; + const char *Symbol = S->getSymbol(); + Mips16IntrinsicHelperType IntrinsicFind = { Symbol, "" }; + const Mips16HardFloatInfo::FuncSignature *Signature = + Mips16HardFloatInfo::findFuncSignature(Symbol); + if (!IsPICCall && (Signature && (FuncInfo->StubsNeeded.find(Symbol) == + FuncInfo->StubsNeeded.end()))) { + FuncInfo->StubsNeeded[Symbol] = Signature; + // + // S2 is normally saved if the stub is for a function which + // returns a float or double value and is not otherwise. This is + // because more work is required after the function the stub + // is calling completes, and so the stub cannot directly return + // and the stub has no stack space to store the return address so + // S2 is used for that purpose. + // In order to take advantage of not saving S2, we need to also + // optimize the call in the stub and this requires some further + // functionality in MipsAsmPrinter which we don't have yet. + // So for now we always save S2. The optimization will be done + // in a follow-on patch. + // + if (1 || (Signature->RetSig != Mips16HardFloatInfo::NoFPRet)) + FuncInfo->setSaveS2(); + } // 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; + const Mips16IntrinsicHelperType *Helper = + std::lower_bound(std::begin(Mips16IntrinsicHelper), + std::end(Mips16IntrinsicHelper), IntrinsicFind); + if (Helper != std::end(Mips16IntrinsicHelper) && + *Helper == IntrinsicFind) { + Mips16HelperFunction = Helper->Helper; NeedMips16Helper = true; LookupHelper = false; } @@ -463,13 +483,13 @@ getOpndList(SmallVectorImpl<SDValue> &Ops, Mips16Libcall Find = { RTLIB::UNKNOWN_LIBCALL, G->getGlobal()->getName().data() }; - if (std::binary_search(HardFloatLibCalls, array_endof(HardFloatLibCalls), - Find)) + if (std::binary_search(std::begin(HardFloatLibCalls), + std::end(HardFloatLibCalls), Find)) LookupHelper = false; } - if (LookupHelper) Mips16HelperFunction = - getMips16HelperFunction(CLI.RetTy, CLI.Args, NeedMips16Helper); - + if (LookupHelper) + Mips16HelperFunction = + getMips16HelperFunction(CLI.RetTy, CLI.getArgs(), NeedMips16Helper); } SDValue JumpTarget = Callee; @@ -524,8 +544,7 @@ emitSel16(unsigned Opc, MachineInstr *MI, MachineBasicBlock *BB) const { // Transfer the remainder of BB and its successor edges to sinkMBB. sinkMBB->splice(sinkMBB->begin(), BB, - llvm::next(MachineBasicBlock::iterator(MI)), - BB->end()); + std::next(MachineBasicBlock::iterator(MI)), BB->end()); sinkMBB->transferSuccessorsAndUpdatePHIs(BB); // Next, add the true and fallthrough blocks as its successors. @@ -587,8 +606,7 @@ MachineBasicBlock *Mips16TargetLowering::emitSelT16 // Transfer the remainder of BB and its successor edges to sinkMBB. sinkMBB->splice(sinkMBB->begin(), BB, - llvm::next(MachineBasicBlock::iterator(MI)), - BB->end()); + std::next(MachineBasicBlock::iterator(MI)), BB->end()); sinkMBB->transferSuccessorsAndUpdatePHIs(BB); // Next, add the true and fallthrough blocks as its successors. @@ -652,8 +670,7 @@ MachineBasicBlock *Mips16TargetLowering::emitSeliT16 // Transfer the remainder of BB and its successor edges to sinkMBB. sinkMBB->splice(sinkMBB->begin(), BB, - llvm::next(MachineBasicBlock::iterator(MI)), - BB->end()); + std::next(MachineBasicBlock::iterator(MI)), BB->end()); sinkMBB->transferSuccessorsAndUpdatePHIs(BB); // Next, add the true and fallthrough blocks as its successors. @@ -747,8 +764,8 @@ MachineBasicBlock *Mips16TargetLowering::emitFEXT_CCRX16_ins( 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(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. diff --git a/lib/Target/Mips/Mips16ISelLowering.h b/lib/Target/Mips/Mips16ISelLowering.h index 33b953f6ff39..e7e4d7f651d4 100644 --- a/lib/Target/Mips/Mips16ISelLowering.h +++ b/lib/Target/Mips/Mips16ISelLowering.h @@ -11,26 +11,28 @@ // //===----------------------------------------------------------------------===// -#ifndef Mips16ISELLOWERING_H -#define Mips16ISELLOWERING_H +#ifndef MIPS16ISELLOWERING_H +#define MIPS16ISELLOWERING_H #include "MipsISelLowering.h" namespace llvm { class Mips16TargetLowering : public MipsTargetLowering { public: - explicit Mips16TargetLowering(MipsTargetMachine &TM); + explicit Mips16TargetLowering(MipsTargetMachine &TM, + const MipsSubtarget &STI); - virtual bool allowsUnalignedMemoryAccesses(EVT VT, bool *Fast) const; + bool allowsUnalignedMemoryAccesses(EVT VT, unsigned AddrSpace, + bool *Fast) const override; - virtual MachineBasicBlock * - EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const; + MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *MBB) const override; private: - virtual bool - isEligibleForTailCallOptimization(const MipsCC &MipsCCInfo, - unsigned NextStackOffset, - const MipsFunctionInfo& FI) const; + bool isEligibleForTailCallOptimization(const MipsCC &MipsCCInfo, + unsigned NextStackOffset, + const MipsFunctionInfo& FI) const override; void setMips16HardFloatLibCalls(); @@ -40,11 +42,12 @@ namespace llvm { const char *getMips16HelperFunction (Type* RetTy, ArgListTy &Args, bool &needHelper) const; - virtual void + 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; + CallLoweringInfo &CLI, SDValue Callee, + SDValue Chain) const override; MachineBasicBlock *emitSel16(unsigned Opc, MachineInstr *MI, MachineBasicBlock *BB) const; diff --git a/lib/Target/Mips/Mips16InstrInfo.cpp b/lib/Target/Mips/Mips16InstrInfo.cpp index 000ea2897f43..4dd9af24968d 100644 --- a/lib/Target/Mips/Mips16InstrInfo.cpp +++ b/lib/Target/Mips/Mips16InstrInfo.cpp @@ -1,3 +1,4 @@ + //===-- Mips16InstrInfo.cpp - Mips16 Instruction Information --------------===// // // The LLVM Compiler Infrastructure @@ -28,17 +29,10 @@ 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); - +#define DEBUG_TYPE "mips16-instrinfo" -Mips16InstrInfo::Mips16InstrInfo(MipsTargetMachine &tm) - : MipsInstrInfo(tm, Mips::Bimm16), - RI(*tm.getSubtargetImpl()) {} +Mips16InstrInfo::Mips16InstrInfo(const MipsSubtarget &STI) + : MipsInstrInfo(STI, Mips::Bimm16), RI(STI) {} const MipsRegisterInfo &Mips16InstrInfo::getRegisterInfo() const { return RI; @@ -49,9 +43,8 @@ const MipsRegisterInfo &Mips16InstrInfo::getRegisterInfo() const { /// 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 -{ +unsigned Mips16InstrInfo::isLoadFromStackSlot(const MachineInstr *MI, + int &FrameIndex) const { return 0; } @@ -60,9 +53,8 @@ isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const /// 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 -{ +unsigned Mips16InstrInfo::isStoreToStackSlot(const MachineInstr *MI, + int &FrameIndex) const { return 0; } @@ -98,11 +90,12 @@ void Mips16InstrInfo::copyPhysReg(MachineBasicBlock &MBB, 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 { +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); @@ -115,10 +108,12 @@ storeRegToStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, .addMemOperand(MMO); } -void Mips16InstrInfo:: -loadRegFromStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, - unsigned DestReg, int FI, const TargetRegisterClass *RC, - const TargetRegisterInfo *TRI, int64_t Offset) const { +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); @@ -175,45 +170,57 @@ unsigned Mips16InstrInfo::getOppositeBranchOpc(unsigned Opc) const { return 0; } +static void addSaveRestoreRegs(MachineInstrBuilder &MIB, + const std::vector<CalleeSavedInfo> &CSI, + unsigned Flags = 0) { + 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[e-i-1].getReg(); + switch (Reg) { + case Mips::RA: + case Mips::S0: + case Mips::S1: + MIB.addReg(Reg, Flags); + break; + case Mips::S2: + break; + default: + llvm_unreachable("unexpected mips16 callee saved register"); + + } + } +} // Adjust SP by FrameSize bytes. Save RA, S0, S1 void Mips16InstrInfo::makeFrame(unsigned SP, int64_t FrameSize, - MachineBasicBlock &MBB, - MachineBasicBlock::iterator I) const { + 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); - } - - } + MachineFunction &MF = *MBB.getParent(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + const BitVector Reserved = RI.getReservedRegs(MF); + bool SaveS2 = Reserved[Mips::S2]; + MachineInstrBuilder MIB; + unsigned Opc = ((FrameSize <= 128) && !SaveS2)? Mips::Save16:Mips::SaveX16; + MIB = BuildMI(MBB, I, DL, get(Opc)); + const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); + addSaveRestoreRegs(MIB, CSI); + if (SaveS2) + MIB.addReg(Mips::S2); + if (isUInt<11>(FrameSize)) + MIB.addImm(FrameSize); 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); + int Base = 2040; // should create template function like isUInt that + // returns largest possible n bit unsigned integer + int64_t Remainder = FrameSize - Base; + MIB.addImm(Base); + if (isInt<16>(-Remainder)) + BuildAddiuSpImm(MBB, I, -Remainder); + else + adjustStackPtrBig(SP, -Remainder, MBB, I, Mips::V0, Mips::V1); } } @@ -222,42 +229,31 @@ 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); - } + MachineFunction *MF = MBB.getParent(); + MachineFrameInfo *MFI = MF->getFrameInfo(); + const BitVector Reserved = RI.getReservedRegs(*MF); + bool SaveS2 = Reserved[Mips::S2]; + MachineInstrBuilder MIB; + unsigned Opc = ((FrameSize <= 128) && !SaveS2)? + Mips::Restore16:Mips::RestoreX16; + + if (!isUInt<11>(FrameSize)) { + unsigned Base = 2040; + int64_t Remainder = FrameSize - Base; + FrameSize = Base; // should create template function like isUInt that + // returns largest possible n bit unsigned integer + if (isInt<16>(Remainder)) + BuildAddiuSpImm(MBB, I, Remainder); + else + adjustStackPtrBig(SP, Remainder, MBB, I, Mips::A0, Mips::A1); + } + MIB = BuildMI(MBB, I, DL, get(Opc)); + const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); + addSaveRestoreRegs(MIB, CSI, RegState::Define); + if (SaveS2) + MIB.addReg(Mips::S2, RegState::Define); + MIB.addImm(FrameSize); } // Adjust SP by Amount bytes where bytes can be up to 32bit number. @@ -270,9 +266,6 @@ void Mips16InstrInfo::adjustStackPtrBig(unsigned SP, int64_t Amount, 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 @@ -281,7 +274,7 @@ void Mips16InstrInfo::adjustStackPtrBig(unsigned SP, int64_t Amount, // // MachineInstrBuilder MIB1 = BuildMI(MBB, I, DL, get(Mips::LwConstant32), Reg1); - MIB1.addImm(Amount); + MIB1.addImm(Amount).addImm(-1); 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); @@ -292,9 +285,9 @@ void Mips16InstrInfo::adjustStackPtrBig(unsigned SP, int64_t Amount, MIB4.addReg(Reg1, RegState::Kill); } -void Mips16InstrInfo::adjustStackPtrBigUnrestricted(unsigned SP, int64_t Amount, - MachineBasicBlock &MBB, - MachineBasicBlock::iterator I) const { +void Mips16InstrInfo::adjustStackPtrBigUnrestricted( + unsigned SP, int64_t Amount, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { assert(false && "adjust stack pointer amount exceeded"); } @@ -310,11 +303,10 @@ void Mips16InstrInfo::adjustStackPtr(unsigned SP, int64_t Amount, /// 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 { +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. @@ -350,7 +342,7 @@ Mips16InstrInfo::loadImmediate(unsigned FrameReg, !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. // @@ -359,7 +351,6 @@ Mips16InstrInfo::loadImmediate(unsigned FrameReg, // 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); @@ -368,9 +359,8 @@ Mips16InstrInfo::loadImmediate(unsigned FrameReg, break; } } - // - BitVector Available = rs.getRegsAvailable(&Mips::CPU16RegsRegClass); + BitVector Available = rs.getRegsAvailable(&Mips::CPU16RegsRegClass); Available &= Candidates; // // we use T0 for the first register, if we need to save something away. @@ -379,7 +369,6 @@ Mips16InstrInfo::loadImmediate(unsigned FrameReg, unsigned FirstRegSaved =0, SecondRegSaved=0; unsigned FirstRegSavedTo = 0, SecondRegSavedTo = 0; - Reg = Available.find_first(); if (Reg == -1) { @@ -393,7 +382,7 @@ Mips16InstrInfo::loadImmediate(unsigned FrameReg, } else Available.reset(Reg); - BuildMI(MBB, II, DL, get(Mips::LwConstant32), Reg).addImm(Imm); + BuildMI(MBB, II, DL, get(Mips::LwConstant32), Reg).addImm(Imm).addImm(-1); NewImm = 0; if (FrameReg == Mips::SP) { SpReg = Available.find_first(); @@ -417,7 +406,7 @@ Mips16InstrInfo::loadImmediate(unsigned FrameReg, BuildMI(MBB, II, DL, get(Mips:: AdduRxRyRz16), Reg).addReg(FrameReg) .addReg(Reg, RegState::Kill); if (FirstRegSaved || SecondRegSaved) { - II = llvm::next(II); + II = std::next(II); if (FirstRegSaved) copyPhysReg(MBB, II, DL, FirstRegSaved, FirstRegSavedTo, true); if (SecondRegSaved) @@ -426,22 +415,6 @@ Mips16InstrInfo::loadImmediate(unsigned FrameReg, 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 || @@ -463,7 +436,6 @@ void Mips16InstrInfo::ExpandRetRA16(MachineBasicBlock &MBB, BuildMI(MBB, I, I->getDebugLoc(), get(Opc)); } - const MCInstrDesc &Mips16InstrInfo::AddiuSpImm(int64_t Imm) const { if (validSpImm8(Imm)) return get(Mips::AddiuSpImm16); @@ -477,8 +449,8 @@ void Mips16InstrInfo::BuildAddiuSpImm BuildMI(MBB, I, DL, AddiuSpImm(Imm)).addImm(Imm); } -const MipsInstrInfo *llvm::createMips16InstrInfo(MipsTargetMachine &TM) { - return new Mips16InstrInfo(TM); +const MipsInstrInfo *llvm::createMips16InstrInfo(const MipsSubtarget &STI) { + return new Mips16InstrInfo(STI); } bool Mips16InstrInfo::validImmediate(unsigned Opcode, unsigned Reg, @@ -518,7 +490,6 @@ bool Mips16InstrInfo::validImmediate(unsigned Opcode, unsigned Reg, unsigned Mips16InstrInfo::getInlineAsmLength(const char *Str, const MCAsmInfo &MAI) const { - // Count the number of instructions in the asm. bool atInsnStart = true; unsigned Length = 0; diff --git a/lib/Target/Mips/Mips16InstrInfo.h b/lib/Target/Mips/Mips16InstrInfo.h index d9a594b537a2..a004c567e6c9 100644 --- a/lib/Target/Mips/Mips16InstrInfo.h +++ b/lib/Target/Mips/Mips16InstrInfo.h @@ -23,48 +23,48 @@ class Mips16InstrInfo : public MipsInstrInfo { const Mips16RegisterInfo RI; public: - explicit Mips16InstrInfo(MipsTargetMachine &TM); + explicit Mips16InstrInfo(const MipsSubtarget &STI); - virtual const MipsRegisterInfo &getRegisterInfo() const; + const MipsRegisterInfo &getRegisterInfo() const override; /// 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; + unsigned isLoadFromStackSlot(const MachineInstr *MI, + int &FrameIndex) const override; /// 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; + unsigned isStoreToStackSlot(const MachineInstr *MI, + int &FrameIndex) const override; - virtual void copyPhysReg(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, DebugLoc DL, - unsigned DestReg, unsigned SrcReg, - bool KillSrc) const; + void copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const override; - virtual void storeRegToStack(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MBBI, - unsigned SrcReg, bool isKill, int FrameIndex, - const TargetRegisterClass *RC, - const TargetRegisterInfo *TRI, - int64_t Offset) const; + void storeRegToStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const override; - virtual void loadRegFromStack(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MBBI, - unsigned DestReg, int FrameIndex, - const TargetRegisterClass *RC, - const TargetRegisterInfo *TRI, - int64_t Offset) const; + void loadRegFromStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const override; - virtual bool expandPostRAPseudo(MachineBasicBlock::iterator MI) const; + bool expandPostRAPseudo(MachineBasicBlock::iterator MI) const override; - virtual unsigned getOppositeBranchOpc(unsigned Opc) const; + unsigned getOppositeBranchOpc(unsigned Opc) const override; // Adjust SP by FrameSize bytes. Save RA, S0, S1 void makeFrame(unsigned SP, int64_t FrameSize, MachineBasicBlock &MBB, @@ -88,11 +88,6 @@ public: 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) { @@ -109,9 +104,9 @@ public: (MachineBasicBlock &MBB, MachineBasicBlock::iterator I, int64_t Imm) const; unsigned getInlineAsmLength(const char *Str, - const MCAsmInfo &MAI) const; + const MCAsmInfo &MAI) const override; private: - virtual unsigned getAnalyzableBrOpc(unsigned Opc) const; + unsigned getAnalyzableBrOpc(unsigned Opc) const override; void ExpandRetRA16(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, unsigned Opc) const; diff --git a/lib/Target/Mips/Mips16InstrInfo.td b/lib/Target/Mips/Mips16InstrInfo.td index 7441c78a0330..5e4eebb62c12 100644 --- a/lib/Target/Mips/Mips16InstrInfo.td +++ b/lib/Target/Mips/Mips16InstrInfo.td @@ -119,7 +119,18 @@ class FJAL16_ins<bits<1> _X, string asmstr, !strconcat(asmstr, "\t$imm\n\tnop"),[], itin> { let isCodeGenOnly=1; + let Size=6; } + +class FJALB16_ins<bits<1> _X, string asmstr, + InstrItinClass itin>: + FJAL16<_X, (outs), (ins simm20:$imm), + !strconcat(asmstr, "\t$imm\t# branch\n\tnop"),[], + itin> { + let isCodeGenOnly=1; + let Size=6; +} + // // EXT-I instruction format // @@ -289,7 +300,7 @@ class FI8_MOV32R16_ins<string asmstr, InstrItinClass itin>: // // This are pseudo formats for multiply -// This first one can be changed to non pseudo now. +// This first one can be changed to non-pseudo now. // // MULT // @@ -734,6 +745,13 @@ def DivuRxRy16: FRR16_div_ins<0b11011, "divu", IIAlu> { def Jal16 : FJAL16_ins<0b0, "jal", IIAlu> { let hasDelaySlot = 0; // not true, but we add the nop for now let isCall=1; + let Defs = [RA]; +} + +def JalB16 : FJALB16_ins<0b0, "jal", IIAlu>, branch16 { + let hasDelaySlot = 0; // not true, but we add the nop for now + let isBranch=1; + let Defs = [RA]; } // @@ -769,7 +787,7 @@ def JrcRx16: FRR16_JALRC_ins<1, 1, 0, "jrc", IIAlu> { // 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{ +def LbRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10011, "lb", mem16, II_LB>, MayLoad{ let isCodeGenOnly = 1; } @@ -779,7 +797,7 @@ def LbRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10011, "lb", mem16, IILoad>, MayLoad{ // To load a byte from memory as a unsigned value. // def LbuRxRyOffMemX16: - FEXT_RRI16_mem_ins<0b10100, "lbu", mem16, IILoad>, MayLoad { + FEXT_RRI16_mem_ins<0b10100, "lbu", mem16, II_LBU>, MayLoad { let isCodeGenOnly = 1; } @@ -788,7 +806,7 @@ def LbuRxRyOffMemX16: // 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{ +def LhRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10100, "lh", mem16, II_LH>, MayLoad{ let isCodeGenOnly = 1; } @@ -798,7 +816,7 @@ def LhRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10100, "lh", mem16, IILoad>, MayLoad{ // To load a halfword from memory as an unsigned value. // def LhuRxRyOffMemX16: - FEXT_RRI16_mem_ins<0b10100, "lhu", mem16, IILoad>, MayLoad { + FEXT_RRI16_mem_ins<0b10100, "lhu", mem16, II_LHU>, MayLoad { let isCodeGenOnly = 1; } @@ -825,7 +843,7 @@ def LiRxImmAlignX16: FEXT_RI16_ins<0b01101, ".align 2\n\tli", IIAlu> { // 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{ +def LwRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10011, "lw", mem16, II_LW>, MayLoad{ let isCodeGenOnly = 1; } @@ -833,13 +851,13 @@ def LwRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10011, "lw", mem16, IILoad>, MayLoad{ // 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{ +def LwRxSpImmX16: FEXT_RI16_SP_explicit_ins<0b10010, "lw", II_LW>, MayLoad{ let Uses = [SP]; } -def LwRxPcTcp16: FRI16_TCP_ins<0b10110, "lw", IILoad>, MayLoad; +def LwRxPcTcp16: FRI16_TCP_ins<0b10110, "lw", II_LW>, MayLoad; -def LwRxPcTcpX16: FEXT_RI16_TCP_ins<0b10110, "lw", IILoad>, MayLoad; +def LwRxPcTcpX16: FEXT_RI16_TCP_ins<0b10110, "lw", II_LW>, MayLoad; // // Format: MOVE r32, rz MIPS16e // Purpose: Move @@ -941,26 +959,18 @@ def OrRxRxRy16: FRxRxRy16_ins<0b01101, "or", IIAlu>, ArithLogic16Defs<1>; // 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 { +def Restore16: + FI8_SVRS16<0b1, (outs), (ins variable_ops), + "", [], II_RESTORE >, MayLoad { let isCodeGenOnly = 1; - let Defs = [S0, S1, S2, RA, SP]; + let Defs = [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 { + +def RestoreX16: + FI8_SVRS16<0b1, (outs), (ins variable_ops), + "", [], II_RESTORE >, MayLoad { let isCodeGenOnly = 1; let Defs = [SP]; let Uses = [SP]; @@ -973,23 +983,17 @@ def RestoreIncSpF16: // 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 { +def Save16: + FI8_SVRS16<0b1, (outs), (ins variable_ops), + "", [], II_SAVE >, MayStore { let isCodeGenOnly = 1; - let Uses = [RA, SP, S0, S1, S2]; + let Uses = [SP]; 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 { +def SaveX16: + FI8_SVRS16<0b1, (outs), (ins variable_ops), + "", [], II_SAVE >, MayStore { let isCodeGenOnly = 1; let Uses = [SP]; let Defs = [SP]; @@ -1000,7 +1004,7 @@ def SaveDecSpF16: // To store a byte to memory. // def SbRxRyOffMemX16: - FEXT_RRI16_mem2_ins<0b11000, "sb", mem16, IIStore>, MayStore; + FEXT_RRI16_mem2_ins<0b11000, "sb", mem16, II_SB>, MayStore; // // Format: SEB rx MIPS16e @@ -1138,7 +1142,7 @@ def SelTBtneZSltiu: SeliT<"btnez", "sltiu">; // To store a halfword to memory. // def ShRxRyOffMemX16: - FEXT_RRI16_mem2_ins<0b11001, "sh", mem16, IIStore>, MayStore; + FEXT_RRI16_mem2_ins<0b11001, "sh", mem16, II_SH>, MayStore; // // Format: SLL rx, ry, sa MIPS16e @@ -1274,7 +1278,7 @@ def SubuRxRyRz16: FRRR16_ins<0b11, "subu", IIAlu>, ArithLogic16Defs<0>; // To store a word to memory. // def SwRxRyOffMemX16: - FEXT_RRI16_mem2_ins<0b11011, "sw", mem16, IIStore>, MayStore; + FEXT_RRI16_mem2_ins<0b11011, "sw", mem16, II_SW>, MayStore; // // Format: SW rx, offset(sp) MIPS16e @@ -1282,7 +1286,7 @@ def SwRxRyOffMemX16: // To store an SP-relative word to memory. // def SwRxSpImmX16: FEXT_RI16_SP_Store_explicit_ins - <0b11010, "sw", IIStore>, MayStore; + <0b11010, "sw", II_SW>, MayStore; // // @@ -1366,15 +1370,19 @@ def : Mips16Pat<(MipsJmpLink (i32 texternalsym:$dst)), (Jal16 texternalsym:$dst)>; // Indirect branch -def: Mips16Pat< - (brind CPU16Regs:$rs), - (JrcRx16 CPU16Regs:$rs)>; +def: Mips16Pat<(brind CPU16Regs:$rs), (JrcRx16 CPU16Regs:$rs)> { + // Ensure that the addition of MIPS32r6/MIPS64r6 support does not change + // MIPS16's behaviour. + let AddedComplexity = 1; +} // 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>; + "jalrc \t$rs", [(MipsJmpLink CPU16Regs:$rs)], IIBranch> { + let Defs = [RA]; +} // Mips16 pseudos let isReturn=1, isTerminator=1, hasDelaySlot=1, isBarrier=1, hasCtrlDep=1, @@ -1890,7 +1898,7 @@ 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 ",[]> ; + "li\t$rh, $immHi\n\taddiu\t$rl, $$pc, $immLo\n ",[]> ; // An operand for the CONSTPOOL_ENTRY pseudo-instruction. def cpinst_operand : Operand<i32> { diff --git a/lib/Target/Mips/Mips16RegisterInfo.cpp b/lib/Target/Mips/Mips16RegisterInfo.cpp index 9d0f2c927e4d..dbee774637dd 100644 --- a/lib/Target/Mips/Mips16RegisterInfo.cpp +++ b/lib/Target/Mips/Mips16RegisterInfo.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "Mips16RegisterInfo.h" -#include "Mips16InstrInfo.h" #include "Mips.h" #include "Mips16InstrInfo.h" #include "MipsAnalyzeImmediate.h" @@ -25,9 +24,8 @@ #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/DebugInfo.h" #include "llvm/IR/Function.h" #include "llvm/IR/Type.h" #include "llvm/Support/CommandLine.h" @@ -41,6 +39,8 @@ using namespace llvm; +#define DEBUG_TYPE "mips16-registerinfo" + Mips16RegisterInfo::Mips16RegisterInfo(const MipsSubtarget &ST) : MipsRegisterInfo(ST) {} diff --git a/lib/Target/Mips/Mips16RegisterInfo.h b/lib/Target/Mips/Mips16RegisterInfo.h index 13e82a3ffba9..f59f1a7c1098 100644 --- a/lib/Target/Mips/Mips16RegisterInfo.h +++ b/lib/Target/Mips/Mips16RegisterInfo.h @@ -23,24 +23,24 @@ class Mips16RegisterInfo : public MipsRegisterInfo { public: Mips16RegisterInfo(const MipsSubtarget &Subtarget); - bool requiresRegisterScavenging(const MachineFunction &MF) const; + bool requiresRegisterScavenging(const MachineFunction &MF) const override; - bool requiresFrameIndexScavenging(const MachineFunction &MF) const; + bool requiresFrameIndexScavenging(const MachineFunction &MF) const override; - bool useFPForScavengingIndex(const MachineFunction &MF) const; + bool useFPForScavengingIndex(const MachineFunction &MF) const override; bool saveScavengerRegister(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, MachineBasicBlock::iterator &UseMI, const TargetRegisterClass *RC, - unsigned Reg) const; + unsigned Reg) const override; - virtual const TargetRegisterClass *intRegClass(unsigned Size) const; + const TargetRegisterClass *intRegClass(unsigned Size) const override; private: - virtual void eliminateFI(MachineBasicBlock::iterator II, unsigned OpNo, - int FrameIndex, uint64_t StackSize, - int64_t SPOffset) const; + void eliminateFI(MachineBasicBlock::iterator II, unsigned OpNo, + int FrameIndex, uint64_t StackSize, + int64_t SPOffset) const override; }; } // end namespace llvm diff --git a/lib/Target/Mips/Mips32r6InstrFormats.td b/lib/Target/Mips/Mips32r6InstrFormats.td new file mode 100644 index 000000000000..e4ec96a92f5b --- /dev/null +++ b/lib/Target/Mips/Mips32r6InstrFormats.td @@ -0,0 +1,543 @@ +//=- Mips32r6InstrFormats.td - Mips32r6 Instruction Formats -*- 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 Mips32r6 instruction formats. +// +//===----------------------------------------------------------------------===// + +class MipsR6Inst : MipsInst<(outs), (ins), "", [], NoItinerary, FrmOther>, + PredicateControl { + let DecoderNamespace = "Mips32r6_64r6"; + let EncodingPredicates = [HasStdEnc]; +} + +//===----------------------------------------------------------------------===// +// +// Field Values +// +//===----------------------------------------------------------------------===// + +class OPGROUP<bits<6> Val> { + bits<6> Value = Val; +} +def OPGROUP_COP1 : OPGROUP<0b010001>; +def OPGROUP_COP2 : OPGROUP<0b010010>; +def OPGROUP_ADDI : OPGROUP<0b001000>; +def OPGROUP_AUI : OPGROUP<0b001111>; +def OPGROUP_BLEZ : OPGROUP<0b000110>; +def OPGROUP_BGTZ : OPGROUP<0b000111>; +def OPGROUP_BLEZL : OPGROUP<0b010110>; +def OPGROUP_BGTZL : OPGROUP<0b010111>; +def OPGROUP_DADDI : OPGROUP<0b011000>; +def OPGROUP_DAUI : OPGROUP<0b011101>; +def OPGROUP_PCREL : OPGROUP<0b111011>; +def OPGROUP_REGIMM : OPGROUP<0b000001>; +def OPGROUP_SPECIAL : OPGROUP<0b000000>; +// The spec occasionally names this value LL, LLD, SC, or SCD. +def OPGROUP_SPECIAL3 : OPGROUP<0b011111>; +// The spec names this constant LWC2, LDC2, SWC2, and SDC2 in different places. +def OPGROUP_COP2LDST : OPGROUP<0b010010>; + +class OPCODE2<bits<2> Val> { + bits<2> Value = Val; +} +def OPCODE2_ADDIUPC : OPCODE2<0b00>; +def OPCODE2_LWPC : OPCODE2<0b01>; +def OPCODE2_LWUPC : OPCODE2<0b10>; + +class OPCODE3<bits<3> Val> { + bits<3> Value = Val; +} +def OPCODE3_LDPC : OPCODE3<0b110>; + +class OPCODE5<bits<5> Val> { + bits<5> Value = Val; +} +def OPCODE5_ALUIPC : OPCODE5<0b11111>; +def OPCODE5_AUIPC : OPCODE5<0b11110>; +def OPCODE5_DAHI : OPCODE5<0b00110>; +def OPCODE5_DATI : OPCODE5<0b11110>; +def OPCODE5_BC1EQZ : OPCODE5<0b01001>; +def OPCODE5_BC1NEZ : OPCODE5<0b01101>; +def OPCODE5_BC2EQZ : OPCODE5<0b01001>; +def OPCODE5_BC2NEZ : OPCODE5<0b01101>; +def OPCODE5_BGEZAL : OPCODE5<0b10001>; +// The next four constants are unnamed in the spec. These names are taken from +// the OPGROUP names they are used with. +def OPCODE5_LDC2 : OPCODE5<0b01110>; +def OPCODE5_LWC2 : OPCODE5<0b01010>; +def OPCODE5_SDC2 : OPCODE5<0b01111>; +def OPCODE5_SWC2 : OPCODE5<0b01011>; + +class OPCODE6<bits<6> Val> { + bits<6> Value = Val; +} +def OPCODE6_ALIGN : OPCODE6<0b100000>; +def OPCODE6_DALIGN : OPCODE6<0b100100>; +def OPCODE6_BITSWAP : OPCODE6<0b100000>; +def OPCODE6_DBITSWAP : OPCODE6<0b100100>; +def OPCODE6_JALR : OPCODE6<0b001001>; +def OPCODE6_CACHE : OPCODE6<0b100101>; +def OPCODE6_PREF : OPCODE6<0b110101>; +// The next four constants are unnamed in the spec. These names are taken from +// the OPGROUP names they are used with. +def OPCODE6_LL : OPCODE6<0b110110>; +def OPCODE6_LLD : OPCODE6<0b110111>; +def OPCODE6_SC : OPCODE6<0b100110>; +def OPCODE6_SCD : OPCODE6<0b100111>; +def OPCODE6_CLO : OPCODE6<0b010001>; +def OPCODE6_CLZ : OPCODE6<0b010000>; +def OPCODE6_DCLO : OPCODE6<0b010011>; +def OPCODE6_DCLZ : OPCODE6<0b010010>; +def OPCODE6_LSA : OPCODE6<0b000101>; +def OPCODE6_DLSA : OPCODE6<0b010101>; +def OPCODE6_SDBBP : OPCODE6<0b001110>; + +class FIELD_FMT<bits<5> Val> { + bits<5> Value = Val; +} +def FIELD_FMT_S : FIELD_FMT<0b10000>; +def FIELD_FMT_D : FIELD_FMT<0b10001>; + +class FIELD_CMP_COND<bits<5> Val> { + bits<5> Value = Val; +} +// Note: The CMP_COND_FMT names differ from the C_COND_FMT names. +def FIELD_CMP_COND_AF : FIELD_CMP_COND<0b00000>; +def FIELD_CMP_COND_UN : FIELD_CMP_COND<0b00001>; +def FIELD_CMP_COND_EQ : FIELD_CMP_COND<0b00010>; +def FIELD_CMP_COND_UEQ : FIELD_CMP_COND<0b00011>; +def FIELD_CMP_COND_LT : FIELD_CMP_COND<0b00100>; +def FIELD_CMP_COND_ULT : FIELD_CMP_COND<0b00101>; +def FIELD_CMP_COND_LE : FIELD_CMP_COND<0b00110>; +def FIELD_CMP_COND_ULE : FIELD_CMP_COND<0b00111>; +def FIELD_CMP_COND_SAF : FIELD_CMP_COND<0b01000>; +def FIELD_CMP_COND_SUN : FIELD_CMP_COND<0b01001>; +def FIELD_CMP_COND_SEQ : FIELD_CMP_COND<0b01010>; +def FIELD_CMP_COND_SUEQ : FIELD_CMP_COND<0b01011>; +def FIELD_CMP_COND_SLT : FIELD_CMP_COND<0b01100>; +def FIELD_CMP_COND_SULT : FIELD_CMP_COND<0b01101>; +def FIELD_CMP_COND_SLE : FIELD_CMP_COND<0b01110>; +def FIELD_CMP_COND_SULE : FIELD_CMP_COND<0b01111>; + +class FIELD_CMP_FORMAT<bits<5> Val> { + bits<5> Value = Val; +} +def FIELD_CMP_FORMAT_S : FIELD_CMP_FORMAT<0b10100>; +def FIELD_CMP_FORMAT_D : FIELD_CMP_FORMAT<0b10101>; + +//===----------------------------------------------------------------------===// +// +// Disambiguators +// +//===----------------------------------------------------------------------===// +// +// Some encodings are ambiguous except by comparing field values. + +class DecodeDisambiguates<string Name> { + string DecoderMethod = !strconcat("Decode", Name); +} + +class DecodeDisambiguatedBy<string Name> : DecodeDisambiguates<Name> { + string DecoderNamespace = "Mips32r6_64r6_Ambiguous"; +} + +//===----------------------------------------------------------------------===// +// +// Encoding Formats +// +//===----------------------------------------------------------------------===// + +class AUI_FM : MipsR6Inst { + bits<5> rs; + bits<5> rt; + bits<16> imm; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_AUI.Value; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-0} = imm; +} + +class DAUI_FM : AUI_FM { + let Inst{31-26} = OPGROUP_DAUI.Value; +} + +class BAL_FM : MipsR6Inst { + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_REGIMM.Value; + let Inst{25-21} = 0b00000; + let Inst{20-16} = OPCODE5_BGEZAL.Value; + let Inst{15-0} = offset; +} + +class COP1_2R_FM<bits<6> funct, FIELD_FMT Format> : MipsR6Inst { + bits<5> fs; + bits<5> fd; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_COP1.Value; + let Inst{25-21} = Format.Value; + let Inst{20-16} = 0b00000; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5-0} = funct; +} + +class COP1_3R_FM<bits<6> funct, FIELD_FMT Format> : MipsR6Inst { + bits<5> ft; + bits<5> fs; + bits<5> fd; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_COP1.Value; + let Inst{25-21} = Format.Value; + let Inst{20-16} = ft; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5-0} = funct; +} + +class COP1_BCCZ_FM<OPCODE5 Operation> : MipsR6Inst { + bits<5> ft; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_COP1.Value; + let Inst{25-21} = Operation.Value; + let Inst{20-16} = ft; + let Inst{15-0} = offset; +} + +class COP2_BCCZ_FM<OPCODE5 Operation> : MipsR6Inst { + bits<5> ct; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_COP2.Value; + let Inst{25-21} = Operation.Value; + let Inst{20-16} = ct; + let Inst{15-0} = offset; +} + +class PCREL16_FM<OPCODE5 Operation> : MipsR6Inst { + bits<5> rs; + bits<16> imm; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_PCREL.Value; + let Inst{25-21} = rs; + let Inst{20-16} = Operation.Value; + let Inst{15-0} = imm; +} + +class PCREL19_FM<OPCODE2 Operation> : MipsR6Inst { + bits<5> rs; + bits<19> imm; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_PCREL.Value; + let Inst{25-21} = rs; + let Inst{20-19} = Operation.Value; + let Inst{18-0} = imm; +} + +class PCREL18_FM<OPCODE3 Operation> : MipsR6Inst { + bits<5> rs; + bits<18> imm; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_PCREL.Value; + let Inst{25-21} = rs; + let Inst{20-18} = Operation.Value; + let Inst{17-0} = imm; +} + +class SPECIAL3_2R_FM<OPCODE6 Operation> : MipsR6Inst { + bits<5> rd; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL3.Value; + let Inst{25-21} = 0b00000; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = 0b00000; + let Inst{5-0} = Operation.Value; +} + +class SPECIAL3_MEM_FM<OPCODE6 Operation> : MipsR6Inst { + bits<21> addr; + bits<5> hint; + bits<5> base = addr{20-16}; + bits<9> offset = addr{8-0}; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL3.Value; + let Inst{25-21} = base; + let Inst{20-16} = hint; + let Inst{15-7} = offset; + let Inst{6} = 0; + let Inst{5-0} = Operation.Value; +} + +class SPECIAL_2R_FM<OPCODE6 Operation> : MipsR6Inst { + bits<5> rd; + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL.Value; + let Inst{25-21} = rs; + let Inst{20-16} = 0b00000; + let Inst{15-11} = rd; + let Inst{10-6} = 0b00001; + let Inst{5-0} = Operation.Value; +} + +class SPECIAL_3R_FM<bits<5> mulop, bits<6> funct> : MipsR6Inst { + bits<5> rd; + bits<5> rs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL.Value; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = mulop; + let Inst{5-0} = funct; +} + +class SPECIAL_SDBBP_FM : MipsR6Inst { + bits<20> code_; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL.Value; + let Inst{25-6} = code_; + let Inst{5-0} = OPCODE6_SDBBP.Value; +} + +// This class is ambiguous with other branches: +// BEQC/BNEC require that rs > rt +class CMP_BRANCH_2R_OFF16_FM<OPGROUP funct> : MipsR6Inst { + bits<5> rs; + bits<5> rt; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = funct.Value; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-0} = offset; +} + +// This class is ambiguous with other branches: +// BLEZC/BGEZC/BEQZALC/BNEZALC/BGTZALC require that rs == 0 && rt != 0 +// The '1R_RT' in the name means 1 register in the rt field. +class CMP_BRANCH_1R_RT_OFF16_FM<OPGROUP funct> : MipsR6Inst { + bits<5> rt; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = funct.Value; + let Inst{25-21} = 0b00000; + let Inst{20-16} = rt; + let Inst{15-0} = offset; +} + +// This class is ambiguous with other branches: +// BLTZC/BGTZC/BLTZALC/BGEZALC require that rs == rt && rt != 0 +// The '1R_BOTH' in the name means 1 register in both the rs and rt fields. +class CMP_BRANCH_1R_BOTH_OFF16_FM<OPGROUP funct> : MipsR6Inst { + bits<5> rt; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = funct.Value; + let Inst{25-21} = rt; + let Inst{20-16} = rt; + let Inst{15-0} = offset; +} + +class CMP_BRANCH_OFF21_FM<bits<6> funct> : MipsR6Inst { + bits<5> rs; // rs != 0 + bits<21> offset; + + bits<32> Inst; + + let Inst{31-26} = funct; + let Inst{25-21} = rs; + let Inst{20-0} = offset; +} + +class JMP_IDX_COMPACT_FM<bits<6> funct> : MipsR6Inst { + bits<5> rt; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = funct; + let Inst{25-21} = 0b000000; + let Inst{20-16} = rt; + let Inst{15-0} = offset; +} + +class BRANCH_OFF26_FM<bits<6> funct> : MipsR6Inst { + bits<32> Inst; + bits<26> offset; + + let Inst{31-26} = funct; + let Inst{25-0} = offset; +} + +class SPECIAL3_ALIGN_FM<OPCODE6 Operation> : MipsR6Inst { + bits<5> rd; + bits<5> rs; + bits<5> rt; + bits<2> bp; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL3.Value; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-8} = 0b010; + let Inst{7-6} = bp; + let Inst{5-0} = Operation.Value; +} + +class SPECIAL3_DALIGN_FM<OPCODE6 Operation> : MipsR6Inst { + bits<5> rd; + bits<5> rs; + bits<5> rt; + bits<3> bp; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL3.Value; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-9} = 0b01; + let Inst{8-6} = bp; + let Inst{5-0} = Operation.Value; +} + +class SPECIAL3_LL_SC_FM<OPCODE6 Operation> : MipsR6Inst { + bits<5> rt; + bits<21> addr; + bits<5> base = addr{20-16}; + bits<9> offset = addr{8-0}; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL3.Value; + let Inst{25-21} = base; + let Inst{20-16} = rt; + let Inst{15-7} = offset; + let Inst{5-0} = Operation.Value; + + string DecoderMethod = "DecodeSpecial3LlSc"; +} + +class SPECIAL_LSA_FM<OPCODE6 Operation> : MipsR6Inst { + bits<5> rd; + bits<5> rs; + bits<5> rt; + bits<2> imm2; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL.Value; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-8} = 0b000; + let Inst{7-6} = imm2; + let Inst{5-0} = Operation.Value; +} + +class REGIMM_FM<OPCODE5 Operation> : MipsR6Inst { + bits<5> rs; + bits<16> imm; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_REGIMM.Value; + let Inst{25-21} = rs; + let Inst{20-16} = Operation.Value; + let Inst{15-0} = imm; +} + +class COP1_CMP_CONDN_FM<FIELD_CMP_FORMAT Format, + FIELD_CMP_COND Cond> : MipsR6Inst { + bits<5> fd; + bits<5> fs; + bits<5> ft; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_COP1.Value; + let Inst{25-21} = Format.Value; + let Inst{20-16} = ft; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5} = 0; + let Inst{4-0} = Cond.Value; +} + +class JR_HB_R6_FM<OPCODE6 Operation> : MipsR6Inst { + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL.Value; + let Inst{25-21} = rs; + let Inst{20-16} = 0; + let Inst{15-11} = 0; + let Inst{10} = 1; + let Inst{9-6} = 0; + let Inst{5-0} = Operation.Value; +} + +class COP2LDST_FM<OPCODE5 Operation> : MipsR6Inst { + bits<5> rt; + bits<21> addr; + bits<5> base = addr{20-16}; + bits<11> offset = addr{10-0}; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_COP2LDST.Value; + let Inst{25-21} = Operation.Value; + let Inst{20-16} = rt; + let Inst{15-11} = base; + let Inst{10-0} = offset; +} diff --git a/lib/Target/Mips/Mips32r6InstrInfo.td b/lib/Target/Mips/Mips32r6InstrInfo.td new file mode 100644 index 000000000000..6d6735b3aae6 --- /dev/null +++ b/lib/Target/Mips/Mips32r6InstrInfo.td @@ -0,0 +1,824 @@ +//=- Mips32r6InstrInfo.td - Mips32r6 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 Mips32r6 instructions. +// +//===----------------------------------------------------------------------===// + +include "Mips32r6InstrFormats.td" + +// Notes about removals/changes from MIPS32r6: +// Reencoded: jr -> jalr +// Reencoded: jr.hb -> jalr.hb + +def brtarget21 : Operand<OtherVT> { + let EncoderMethod = "getBranchTarget21OpValue"; + let OperandType = "OPERAND_PCREL"; + let DecoderMethod = "DecodeBranchTarget21"; + let ParserMatchClass = MipsJumpTargetAsmOperand; +} + +def brtarget26 : Operand<OtherVT> { + let EncoderMethod = "getBranchTarget26OpValue"; + let OperandType = "OPERAND_PCREL"; + let DecoderMethod = "DecodeBranchTarget26"; + let ParserMatchClass = MipsJumpTargetAsmOperand; +} + +def jmpoffset16 : Operand<OtherVT> { + let EncoderMethod = "getJumpOffset16OpValue"; + let ParserMatchClass = MipsJumpTargetAsmOperand; +} + +def calloffset16 : Operand<iPTR> { + let EncoderMethod = "getJumpOffset16OpValue"; + let ParserMatchClass = MipsJumpTargetAsmOperand; +} + +//===----------------------------------------------------------------------===// +// +// Instruction Encodings +// +//===----------------------------------------------------------------------===// + +class ADDIUPC_ENC : PCREL19_FM<OPCODE2_ADDIUPC>; +class ALIGN_ENC : SPECIAL3_ALIGN_FM<OPCODE6_ALIGN>; +class ALUIPC_ENC : PCREL16_FM<OPCODE5_ALUIPC>; +class AUI_ENC : AUI_FM; +class AUIPC_ENC : PCREL16_FM<OPCODE5_AUIPC>; + +class BAL_ENC : BAL_FM; +class BALC_ENC : BRANCH_OFF26_FM<0b111010>; +class BC_ENC : BRANCH_OFF26_FM<0b110010>; +class BEQC_ENC : CMP_BRANCH_2R_OFF16_FM<OPGROUP_ADDI>, + DecodeDisambiguates<"AddiGroupBranch">; +class BEQZALC_ENC : CMP_BRANCH_1R_RT_OFF16_FM<OPGROUP_ADDI>, + DecodeDisambiguatedBy<"DaddiGroupBranch">; +class BNEC_ENC : CMP_BRANCH_2R_OFF16_FM<OPGROUP_DADDI>, + DecodeDisambiguates<"DaddiGroupBranch">; +class BNEZALC_ENC : CMP_BRANCH_1R_RT_OFF16_FM<OPGROUP_DADDI>, + DecodeDisambiguatedBy<"DaddiGroupBranch">; + +class BLTZC_ENC : CMP_BRANCH_1R_BOTH_OFF16_FM<OPGROUP_BGTZL>, + DecodeDisambiguates<"BgtzlGroupBranch">; +class BGEC_ENC : CMP_BRANCH_2R_OFF16_FM<OPGROUP_BLEZL>, + DecodeDisambiguatedBy<"BlezlGroupBranch">; +class BGEUC_ENC : CMP_BRANCH_2R_OFF16_FM<OPGROUP_BLEZ>, + DecodeDisambiguatedBy<"BlezGroupBranch">; +class BGEZC_ENC : CMP_BRANCH_1R_BOTH_OFF16_FM<OPGROUP_BLEZL>, + DecodeDisambiguates<"BlezlGroupBranch">; +class BGTZALC_ENC : CMP_BRANCH_1R_RT_OFF16_FM<OPGROUP_BGTZ>, + DecodeDisambiguatedBy<"BgtzGroupBranch">; + +class BLTC_ENC : CMP_BRANCH_2R_OFF16_FM<OPGROUP_BGTZL>, + DecodeDisambiguatedBy<"BgtzlGroupBranch">; +class BLTUC_ENC : CMP_BRANCH_2R_OFF16_FM<OPGROUP_BGTZ>, + DecodeDisambiguatedBy<"BgtzGroupBranch">; + +class BLEZC_ENC : CMP_BRANCH_1R_RT_OFF16_FM<OPGROUP_BLEZL>, + DecodeDisambiguatedBy<"BlezlGroupBranch">; +class BLTZALC_ENC : CMP_BRANCH_1R_BOTH_OFF16_FM<OPGROUP_BGTZ>, + DecodeDisambiguates<"BgtzGroupBranch">; +class BGTZC_ENC : CMP_BRANCH_1R_RT_OFF16_FM<OPGROUP_BGTZL>, + DecodeDisambiguatedBy<"BgtzlGroupBranch">; + +class BEQZC_ENC : CMP_BRANCH_OFF21_FM<0b110110>; +class BGEZALC_ENC : CMP_BRANCH_1R_BOTH_OFF16_FM<OPGROUP_BLEZ>, + DecodeDisambiguates<"BlezGroupBranch">; +class BNEZC_ENC : CMP_BRANCH_OFF21_FM<0b111110>; + +class BC1EQZ_ENC : COP1_BCCZ_FM<OPCODE5_BC1EQZ>; +class BC1NEZ_ENC : COP1_BCCZ_FM<OPCODE5_BC1NEZ>; +class BC2EQZ_ENC : COP2_BCCZ_FM<OPCODE5_BC2EQZ>; +class BC2NEZ_ENC : COP2_BCCZ_FM<OPCODE5_BC2NEZ>; + +class JIALC_ENC : JMP_IDX_COMPACT_FM<0b111110>; +class JIC_ENC : JMP_IDX_COMPACT_FM<0b110110>; +class JR_HB_R6_ENC : JR_HB_R6_FM<OPCODE6_JALR>; +class BITSWAP_ENC : SPECIAL3_2R_FM<OPCODE6_BITSWAP>; +class BLEZALC_ENC : CMP_BRANCH_1R_RT_OFF16_FM<OPGROUP_BLEZ>, + DecodeDisambiguatedBy<"BlezGroupBranch">; +class BNVC_ENC : CMP_BRANCH_2R_OFF16_FM<OPGROUP_DADDI>, + DecodeDisambiguatedBy<"DaddiGroupBranch">; +class BOVC_ENC : CMP_BRANCH_2R_OFF16_FM<OPGROUP_ADDI>, + DecodeDisambiguatedBy<"AddiGroupBranch">; +class DIV_ENC : SPECIAL_3R_FM<0b00010, 0b011010>; +class DIVU_ENC : SPECIAL_3R_FM<0b00010, 0b011011>; +class MOD_ENC : SPECIAL_3R_FM<0b00011, 0b011010>; +class MODU_ENC : SPECIAL_3R_FM<0b00011, 0b011011>; +class MUH_ENC : SPECIAL_3R_FM<0b00011, 0b011000>; +class MUHU_ENC : SPECIAL_3R_FM<0b00011, 0b011001>; +class MUL_R6_ENC : SPECIAL_3R_FM<0b00010, 0b011000>; +class MULU_ENC : SPECIAL_3R_FM<0b00010, 0b011001>; + +class MADDF_S_ENC : COP1_3R_FM<0b011000, FIELD_FMT_S>; +class MADDF_D_ENC : COP1_3R_FM<0b011000, FIELD_FMT_D>; +class MSUBF_S_ENC : COP1_3R_FM<0b011001, FIELD_FMT_S>; +class MSUBF_D_ENC : COP1_3R_FM<0b011001, FIELD_FMT_D>; + +class SEL_D_ENC : COP1_3R_FM<0b010000, FIELD_FMT_D>; +class SEL_S_ENC : COP1_3R_FM<0b010000, FIELD_FMT_S>; + +class SELEQZ_ENC : SPECIAL_3R_FM<0b00000, 0b110101>; +class SELNEZ_ENC : SPECIAL_3R_FM<0b00000, 0b110111>; + +class LWPC_ENC : PCREL19_FM<OPCODE2_LWPC>; +class LWUPC_ENC : PCREL19_FM<OPCODE2_LWUPC>; + +class MAX_S_ENC : COP1_3R_FM<0b011101, FIELD_FMT_S>; +class MAX_D_ENC : COP1_3R_FM<0b011101, FIELD_FMT_D>; +class MIN_S_ENC : COP1_3R_FM<0b011100, FIELD_FMT_S>; +class MIN_D_ENC : COP1_3R_FM<0b011100, FIELD_FMT_D>; + +class MAXA_S_ENC : COP1_3R_FM<0b011111, FIELD_FMT_S>; +class MAXA_D_ENC : COP1_3R_FM<0b011111, FIELD_FMT_D>; +class MINA_S_ENC : COP1_3R_FM<0b011110, FIELD_FMT_S>; +class MINA_D_ENC : COP1_3R_FM<0b011110, FIELD_FMT_D>; + +class SELEQZ_S_ENC : COP1_3R_FM<0b010100, FIELD_FMT_S>; +class SELEQZ_D_ENC : COP1_3R_FM<0b010100, FIELD_FMT_D>; +class SELNEZ_S_ENC : COP1_3R_FM<0b010111, FIELD_FMT_S>; +class SELNEZ_D_ENC : COP1_3R_FM<0b010111, FIELD_FMT_D>; + +class RINT_S_ENC : COP1_2R_FM<0b011010, FIELD_FMT_S>; +class RINT_D_ENC : COP1_2R_FM<0b011010, FIELD_FMT_D>; +class CLASS_S_ENC : COP1_2R_FM<0b011011, FIELD_FMT_S>; +class CLASS_D_ENC : COP1_2R_FM<0b011011, FIELD_FMT_D>; + +class CACHE_ENC : SPECIAL3_MEM_FM<OPCODE6_CACHE>; +class PREF_ENC : SPECIAL3_MEM_FM<OPCODE6_PREF>; + +class LDC2_R6_ENC : COP2LDST_FM<OPCODE5_LDC2>; +class LWC2_R6_ENC : COP2LDST_FM<OPCODE5_LWC2>; +class SDC2_R6_ENC : COP2LDST_FM<OPCODE5_SDC2>; +class SWC2_R6_ENC : COP2LDST_FM<OPCODE5_SWC2>; + +class LSA_R6_ENC : SPECIAL_LSA_FM<OPCODE6_LSA>; + +class LL_R6_ENC : SPECIAL3_LL_SC_FM<OPCODE6_LL>; +class SC_R6_ENC : SPECIAL3_LL_SC_FM<OPCODE6_SC>; + +class CLO_R6_ENC : SPECIAL_2R_FM<OPCODE6_CLO>; +class CLZ_R6_ENC : SPECIAL_2R_FM<OPCODE6_CLZ>; + +class SDBBP_R6_ENC : SPECIAL_SDBBP_FM; + +//===----------------------------------------------------------------------===// +// +// Instruction Multiclasses +// +//===----------------------------------------------------------------------===// + +class CMP_CONDN_DESC_BASE<string CondStr, string Typestr, + RegisterOperand FGROpnd, + SDPatternOperator Op = null_frag> { + dag OutOperandList = (outs FGRCCOpnd:$fd); + dag InOperandList = (ins FGROpnd:$fs, FGROpnd:$ft); + string AsmString = !strconcat("cmp.", CondStr, ".", Typestr, "\t$fd, $fs, $ft"); + list<dag> Pattern = [(set FGRCCOpnd:$fd, (Op FGROpnd:$fs, FGROpnd:$ft))]; +} + +multiclass CMP_CC_M <FIELD_CMP_FORMAT Format, string Typestr, + RegisterOperand FGROpnd>{ + def CMP_F_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_AF>, + CMP_CONDN_DESC_BASE<"af", Typestr, FGROpnd>, + ISA_MIPS32R6; + def CMP_UN_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_UN>, + CMP_CONDN_DESC_BASE<"un", Typestr, FGROpnd, setuo>, + ISA_MIPS32R6; + def CMP_EQ_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_EQ>, + CMP_CONDN_DESC_BASE<"eq", Typestr, FGROpnd, setoeq>, + ISA_MIPS32R6; + def CMP_UEQ_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_UEQ>, + CMP_CONDN_DESC_BASE<"ueq", Typestr, FGROpnd, setueq>, + ISA_MIPS32R6; + def CMP_LT_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_LT>, + CMP_CONDN_DESC_BASE<"lt", Typestr, FGROpnd, setolt>, + ISA_MIPS32R6; + def CMP_ULT_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_ULT>, + CMP_CONDN_DESC_BASE<"ult", Typestr, FGROpnd, setult>, + ISA_MIPS32R6; + def CMP_LE_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_LE>, + CMP_CONDN_DESC_BASE<"le", Typestr, FGROpnd, setole>, + ISA_MIPS32R6; + def CMP_ULE_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_ULE>, + CMP_CONDN_DESC_BASE<"ule", Typestr, FGROpnd, setule>, + ISA_MIPS32R6; + def CMP_SAF_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SAF>, + CMP_CONDN_DESC_BASE<"saf", Typestr, FGROpnd>, + ISA_MIPS32R6; + def CMP_SUN_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SUN>, + CMP_CONDN_DESC_BASE<"sun", Typestr, FGROpnd>, + ISA_MIPS32R6; + def CMP_SEQ_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SEQ>, + CMP_CONDN_DESC_BASE<"seq", Typestr, FGROpnd>, + ISA_MIPS32R6; + def CMP_SUEQ_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SUEQ>, + CMP_CONDN_DESC_BASE<"sueq", Typestr, FGROpnd>, + ISA_MIPS32R6; + def CMP_SLT_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SLT>, + CMP_CONDN_DESC_BASE<"slt", Typestr, FGROpnd>, + ISA_MIPS32R6; + def CMP_SULT_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SULT>, + CMP_CONDN_DESC_BASE<"sult", Typestr, FGROpnd>, + ISA_MIPS32R6; + def CMP_SLE_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SLE>, + CMP_CONDN_DESC_BASE<"sle", Typestr, FGROpnd>, + ISA_MIPS32R6; + def CMP_SULE_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SULE>, + CMP_CONDN_DESC_BASE<"sule", Typestr, FGROpnd>, + ISA_MIPS32R6; +} + +//===----------------------------------------------------------------------===// +// +// Instruction Descriptions +// +//===----------------------------------------------------------------------===// + +class PCREL_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + Operand ImmOpnd> { + dag OutOperandList = (outs GPROpnd:$rs); + dag InOperandList = (ins ImmOpnd:$imm); + string AsmString = !strconcat(instr_asm, "\t$rs, $imm"); + list<dag> Pattern = []; +} + +class ADDIUPC_DESC : PCREL_DESC_BASE<"addiupc", GPR32Opnd, simm19_lsl2>; +class LWPC_DESC: PCREL_DESC_BASE<"lwpc", GPR32Opnd, simm19_lsl2>; +class LWUPC_DESC: PCREL_DESC_BASE<"lwupc", GPR32Opnd, simm19_lsl2>; + +class ALIGN_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + Operand ImmOpnd> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, ImmOpnd:$bp); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt, $bp"); + list<dag> Pattern = []; +} + +class ALIGN_DESC : ALIGN_DESC_BASE<"align", GPR32Opnd, uimm2>; + +class ALUIPC_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$rs); + dag InOperandList = (ins simm16:$imm); + string AsmString = !strconcat(instr_asm, "\t$rs, $imm"); + list<dag> Pattern = []; +} + +class ALUIPC_DESC : ALUIPC_DESC_BASE<"aluipc", GPR32Opnd>; +class AUIPC_DESC : ALUIPC_DESC_BASE<"auipc", GPR32Opnd>; + +class AUI_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$rs); + dag InOperandList = (ins GPROpnd:$rt, simm16:$imm); + string AsmString = !strconcat(instr_asm, "\t$rs, $rt, $imm"); + list<dag> Pattern = []; +} + +class AUI_DESC : AUI_DESC_BASE<"aui", GPR32Opnd>; + +class BRANCH_DESC_BASE { + bit isBranch = 1; + bit isTerminator = 1; + bit hasDelaySlot = 0; +} + +class BC_DESC_BASE<string instr_asm, DAGOperand opnd> : BRANCH_DESC_BASE { + dag InOperandList = (ins opnd:$offset); + dag OutOperandList = (outs); + string AsmString = !strconcat(instr_asm, "\t$offset"); + bit isBarrier = 1; +} + +class CMP_BC_DESC_BASE<string instr_asm, DAGOperand opnd, + RegisterOperand GPROpnd> : BRANCH_DESC_BASE { + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, opnd:$offset); + dag OutOperandList = (outs); + string AsmString = !strconcat(instr_asm, "\t$rs, $rt, $offset"); + list<Register> Defs = [AT]; +} + +class CMP_CBR_EQNE_Z_DESC_BASE<string instr_asm, DAGOperand opnd, + RegisterOperand GPROpnd> : BRANCH_DESC_BASE { + dag InOperandList = (ins GPROpnd:$rs, opnd:$offset); + dag OutOperandList = (outs); + string AsmString = !strconcat(instr_asm, "\t$rs, $offset"); + list<Register> Defs = [AT]; +} + +class CMP_CBR_RT_Z_DESC_BASE<string instr_asm, DAGOperand opnd, + RegisterOperand GPROpnd> : BRANCH_DESC_BASE { + dag InOperandList = (ins GPROpnd:$rt, opnd:$offset); + dag OutOperandList = (outs); + string AsmString = !strconcat(instr_asm, "\t$rt, $offset"); + list<Register> Defs = [AT]; +} + +class BAL_DESC : BC_DESC_BASE<"bal", brtarget> { + bit isCall = 1; + bit hasDelaySlot = 1; + list<Register> Defs = [RA]; +} + +class BALC_DESC : BC_DESC_BASE<"balc", brtarget26> { + bit isCall = 1; + list<Register> Defs = [RA]; +} + +class BC_DESC : BC_DESC_BASE<"bc", brtarget26>; +class BGEC_DESC : CMP_BC_DESC_BASE<"bgec", brtarget, GPR32Opnd>; +class BGEUC_DESC : CMP_BC_DESC_BASE<"bgeuc", brtarget, GPR32Opnd>; +class BEQC_DESC : CMP_BC_DESC_BASE<"beqc", brtarget, GPR32Opnd>; +class BNEC_DESC : CMP_BC_DESC_BASE<"bnec", brtarget, GPR32Opnd>; + +class BLTC_DESC : CMP_BC_DESC_BASE<"bltc", brtarget, GPR32Opnd>; +class BLTUC_DESC : CMP_BC_DESC_BASE<"bltuc", brtarget, GPR32Opnd>; + +class BLTZC_DESC : CMP_CBR_RT_Z_DESC_BASE<"bltzc", brtarget, GPR32Opnd>; +class BGEZC_DESC : CMP_CBR_RT_Z_DESC_BASE<"bgezc", brtarget, GPR32Opnd>; + +class BLEZC_DESC : CMP_CBR_RT_Z_DESC_BASE<"blezc", brtarget, GPR32Opnd>; +class BGTZC_DESC : CMP_CBR_RT_Z_DESC_BASE<"bgtzc", brtarget, GPR32Opnd>; + +class BEQZC_DESC : CMP_CBR_EQNE_Z_DESC_BASE<"beqzc", brtarget21, GPR32Opnd>; +class BNEZC_DESC : CMP_CBR_EQNE_Z_DESC_BASE<"bnezc", brtarget21, GPR32Opnd>; + +class COP1_BCCZ_DESC_BASE<string instr_asm> : BRANCH_DESC_BASE { + dag InOperandList = (ins FGR64Opnd:$ft, brtarget:$offset); + dag OutOperandList = (outs); + string AsmString = instr_asm; + bit hasDelaySlot = 1; +} + +class BC1EQZ_DESC : COP1_BCCZ_DESC_BASE<"bc1eqz $ft, $offset">; +class BC1NEZ_DESC : COP1_BCCZ_DESC_BASE<"bc1nez $ft, $offset">; + +class COP2_BCCZ_DESC_BASE<string instr_asm> : BRANCH_DESC_BASE { + dag InOperandList = (ins COP2Opnd:$ct, brtarget:$offset); + dag OutOperandList = (outs); + string AsmString = instr_asm; + bit hasDelaySlot = 1; +} + +class BC2EQZ_DESC : COP2_BCCZ_DESC_BASE<"bc2eqz $ct, $offset">; +class BC2NEZ_DESC : COP2_BCCZ_DESC_BASE<"bc2nez $ct, $offset">; + +class BOVC_DESC : CMP_BC_DESC_BASE<"bovc", brtarget, GPR32Opnd>; +class BNVC_DESC : CMP_BC_DESC_BASE<"bnvc", brtarget, GPR32Opnd>; + +class JMP_IDX_COMPACT_DESC_BASE<string opstr, DAGOperand opnd, + RegisterOperand GPROpnd> { + dag InOperandList = (ins GPROpnd:$rt, opnd:$offset); + string AsmString = !strconcat(opstr, "\t$rt, $offset"); + list<dag> Pattern = []; + bit isTerminator = 1; + bit hasDelaySlot = 0; + string DecoderMethod = "DecodeSimm16"; +} + +class JIALC_DESC : JMP_IDX_COMPACT_DESC_BASE<"jialc", calloffset16, + GPR32Opnd> { + bit isCall = 1; + list<Register> Defs = [RA]; +} + +class JIC_DESC : JMP_IDX_COMPACT_DESC_BASE<"jic", jmpoffset16, GPR32Opnd> { + bit isBarrier = 1; + list<Register> Defs = [AT]; +} + +class JR_HB_R6_DESC : JR_HB_DESC_BASE<"jr.hb", GPR32Opnd> { + bit isBranch = 1; + bit isIndirectBranch = 1; + bit hasDelaySlot = 1; + bit isTerminator=1; + bit isBarrier=1; +} + +class BITSWAP_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rt"); + list<dag> Pattern = []; +} + +class BITSWAP_DESC : BITSWAP_DESC_BASE<"bitswap", GPR32Opnd>; + +class DIVMOD_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + SDPatternOperator Op=null_frag> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt"); + list<dag> Pattern = [(set GPROpnd:$rd, (Op GPROpnd:$rs, GPROpnd:$rt))]; + + // This instruction doesn't trap division by zero itself. We must insert + // teq instructions as well. + bit usesCustomInserter = 1; +} + +class DIV_DESC : DIVMOD_DESC_BASE<"div", GPR32Opnd, sdiv>; +class DIVU_DESC : DIVMOD_DESC_BASE<"divu", GPR32Opnd, udiv>; +class MOD_DESC : DIVMOD_DESC_BASE<"mod", GPR32Opnd, srem>; +class MODU_DESC : DIVMOD_DESC_BASE<"modu", GPR32Opnd, urem>; + +class BEQZALC_DESC : CMP_CBR_RT_Z_DESC_BASE<"beqzalc", brtarget, GPR32Opnd> { + list<Register> Defs = [RA]; +} + +class BGEZALC_DESC : CMP_CBR_RT_Z_DESC_BASE<"bgezalc", brtarget, GPR32Opnd> { + list<Register> Defs = [RA]; +} + +class BGTZALC_DESC : CMP_CBR_RT_Z_DESC_BASE<"bgtzalc", brtarget, GPR32Opnd> { + list<Register> Defs = [RA]; +} + +class BLEZALC_DESC : CMP_CBR_RT_Z_DESC_BASE<"blezalc", brtarget, GPR32Opnd> { + list<Register> Defs = [RA]; +} + +class BLTZALC_DESC : CMP_CBR_RT_Z_DESC_BASE<"bltzalc", brtarget, GPR32Opnd> { + list<Register> Defs = [RA]; +} + +class BNEZALC_DESC : CMP_CBR_RT_Z_DESC_BASE<"bnezalc", brtarget, GPR32Opnd> { + list<Register> Defs = [RA]; +} + +class MUL_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + SDPatternOperator Op=null_frag> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt"); + list<dag> Pattern = [(set GPROpnd:$rd, (Op GPROpnd:$rs, GPROpnd:$rt))]; +} + +class MUH_DESC : MUL_R6_DESC_BASE<"muh", GPR32Opnd, mulhs>; +class MUHU_DESC : MUL_R6_DESC_BASE<"muhu", GPR32Opnd, mulhu>; +class MUL_R6_DESC : MUL_R6_DESC_BASE<"mul", GPR32Opnd, mul>; +class MULU_DESC : MUL_R6_DESC_BASE<"mulu", GPR32Opnd>; + +class COP1_SEL_DESC_BASE<string instr_asm, RegisterOperand FGROpnd> { + dag OutOperandList = (outs FGROpnd:$fd); + dag InOperandList = (ins FGRCCOpnd:$fd_in, FGROpnd:$fs, FGROpnd:$ft); + string AsmString = !strconcat(instr_asm, "\t$fd, $fs, $ft"); + list<dag> Pattern = [(set FGROpnd:$fd, (select FGRCCOpnd:$fd_in, + FGROpnd:$ft, + FGROpnd:$fs))]; + string Constraints = "$fd_in = $fd"; +} + +class SEL_D_DESC : COP1_SEL_DESC_BASE<"sel.d", FGR64Opnd> { + // We must insert a SUBREG_TO_REG around $fd_in + bit usesCustomInserter = 1; +} +class SEL_S_DESC : COP1_SEL_DESC_BASE<"sel.s", FGR32Opnd>; + +class SELEQNE_Z_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt"); + list<dag> Pattern = []; +} + +class SELEQZ_DESC : SELEQNE_Z_DESC_BASE<"seleqz", GPR32Opnd>; +class SELNEZ_DESC : SELEQNE_Z_DESC_BASE<"selnez", GPR32Opnd>; + +class COP1_4R_DESC_BASE<string instr_asm, RegisterOperand FGROpnd> { + dag OutOperandList = (outs FGROpnd:$fd); + dag InOperandList = (ins FGROpnd:$fd_in, FGROpnd:$fs, FGROpnd:$ft); + string AsmString = !strconcat(instr_asm, "\t$fd, $fs, $ft"); + list<dag> Pattern = []; + string Constraints = "$fd_in = $fd"; +} + +class MADDF_S_DESC : COP1_4R_DESC_BASE<"maddf.s", FGR32Opnd>; +class MADDF_D_DESC : COP1_4R_DESC_BASE<"maddf.d", FGR64Opnd>; +class MSUBF_S_DESC : COP1_4R_DESC_BASE<"msubf.s", FGR32Opnd>; +class MSUBF_D_DESC : COP1_4R_DESC_BASE<"msubf.d", FGR64Opnd>; + +class MAX_MIN_DESC_BASE<string instr_asm, RegisterOperand FGROpnd> { + dag OutOperandList = (outs FGROpnd:$fd); + dag InOperandList = (ins FGROpnd:$fs, FGROpnd:$ft); + string AsmString = !strconcat(instr_asm, "\t$fd, $fs, $ft"); + list<dag> Pattern = []; +} + +class MAX_S_DESC : MAX_MIN_DESC_BASE<"max.s", FGR32Opnd>; +class MAX_D_DESC : MAX_MIN_DESC_BASE<"max.d", FGR64Opnd>; +class MIN_S_DESC : MAX_MIN_DESC_BASE<"min.s", FGR32Opnd>; +class MIN_D_DESC : MAX_MIN_DESC_BASE<"min.d", FGR64Opnd>; + +class MAXA_S_DESC : MAX_MIN_DESC_BASE<"maxa.s", FGR32Opnd>; +class MAXA_D_DESC : MAX_MIN_DESC_BASE<"maxa.d", FGR64Opnd>; +class MINA_S_DESC : MAX_MIN_DESC_BASE<"mina.s", FGR32Opnd>; +class MINA_D_DESC : MAX_MIN_DESC_BASE<"mina.d", FGR64Opnd>; + +class SELEQNEZ_DESC_BASE<string instr_asm, RegisterOperand FGROpnd> { + dag OutOperandList = (outs FGROpnd:$fd); + dag InOperandList = (ins FGROpnd:$fs, FGROpnd:$ft); + string AsmString = !strconcat(instr_asm, "\t$fd, $fs, $ft"); + list<dag> Pattern = []; +} + +class SELEQZ_S_DESC : SELEQNEZ_DESC_BASE<"seleqz.s", FGR32Opnd>; +class SELEQZ_D_DESC : SELEQNEZ_DESC_BASE<"seleqz.d", FGR64Opnd>; +class SELNEZ_S_DESC : SELEQNEZ_DESC_BASE<"selnez.s", FGR32Opnd>; +class SELNEZ_D_DESC : SELEQNEZ_DESC_BASE<"selnez.d", FGR64Opnd>; + +class CLASS_RINT_DESC_BASE<string instr_asm, RegisterOperand FGROpnd> { + dag OutOperandList = (outs FGROpnd:$fd); + dag InOperandList = (ins FGROpnd:$fs); + string AsmString = !strconcat(instr_asm, "\t$fd, $fs"); + list<dag> Pattern = []; +} + +class RINT_S_DESC : CLASS_RINT_DESC_BASE<"rint.s", FGR32Opnd>; +class RINT_D_DESC : CLASS_RINT_DESC_BASE<"rint.d", FGR64Opnd>; +class CLASS_S_DESC : CLASS_RINT_DESC_BASE<"class.s", FGR32Opnd>; +class CLASS_D_DESC : CLASS_RINT_DESC_BASE<"class.d", FGR64Opnd>; + +class CACHE_HINT_DESC<string instr_asm, Operand MemOpnd, + RegisterOperand GPROpnd> { + dag OutOperandList = (outs); + dag InOperandList = (ins MemOpnd:$addr, uimm5:$hint); + string AsmString = !strconcat(instr_asm, "\t$hint, $addr"); + list<dag> Pattern = []; +} + +class CACHE_DESC : CACHE_HINT_DESC<"cache", mem_simm9, GPR32Opnd>; +class PREF_DESC : CACHE_HINT_DESC<"pref", mem_simm9, GPR32Opnd>; + +class COP2LD_DESC_BASE<string instr_asm, RegisterOperand COPOpnd> { + dag OutOperandList = (outs COPOpnd:$rt); + dag InOperandList = (ins mem_simm11:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + bit mayLoad = 1; +} + +class LDC2_R6_DESC : COP2LD_DESC_BASE<"ldc2", COP2Opnd>; +class LWC2_R6_DESC : COP2LD_DESC_BASE<"lwc2", COP2Opnd>; + +class COP2ST_DESC_BASE<string instr_asm, RegisterOperand COPOpnd> { + dag OutOperandList = (outs); + dag InOperandList = (ins COPOpnd:$rt, mem_simm11:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + bit mayStore = 1; +} + +class SDC2_R6_DESC : COP2ST_DESC_BASE<"sdc2", COP2Opnd>; +class SWC2_R6_DESC : COP2ST_DESC_BASE<"swc2", COP2Opnd>; + +class LSA_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + Operand ImmOpnd> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, ImmOpnd:$imm2); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt, $imm2"); + list<dag> Pattern = []; +} + +class LSA_R6_DESC : LSA_R6_DESC_BASE<"lsa", GPR32Opnd, uimm2>; + +class LL_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$rt); + dag InOperandList = (ins mem_simm9:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + bit mayLoad = 1; +} + +class LL_R6_DESC : LL_R6_DESC_BASE<"ll", GPR32Opnd>; + +class SC_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$dst); + dag InOperandList = (ins GPROpnd:$rt, mem_simm9:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + bit mayStore = 1; + string Constraints = "$rt = $dst"; +} + +class SC_R6_DESC : SC_R6_DESC_BASE<"sc", GPR32Opnd>; + +class CLO_CLZ_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs"); +} + +class CLO_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> : + CLO_CLZ_R6_DESC_BASE<instr_asm, GPROpnd> { + list<dag> Pattern = [(set GPROpnd:$rd, (ctlz (not GPROpnd:$rs)))]; +} + +class CLZ_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> : + CLO_CLZ_R6_DESC_BASE<instr_asm, GPROpnd> { + list<dag> Pattern = [(set GPROpnd:$rd, (ctlz GPROpnd:$rs))]; +} + +class CLO_R6_DESC : CLO_R6_DESC_BASE<"clo", GPR32Opnd>; +class CLZ_R6_DESC : CLZ_R6_DESC_BASE<"clz", GPR32Opnd>; + +class SDBBP_R6_DESC { + dag OutOperandList = (outs); + dag InOperandList = (ins uimm20:$code_); + string AsmString = "sdbbp\t$code_"; + list<dag> Pattern = []; +} + +//===----------------------------------------------------------------------===// +// +// Instruction Definitions +// +//===----------------------------------------------------------------------===// + +def ADDIUPC : ADDIUPC_ENC, ADDIUPC_DESC, ISA_MIPS32R6; +def ALIGN : ALIGN_ENC, ALIGN_DESC, ISA_MIPS32R6; +def ALUIPC : ALUIPC_ENC, ALUIPC_DESC, ISA_MIPS32R6; +def AUI : AUI_ENC, AUI_DESC, ISA_MIPS32R6; +def AUIPC : AUIPC_ENC, AUIPC_DESC, ISA_MIPS32R6; +def BAL : BAL_ENC, BAL_DESC, ISA_MIPS32R6; +def BALC : BALC_ENC, BALC_DESC, ISA_MIPS32R6; +def BC1EQZ : BC1EQZ_ENC, BC1EQZ_DESC, ISA_MIPS32R6; +def BC1NEZ : BC1NEZ_ENC, BC1NEZ_DESC, ISA_MIPS32R6; +def BC2EQZ : BC2EQZ_ENC, BC2EQZ_DESC, ISA_MIPS32R6; +def BC2NEZ : BC2NEZ_ENC, BC2NEZ_DESC, ISA_MIPS32R6; +def BC : BC_ENC, BC_DESC, ISA_MIPS32R6; +def BEQC : BEQC_ENC, BEQC_DESC, ISA_MIPS32R6; +def BEQZALC : BEQZALC_ENC, BEQZALC_DESC, ISA_MIPS32R6; +def BEQZC : BEQZC_ENC, BEQZC_DESC, ISA_MIPS32R6; +def BGEC : BGEC_ENC, BGEC_DESC, ISA_MIPS32R6; +def BGEUC : BGEUC_ENC, BGEUC_DESC, ISA_MIPS32R6; +def BGEZALC : BGEZALC_ENC, BGEZALC_DESC, ISA_MIPS32R6; +def BGEZC : BGEZC_ENC, BGEZC_DESC, ISA_MIPS32R6; +def BGTZALC : BGTZALC_ENC, BGTZALC_DESC, ISA_MIPS32R6; +def BGTZC : BGTZC_ENC, BGTZC_DESC, ISA_MIPS32R6; +def BITSWAP : BITSWAP_ENC, BITSWAP_DESC, ISA_MIPS32R6; +def BLEZALC : BLEZALC_ENC, BLEZALC_DESC, ISA_MIPS32R6; +def BLEZC : BLEZC_ENC, BLEZC_DESC, ISA_MIPS32R6; +def BLTC : BLTC_ENC, BLTC_DESC, ISA_MIPS32R6; +def BLTUC : BLTUC_ENC, BLTUC_DESC, ISA_MIPS32R6; +def BLTZALC : BLTZALC_ENC, BLTZALC_DESC, ISA_MIPS32R6; +def BLTZC : BLTZC_ENC, BLTZC_DESC, ISA_MIPS32R6; +def BNEC : BNEC_ENC, BNEC_DESC, ISA_MIPS32R6; +def BNEZALC : BNEZALC_ENC, BNEZALC_DESC, ISA_MIPS32R6; +def BNEZC : BNEZC_ENC, BNEZC_DESC, ISA_MIPS32R6; +def BNVC : BNVC_ENC, BNVC_DESC, ISA_MIPS32R6; +def BOVC : BOVC_ENC, BOVC_DESC, ISA_MIPS32R6; +def CACHE_R6 : CACHE_ENC, CACHE_DESC, ISA_MIPS32R6; +def CLASS_D : CLASS_D_ENC, CLASS_D_DESC, ISA_MIPS32R6; +def CLASS_S : CLASS_S_ENC, CLASS_S_DESC, ISA_MIPS32R6; +def CLO_R6 : CLO_R6_ENC, CLO_R6_DESC, ISA_MIPS32R6; +def CLZ_R6 : CLZ_R6_ENC, CLZ_R6_DESC, ISA_MIPS32R6; +defm S : CMP_CC_M<FIELD_CMP_FORMAT_S, "s", FGR32Opnd>; +defm D : CMP_CC_M<FIELD_CMP_FORMAT_D, "d", FGR64Opnd>; +def DIV : DIV_ENC, DIV_DESC, ISA_MIPS32R6; +def DIVU : DIVU_ENC, DIVU_DESC, ISA_MIPS32R6; +def JIALC : JIALC_ENC, JIALC_DESC, ISA_MIPS32R6; +def JIC : JIC_ENC, JIC_DESC, ISA_MIPS32R6; +def JR_HB_R6 : JR_HB_R6_ENC, JR_HB_R6_DESC, ISA_MIPS32R6; +def LDC2_R6 : LDC2_R6_ENC, LDC2_R6_DESC, ISA_MIPS32R6; +def LL_R6 : LL_R6_ENC, LL_R6_DESC, ISA_MIPS32R6; +def LSA_R6 : LSA_R6_ENC, LSA_R6_DESC, ISA_MIPS32R6; +def LWC2_R6 : LWC2_R6_ENC, LWC2_R6_DESC, ISA_MIPS32R6; +def LWPC : LWPC_ENC, LWPC_DESC, ISA_MIPS32R6; +def LWUPC : LWUPC_ENC, LWUPC_DESC, ISA_MIPS32R6; +def MADDF_S : MADDF_S_ENC, MADDF_S_DESC, ISA_MIPS32R6; +def MADDF_D : MADDF_D_ENC, MADDF_D_DESC, ISA_MIPS32R6; +def MAXA_D : MAXA_D_ENC, MAXA_D_DESC, ISA_MIPS32R6; +def MAXA_S : MAXA_S_ENC, MAXA_S_DESC, ISA_MIPS32R6; +def MAX_D : MAX_D_ENC, MAX_D_DESC, ISA_MIPS32R6; +def MAX_S : MAX_S_ENC, MAX_S_DESC, ISA_MIPS32R6; +def MINA_D : MINA_D_ENC, MINA_D_DESC, ISA_MIPS32R6; +def MINA_S : MINA_S_ENC, MINA_S_DESC, ISA_MIPS32R6; +def MIN_D : MIN_D_ENC, MIN_D_DESC, ISA_MIPS32R6; +def MIN_S : MIN_S_ENC, MIN_S_DESC, ISA_MIPS32R6; +def MOD : MOD_ENC, MOD_DESC, ISA_MIPS32R6; +def MODU : MODU_ENC, MODU_DESC, ISA_MIPS32R6; +def MSUBF_S : MSUBF_S_ENC, MSUBF_S_DESC, ISA_MIPS32R6; +def MSUBF_D : MSUBF_D_ENC, MSUBF_D_DESC, ISA_MIPS32R6; +def MUH : MUH_ENC, MUH_DESC, ISA_MIPS32R6; +def MUHU : MUHU_ENC, MUHU_DESC, ISA_MIPS32R6; +def MUL_R6 : MUL_R6_ENC, MUL_R6_DESC, ISA_MIPS32R6; +def MULU : MULU_ENC, MULU_DESC, ISA_MIPS32R6; +def NAL; // BAL with rd=0 +def PREF_R6 : PREF_ENC, PREF_DESC, ISA_MIPS32R6; +def RINT_D : RINT_D_ENC, RINT_D_DESC, ISA_MIPS32R6; +def RINT_S : RINT_S_ENC, RINT_S_DESC, ISA_MIPS32R6; +def SC_R6 : SC_R6_ENC, SC_R6_DESC, ISA_MIPS32R6; +def SDBBP_R6 : SDBBP_R6_ENC, SDBBP_R6_DESC, ISA_MIPS32R6; +def SDC2_R6 : SDC2_R6_ENC, SDC2_R6_DESC, ISA_MIPS32R6; +def SELEQZ : SELEQZ_ENC, SELEQZ_DESC, ISA_MIPS32R6, GPR_32; +def SELEQZ_D : SELEQZ_D_ENC, SELEQZ_D_DESC, ISA_MIPS32R6; +def SELEQZ_S : SELEQZ_S_ENC, SELEQZ_S_DESC, ISA_MIPS32R6; +def SELNEZ : SELNEZ_ENC, SELNEZ_DESC, ISA_MIPS32R6, GPR_32; +def SELNEZ_D : SELNEZ_D_ENC, SELNEZ_D_DESC, ISA_MIPS32R6; +def SELNEZ_S : SELNEZ_S_ENC, SELNEZ_S_DESC, ISA_MIPS32R6; +def SEL_D : SEL_D_ENC, SEL_D_DESC, ISA_MIPS32R6; +def SEL_S : SEL_S_ENC, SEL_S_DESC, ISA_MIPS32R6; +def SWC2_R6 : SWC2_R6_ENC, SWC2_R6_DESC, ISA_MIPS32R6; + +//===----------------------------------------------------------------------===// +// +// Instruction Aliases +// +//===----------------------------------------------------------------------===// + +def : MipsInstAlias<"sdbbp", (SDBBP_R6 0)>, ISA_MIPS32R6; +def : MipsInstAlias<"jr $rs", (JALR ZERO, GPR32Opnd:$rs), 1>, ISA_MIPS32R6; + +//===----------------------------------------------------------------------===// +// +// Patterns and Pseudo Instructions +// +//===----------------------------------------------------------------------===// + +// f32 comparisons supported via another comparison +def : MipsPat<(setone f32:$lhs, f32:$rhs), + (NOR (CMP_UEQ_S f32:$lhs, f32:$rhs), ZERO)>, ISA_MIPS32R6; +def : MipsPat<(seto f32:$lhs, f32:$rhs), + (NOR (CMP_UN_S f32:$lhs, f32:$rhs), ZERO)>, ISA_MIPS32R6; +def : MipsPat<(setune f32:$lhs, f32:$rhs), + (NOR (CMP_EQ_S f32:$lhs, f32:$rhs), ZERO)>, ISA_MIPS32R6; +def : MipsPat<(seteq f32:$lhs, f32:$rhs), (CMP_EQ_S f32:$lhs, f32:$rhs)>, + ISA_MIPS32R6; +def : MipsPat<(setgt f32:$lhs, f32:$rhs), (CMP_LE_S f32:$rhs, f32:$lhs)>, + ISA_MIPS32R6; +def : MipsPat<(setge f32:$lhs, f32:$rhs), (CMP_LT_S f32:$rhs, f32:$lhs)>, + ISA_MIPS32R6; +def : MipsPat<(setlt f32:$lhs, f32:$rhs), (CMP_LT_S f32:$lhs, f32:$rhs)>, + ISA_MIPS32R6; +def : MipsPat<(setlt f32:$lhs, f32:$rhs), (CMP_LE_S f32:$lhs, f32:$rhs)>, + ISA_MIPS32R6; +def : MipsPat<(setne f32:$lhs, f32:$rhs), + (NOR (CMP_EQ_S f32:$lhs, f32:$rhs), ZERO)>, ISA_MIPS32R6; + +// f64 comparisons supported via another comparison +def : MipsPat<(setone f64:$lhs, f64:$rhs), + (NOR (CMP_UEQ_D f64:$lhs, f64:$rhs), ZERO)>, ISA_MIPS32R6; +def : MipsPat<(seto f64:$lhs, f64:$rhs), + (NOR (CMP_UN_D f64:$lhs, f64:$rhs), ZERO)>, ISA_MIPS32R6; +def : MipsPat<(setune f64:$lhs, f64:$rhs), + (NOR (CMP_EQ_D f64:$lhs, f64:$rhs), ZERO)>, ISA_MIPS32R6; +def : MipsPat<(seteq f64:$lhs, f64:$rhs), (CMP_EQ_D f64:$lhs, f64:$rhs)>, + ISA_MIPS32R6; +def : MipsPat<(setgt f64:$lhs, f64:$rhs), (CMP_LE_D f64:$rhs, f64:$lhs)>, + ISA_MIPS32R6; +def : MipsPat<(setge f64:$lhs, f64:$rhs), (CMP_LT_D f64:$rhs, f64:$lhs)>, + ISA_MIPS32R6; +def : MipsPat<(setlt f64:$lhs, f64:$rhs), (CMP_LT_D f64:$lhs, f64:$rhs)>, + ISA_MIPS32R6; +def : MipsPat<(setlt f64:$lhs, f64:$rhs), (CMP_LE_D f64:$lhs, f64:$rhs)>, + ISA_MIPS32R6; +def : MipsPat<(setne f64:$lhs, f64:$rhs), + (NOR (CMP_EQ_D f64:$lhs, f64:$rhs), ZERO)>, ISA_MIPS32R6; + +// i32 selects +def : MipsPat<(select i32:$cond, i32:$t, i32:$f), + (OR (SELNEZ i32:$t, i32:$cond), (SELEQZ i32:$f, i32:$cond))>, + ISA_MIPS32R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immz)), i32:$t, i32:$f), + (OR (SELEQZ i32:$t, i32:$cond), (SELNEZ i32:$f, i32:$cond))>, + ISA_MIPS32R6; +def : MipsPat<(select (i32 (setne i32:$cond, immz)), i32:$t, i32:$f), + (OR (SELNEZ i32:$t, i32:$cond), (SELEQZ i32:$f, i32:$cond))>, + ISA_MIPS32R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immZExt16:$imm)), i32:$t, i32:$f), + (OR (SELEQZ i32:$t, (XORi i32:$cond, immZExt16:$imm)), + (SELNEZ i32:$f, (XORi i32:$cond, immZExt16:$imm)))>, + ISA_MIPS32R6; +def : MipsPat<(select (i32 (setne i32:$cond, immZExt16:$imm)), i32:$t, i32:$f), + (OR (SELNEZ i32:$t, (XORi i32:$cond, immZExt16:$imm)), + (SELEQZ i32:$f, (XORi i32:$cond, immZExt16:$imm)))>, + ISA_MIPS32R6; +def : MipsPat<(select (i32 (setgt i32:$cond, immSExt16Plus1:$imm)), i32:$t, + i32:$f), + (OR (SELEQZ i32:$t, (SLTi i32:$cond, (Plus1 imm:$imm))), + (SELNEZ i32:$f, (SLTi i32:$cond, (Plus1 imm:$imm))))>, + ISA_MIPS32R6; +def : MipsPat<(select (i32 (setugt i32:$cond, immSExt16Plus1:$imm)), + i32:$t, i32:$f), + (OR (SELEQZ i32:$t, (SLTiu i32:$cond, (Plus1 imm:$imm))), + (SELNEZ i32:$f, (SLTiu i32:$cond, (Plus1 imm:$imm))))>, + ISA_MIPS32R6; + +def : MipsPat<(select i32:$cond, i32:$t, immz), + (SELNEZ i32:$t, i32:$cond)>, ISA_MIPS32R6; +def : MipsPat<(select (i32 (setne i32:$cond, immz)), i32:$t, immz), + (SELNEZ i32:$t, i32:$cond)>, ISA_MIPS32R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immz)), i32:$t, immz), + (SELEQZ i32:$t, i32:$cond)>, ISA_MIPS32R6; +def : MipsPat<(select i32:$cond, immz, i32:$f), + (SELEQZ i32:$f, i32:$cond)>, ISA_MIPS32R6; +def : MipsPat<(select (i32 (setne i32:$cond, immz)), immz, i32:$f), + (SELEQZ i32:$f, i32:$cond)>, ISA_MIPS32R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immz)), immz, i32:$f), + (SELNEZ i32:$f, i32:$cond)>, ISA_MIPS32R6; diff --git a/lib/Target/Mips/Mips64InstrInfo.td b/lib/Target/Mips/Mips64InstrInfo.td index 15ef654555d6..f0b6814e37cc 100644 --- a/lib/Target/Mips/Mips64InstrInfo.td +++ b/lib/Target/Mips/Mips64InstrInfo.td @@ -20,6 +20,11 @@ def uimm16_64 : Operand<i64> { let PrintMethod = "printUnsignedImm"; } +// Signed Operand +def simm10_64 : Operand<i64>; + +def imm64: Operand<i64>; + // Transformation Function - get Imm - 32. def Subtract32 : SDNodeXForm<imm, [{ return getImm(N, (unsigned)N->getZExtValue() - 32); @@ -28,6 +33,14 @@ def Subtract32 : SDNodeXForm<imm, [{ // shamt must fit in 6 bits. def immZExt6 : ImmLeaf<i32, [{return Imm == (Imm & 0x3f);}]>; +// Node immediate fits as 10-bit sign extended on target immediate. +// e.g. seqi, snei +def immSExt10_64 : PatLeaf<(i64 imm), + [{ return isInt<10>(N->getSExtValue()); }]>; + +def immZExt16_64 : PatLeaf<(i64 imm), + [{ return isInt<16>(N->getZExtValue()); }]>; + //===----------------------------------------------------------------------===// // Instructions specific format //===----------------------------------------------------------------------===// @@ -53,153 +66,176 @@ let isPseudo = 1, isCodeGenOnly = 1 in { //===----------------------------------------------------------------------===// 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, +def DADDi : ArithLogicI<"daddi", simm16_64, GPR64Opnd>, ADDI_FM<0x18>, + ISA_MIPS3_NOT_32R6_64R6; +def DADDiu : ArithLogicI<"daddiu", simm16_64, GPR64Opnd, II_DADDIU, immSExt16, add>, - ADDI_FM<0x19>, IsAsCheapAsAMove; + ADDI_FM<0x19>, IsAsCheapAsAMove, ISA_MIPS3; 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>, +def ANDi64 : ArithLogicI<"andi", uimm16_64, GPR64Opnd, II_AND, immZExt16, and>, ADDI_FM<0xc>; -def ORi64 : ArithLogicI<"ori", uimm16_64, GPR64Opnd, IILogic, immZExt16, - or>, +def ORi64 : ArithLogicI<"ori", uimm16_64, GPR64Opnd, II_OR, immZExt16, or>, ADDI_FM<0xd>; -def XORi64 : ArithLogicI<"xori", uimm16_64, GPR64Opnd, IILogic, immZExt16, - xor>, +def XORi64 : ArithLogicI<"xori", uimm16_64, GPR64Opnd, II_XOR, 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>; +def DADD : ArithLogicR<"dadd", GPR64Opnd, 1, II_DADD>, ADD_FM<0, 0x2c>, + ISA_MIPS3; +def DADDu : ArithLogicR<"daddu", GPR64Opnd, 1, II_DADDU, add>, ADD_FM<0, 0x2d>, + ISA_MIPS3; +def DSUBu : ArithLogicR<"dsubu", GPR64Opnd, 0, II_DSUBU, sub>, ADD_FM<0, 0x2f>, + ISA_MIPS3; +def DSUB : ArithLogicR<"dsub", GPR64Opnd, 0, II_DSUB>, ADD_FM<0, 0x2e>, + ISA_MIPS3; 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 AND64 : ArithLogicR<"and", GPR64Opnd, 1, II_AND, and>, ADD_FM<0, 0x24>; +def OR64 : ArithLogicR<"or", GPR64Opnd, 1, II_OR, or>, ADD_FM<0, 0x25>; +def XOR64 : ArithLogicR<"xor", GPR64Opnd, 1, II_XOR, 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>; +def DSLL : shift_rotate_imm<"dsll", uimm6, GPR64Opnd, II_DSLL, shl, immZExt6>, + SRA_FM<0x38, 0>, ISA_MIPS3; +def DSRL : shift_rotate_imm<"dsrl", uimm6, GPR64Opnd, II_DSRL, srl, immZExt6>, + SRA_FM<0x3a, 0>, ISA_MIPS3; +def DSRA : shift_rotate_imm<"dsra", uimm6, GPR64Opnd, II_DSRA, sra, immZExt6>, + SRA_FM<0x3b, 0>, ISA_MIPS3; +def DSLLV : shift_rotate_reg<"dsllv", GPR64Opnd, II_DSLLV, shl>, + SRLV_FM<0x14, 0>, ISA_MIPS3; +def DSRLV : shift_rotate_reg<"dsrlv", GPR64Opnd, II_DSRLV, srl>, + SRLV_FM<0x16, 0>, ISA_MIPS3; +def DSRAV : shift_rotate_reg<"dsrav", GPR64Opnd, II_DSRAV, sra>, + SRLV_FM<0x17, 0>, ISA_MIPS3; +def DSLL32 : shift_rotate_imm<"dsll32", uimm5, GPR64Opnd, II_DSLL32>, + SRA_FM<0x3c, 0>, ISA_MIPS3; +def DSRL32 : shift_rotate_imm<"dsrl32", uimm5, GPR64Opnd, II_DSRL32>, + SRA_FM<0x3e, 0>, ISA_MIPS3; +def DSRA32 : shift_rotate_imm<"dsra32", uimm5, GPR64Opnd, II_DSRA32>, + SRA_FM<0x3f, 0>, ISA_MIPS3; // 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>; -} +def DROTR : shift_rotate_imm<"drotr", uimm6, GPR64Opnd, II_DROTR, rotr, + immZExt6>, + SRA_FM<0x3a, 1>, ISA_MIPS64R2; +def DROTRV : shift_rotate_reg<"drotrv", GPR64Opnd, II_DROTRV, rotr>, + SRLV_FM<0x16, 1>, ISA_MIPS64R2; +def DROTR32 : shift_rotate_imm<"drotr32", uimm5, GPR64Opnd, II_DROTR32>, + SRA_FM<0x3e, 1>, ISA_MIPS64R2; /// 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 LB64 : Load<"lb", GPR64Opnd, sextloadi8, II_LB>, LW_FM<0x20>; +def LBu64 : Load<"lbu", GPR64Opnd, zextloadi8, II_LBU>, LW_FM<0x24>; +def LH64 : Load<"lh", GPR64Opnd, sextloadi16, II_LH>, LW_FM<0x21>; +def LHu64 : Load<"lhu", GPR64Opnd, zextloadi16, II_LHU>, LW_FM<0x25>; +def LW64 : Load<"lw", GPR64Opnd, sextloadi32, II_LW>, LW_FM<0x23>; +def SB64 : Store<"sb", GPR64Opnd, truncstorei8, II_SB>, LW_FM<0x28>; +def SH64 : Store<"sh", GPR64Opnd, truncstorei16, II_SH>, LW_FM<0x29>; +def SW64 : Store<"sw", GPR64Opnd, truncstorei32, II_SW>, 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>; +def LWu : Load<"lwu", GPR64Opnd, zextloadi32, II_LWU>, LW_FM<0x27>, ISA_MIPS3; +def LD : Load<"ld", GPR64Opnd, load, II_LD>, LW_FM<0x37>, ISA_MIPS3; +def SD : Store<"sd", GPR64Opnd, store, II_SD>, LW_FM<0x3f>, ISA_MIPS3; /// 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 LWL64 : LoadLeftRight<"lwl", MipsLWL, GPR64Opnd, II_LWL>, LW_FM<0x22>; +def LWR64 : LoadLeftRight<"lwr", MipsLWR, GPR64Opnd, II_LWR>, LW_FM<0x26>; +def SWL64 : StoreLeftRight<"swl", MipsSWL, GPR64Opnd, II_SWL>, LW_FM<0x2a>; +def SWR64 : StoreLeftRight<"swr", MipsSWR, GPR64Opnd, II_SWR>, 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>; +def LDL : LoadLeftRight<"ldl", MipsLDL, GPR64Opnd, II_LDL>, LW_FM<0x1a>, + ISA_MIPS3_NOT_32R6_64R6; +def LDR : LoadLeftRight<"ldr", MipsLDR, GPR64Opnd, II_LDR>, LW_FM<0x1b>, + ISA_MIPS3_NOT_32R6_64R6; +def SDL : StoreLeftRight<"sdl", MipsSDL, GPR64Opnd, II_SDL>, LW_FM<0x2c>, + ISA_MIPS3_NOT_32R6_64R6; +def SDR : StoreLeftRight<"sdr", MipsSDR, GPR64Opnd, II_SDR>, LW_FM<0x2d>, + ISA_MIPS3_NOT_32R6_64R6; /// Load-linked, Store-conditional -def LLD : LLBase<"lld", GPR64Opnd>, LW_FM<0x34>; -def SCD : SCBase<"scd", GPR64Opnd>, LW_FM<0x3c>; +def LLD : LLBase<"lld", GPR64Opnd>, LW_FM<0x34>, ISA_MIPS3_NOT_32R6_64R6; +def SCD : SCBase<"scd", GPR64Opnd>, LW_FM<0x3c>, ISA_MIPS3_NOT_32R6_64R6; /// 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; + 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 : TailCallReg<GPR64Opnd, JR, GPR32Opnd>; } +def PseudoReturn64 : PseudoReturnBase<GPR64Opnd>; +def PseudoIndirectBranch64 : PseudoIndirectBranchBase<GPR64Opnd>; + /// 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 DMULT : Mult<"dmult", II_DMULT, GPR64Opnd, [HI0_64, LO0_64]>, + MULT_FM<0, 0x1c>, ISA_MIPS3_NOT_32R6_64R6; +def DMULTu : Mult<"dmultu", II_DMULTU, GPR64Opnd, [HI0_64, LO0_64]>, + MULT_FM<0, 0x1d>, ISA_MIPS3_NOT_32R6_64R6; def PseudoDMULT : MultDivPseudo<DMULT, ACC128, GPR64Opnd, MipsMult, - IIImult>; + II_DMULT>, ISA_MIPS3_NOT_32R6_64R6; 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>; + II_DMULTU>, ISA_MIPS3_NOT_32R6_64R6; +def DSDIV : Div<"ddiv", II_DDIV, GPR64Opnd, [HI0_64, LO0_64]>, + MULT_FM<0, 0x1e>, ISA_MIPS3_NOT_32R6_64R6; +def DUDIV : Div<"ddivu", II_DDIVU, GPR64Opnd, [HI0_64, LO0_64]>, + MULT_FM<0, 0x1f>, ISA_MIPS3_NOT_32R6_64R6; def PseudoDSDIV : MultDivPseudo<DSDIV, ACC128, GPR64Opnd, MipsDivRem, - IIIdiv, 0, 1, 1>; + II_DDIV, 0, 1, 1>, ISA_MIPS3_NOT_32R6_64R6; def PseudoDUDIV : MultDivPseudo<DUDIV, ACC128, GPR64Opnd, MipsDivRemU, - IIIdiv, 0, 1, 1>; + II_DDIVU, 0, 1, 1>, ISA_MIPS3_NOT_32R6_64R6; 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>; +def MTHI64 : MoveToLOHI<"mthi", GPR64Opnd, [HI0_64]>, MTLO_FM<0x11>, + ISA_MIPS3_NOT_32R6_64R6; +def MTLO64 : MoveToLOHI<"mtlo", GPR64Opnd, [LO0_64]>, MTLO_FM<0x13>, + ISA_MIPS3_NOT_32R6_64R6; +def MFHI64 : MoveFromLOHI<"mfhi", GPR64Opnd, AC0_64>, MFLO_FM<0x10>, + ISA_MIPS3_NOT_32R6_64R6; +def MFLO64 : MoveFromLOHI<"mflo", GPR64Opnd, AC0_64>, MFLO_FM<0x12>, + ISA_MIPS3_NOT_32R6_64R6; +def PseudoMFHI64 : PseudoMFLOHI<GPR64, ACC128, MipsMFHI>, + ISA_MIPS3_NOT_32R6_64R6; +def PseudoMFLO64 : PseudoMFLOHI<GPR64, ACC128, MipsMFLO>, + ISA_MIPS3_NOT_32R6_64R6; +def PseudoMTLOHI64 : PseudoMTLOHI<ACC128, GPR64>, ISA_MIPS3_NOT_32R6_64R6; /// 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>; +def SEB64 : SignExtInReg<"seb", i8, GPR64Opnd, II_SEB>, SEB_FM<0x10, 0x20>, + ISA_MIPS32R2; +def SEH64 : SignExtInReg<"seh", i16, GPR64Opnd, II_SEH>, SEB_FM<0x18, 0x20>, + ISA_MIPS32R2; } /// Count Leading -def DCLZ : CountLeading0<"dclz", GPR64Opnd>, CLO_FM<0x24>; -def DCLO : CountLeading1<"dclo", GPR64Opnd>, CLO_FM<0x25>; +def DCLZ : CountLeading0<"dclz", GPR64Opnd>, CLO_FM<0x24>, ISA_MIPS64_NOT_64R6; +def DCLO : CountLeading1<"dclo", GPR64Opnd>, CLO_FM<0x25>, ISA_MIPS64_NOT_64R6; /// Double Word Swap Bytes/HalfWords -def DSBH : SubwordSwap<"dsbh", GPR64Opnd>, SEB_FM<2, 0x24>; -def DSHD : SubwordSwap<"dshd", GPR64Opnd>, SEB_FM<5, 0x24>; +def DSBH : SubwordSwap<"dsbh", GPR64Opnd>, SEB_FM<2, 0x24>, ISA_MIPS64R2; +def DSHD : SubwordSwap<"dshd", GPR64Opnd>, SEB_FM<5, 0x24>, ISA_MIPS64R2; def LEA_ADDiu64 : EffectiveAddress<"daddiu", GPR64Opnd>, LW_FM<0x19>; @@ -216,24 +252,122 @@ 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>; + "dsll\t$rd, $rt, 32", [], II_DSLL>; def SLL64_32 : FR<0x0, 0x00, (outs GPR64:$rd), (ins GPR32:$rt), - "sll\t$rd, $rt, 0", [], IIArith>; + "sll\t$rd, $rt, 0", [], II_SLL>; def SLL64_64 : FR<0x0, 0x00, (outs GPR64:$rd), (ins GPR64:$rt), - "sll\t$rd, $rt, 0", [], IIArith>; + "sll\t$rd, $rt, 0", [], II_SLL>; } + +// We need the following pseudo instruction to avoid offset calculation for +// long branches. See the comment in file MipsLongBranch.cpp for detailed +// explanation. + +// Expands to: daddiu $dst, $src, %PART($tgt - $baltgt) +// where %PART may be %hi or %lo, depending on the relocation kind +// that $tgt is annotated with. +def LONG_BRANCH_DADDiu : PseudoSE<(outs GPR64Opnd:$dst), + (ins GPR64Opnd:$src, brtarget:$tgt, brtarget:$baltgt), []>; + +// Cavium Octeon cmMIPS instructions +let EncodingPredicates = []<Predicate>, // FIXME: The lack of HasStdEnc is probably a bug + AdditionalPredicates = [HasCnMips] in { + +class Count1s<string opstr, RegisterOperand RO>: + InstSE<(outs RO:$rd), (ins RO:$rs), !strconcat(opstr, "\t$rd, $rs"), + [(set RO:$rd, (ctpop RO:$rs))], II_POP, FrmR, opstr> { + let TwoOperandAliasConstraint = "$rd = $rs"; +} + +class ExtsCins<string opstr, SDPatternOperator Op = null_frag>: + InstSE<(outs GPR64Opnd:$rt), (ins GPR64Opnd:$rs, uimm5:$pos, uimm5:$lenm1), + !strconcat(opstr, " $rt, $rs, $pos, $lenm1"), + [(set GPR64Opnd:$rt, (Op GPR64Opnd:$rs, imm:$pos, imm:$lenm1))], + NoItinerary, FrmR, opstr> { + let TwoOperandAliasConstraint = "$rt = $rs"; +} + +class SetCC64_R<string opstr, PatFrag cond_op> : + InstSE<(outs GPR64Opnd:$rd), (ins GPR64Opnd:$rs, GPR64Opnd:$rt), + !strconcat(opstr, "\t$rd, $rs, $rt"), + [(set GPR64Opnd:$rd, (cond_op GPR64Opnd:$rs, GPR64Opnd:$rt))], + II_SEQ_SNE, FrmR, opstr> { + let TwoOperandAliasConstraint = "$rd = $rs"; +} + +class SetCC64_I<string opstr, PatFrag cond_op>: + InstSE<(outs GPR64Opnd:$rt), (ins GPR64Opnd:$rs, simm10_64:$imm10), + !strconcat(opstr, "\t$rt, $rs, $imm10"), + [(set GPR64Opnd:$rt, (cond_op GPR64Opnd:$rs, immSExt10_64:$imm10))], + II_SEQI_SNEI, FrmI, opstr> { + let TwoOperandAliasConstraint = "$rt = $rs"; } + +// Unsigned Byte Add +let Pattern = [(set GPR64Opnd:$rd, + (and (add GPR64Opnd:$rs, GPR64Opnd:$rt), 255))] in +def BADDu : ArithLogicR<"baddu", GPR64Opnd, 1, II_BADDU>, + ADD_FM<0x1c, 0x28>; + +// Multiply Doubleword to GPR +let Defs = [HI0, LO0, P0, P1, P2] in +def DMUL : ArithLogicR<"dmul", GPR64Opnd, 1, II_DMUL, mul>, + ADD_FM<0x1c, 0x03>; + +// Extract a signed bit field /+32 +def EXTS : ExtsCins<"exts">, EXTS_FM<0x3a>; +def EXTS32: ExtsCins<"exts32">, EXTS_FM<0x3b>; + +// Clear and insert a bit field /+32 +def CINS : ExtsCins<"cins">, EXTS_FM<0x32>; +def CINS32: ExtsCins<"cins32">, EXTS_FM<0x33>; + +// Move to multiplier/product register +def MTM0 : MoveToLOHI<"mtm0", GPR64Opnd, [MPL0, P0, P1, P2]>, MTMR_FM<0x08>; +def MTM1 : MoveToLOHI<"mtm1", GPR64Opnd, [MPL1, P0, P1, P2]>, MTMR_FM<0x0c>; +def MTM2 : MoveToLOHI<"mtm2", GPR64Opnd, [MPL2, P0, P1, P2]>, MTMR_FM<0x0d>; +def MTP0 : MoveToLOHI<"mtp0", GPR64Opnd, [P0]>, MTMR_FM<0x09>; +def MTP1 : MoveToLOHI<"mtp1", GPR64Opnd, [P1]>, MTMR_FM<0x0a>; +def MTP2 : MoveToLOHI<"mtp2", GPR64Opnd, [P2]>, MTMR_FM<0x0b>; + +// Count Ones in a Word/Doubleword +def POP : Count1s<"pop", GPR32Opnd>, POP_FM<0x2c>; +def DPOP : Count1s<"dpop", GPR64Opnd>, POP_FM<0x2d>; + +// Set on equal/not equal +def SEQ : SetCC64_R<"seq", seteq>, SEQ_FM<0x2a>; +def SEQi : SetCC64_I<"seqi", seteq>, SEQI_FM<0x2e>; +def SNE : SetCC64_R<"sne", setne>, SEQ_FM<0x2b>; +def SNEi : SetCC64_I<"snei", setne>, SEQI_FM<0x2f>; + +// 192-bit x 64-bit Unsigned Multiply and Add +let Defs = [P0, P1, P2] in +def V3MULU: ArithLogicR<"v3mulu", GPR64Opnd, 0, II_DMUL>, + ADD_FM<0x1c, 0x11>; + +// 64-bit Unsigned Multiply and Add Move +let Defs = [MPL0, P0, P1, P2] in +def VMM0 : ArithLogicR<"vmm0", GPR64Opnd, 0, II_DMUL>, + ADD_FM<0x1c, 0x10>; + +// 64-bit Unsigned Multiply and Add +let Defs = [MPL1, MPL2, P0, P1, P2] in +def VMULU : ArithLogicR<"vmulu", GPR64Opnd, 0, II_DMUL>, + ADD_FM<0x1c, 0x0f>; + +} + +} + //===----------------------------------------------------------------------===// // 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)>; -} +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)>; @@ -286,8 +420,7 @@ defm : SetgeImmPats<GPR64, SLTi64, SLTiu64>; // truncate def : MipsPat<(i32 (trunc GPR64:$src)), - (SLL (EXTRACT_SUBREG GPR64:$src, sub_32), 0)>, - Requires<[HasStdEnc]>; + (SLL (EXTRACT_SUBREG GPR64:$src, sub_32), 0)>; // 32-to-64-bit extension def : MipsPat<(i64 (anyext GPR32:$src)), (SLL64_32 GPR32:$src)>; @@ -304,27 +437,76 @@ 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>; +def : MipsInstAlias<"move $dst, $src", + (DADDu GPR64Opnd:$dst, GPR64Opnd:$src, ZERO_64), 1>, + GPR_64; +def : MipsInstAlias<"daddu $rs, $rt, $imm", + (DADDiu GPR64Opnd:$rs, GPR64Opnd:$rt, simm16_64:$imm), + 0>; +def : MipsInstAlias<"dadd $rs, $rt, $imm", + (DADDi GPR64Opnd:$rs, GPR64Opnd:$rt, simm16_64:$imm), + 0>, ISA_MIPS3_NOT_32R6_64R6; +def : MipsInstAlias<"daddu $rs, $imm", + (DADDiu GPR64Opnd:$rs, GPR64Opnd:$rs, simm16_64:$imm), + 0>; +def : MipsInstAlias<"dadd $rs, $imm", + (DADDi GPR64Opnd:$rs, GPR64Opnd:$rs, simm16_64:$imm), + 0>, ISA_MIPS3_NOT_32R6_64R6; +def : MipsInstAlias<"add $rs, $imm", + (ADDi GPR32Opnd:$rs, GPR32Opnd:$rs, simm16:$imm), + 0>; +def : MipsInstAlias<"addu $rs, $imm", + (ADDiu GPR32Opnd:$rs, GPR32Opnd:$rs, simm16:$imm), + 0>; +def : MipsInstAlias<"dsll $rd, $rt, $rs", + (DSLLV GPR64Opnd:$rd, GPR64Opnd:$rt, GPR32Opnd:$rs), 0>, + ISA_MIPS3; +def : MipsInstAlias<"dsubu $rt, $rs, $imm", + (DADDiu GPR64Opnd:$rt, GPR64Opnd:$rs, + InvertedImOperand64:$imm), 0>; +def : MipsInstAlias<"dsubi $rs, $rt, $imm", + (DADDi GPR64Opnd:$rs, GPR64Opnd:$rt, + InvertedImOperand64:$imm), + 0>, ISA_MIPS3_NOT_32R6_64R6; +def : MipsInstAlias<"dsubi $rs, $imm", + (DADDi GPR64Opnd:$rs, GPR64Opnd:$rs, + InvertedImOperand64:$imm), + 0>, ISA_MIPS3_NOT_32R6_64R6; +def : MipsInstAlias<"dsub $rs, $rt, $imm", + (DADDi GPR64Opnd:$rs, GPR64Opnd:$rt, + InvertedImOperand64:$imm), + 0>, ISA_MIPS3_NOT_32R6_64R6; +def : MipsInstAlias<"dsub $rs, $imm", + (DADDi GPR64Opnd:$rs, GPR64Opnd:$rs, + InvertedImOperand64:$imm), + 0>, ISA_MIPS3_NOT_32R6_64R6; +def : MipsInstAlias<"dsubu $rs, $imm", + (DADDiu GPR64Opnd:$rs, GPR64Opnd:$rs, + InvertedImOperand64:$imm), + 0>; +def : MipsInstAlias<"dsra $rd, $rt, $rs", + (DSRAV GPR64Opnd:$rd, GPR64Opnd:$rt, GPR32Opnd:$rs), 0>, + ISA_MIPS3; +def : MipsInstAlias<"dsrl $rd, $rt, $rs", + (DSRLV GPR64Opnd:$rd, GPR64Opnd:$rt, GPR32Opnd:$rs), 0>, + ISA_MIPS3; + +class LoadImm64< string instr_asm, Operand Od, RegisterOperand RO> : + MipsAsmPseudoInst<(outs RO:$rt), (ins Od:$imm64), + !strconcat(instr_asm, "\t$rt, $imm64")> ; +def LoadImm64Reg : LoadImm64<"dli", imm64, GPR64Opnd>; /// 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>; +def DMTC0 : MFC3OP<"dmtc0", GPR64Opnd>, MFC3OP_FM<0x10, 5>, ISA_MIPS3; +def DMFC2 : MFC3OP<"dmfc2", GPR64Opnd>, MFC3OP_FM<0x12, 1>, ISA_MIPS3; +def DMTC2 : MFC3OP<"dmtc2", GPR64Opnd>, MFC3OP_FM<0x12, 5>, ISA_MIPS3; } // 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>; +def : MipsInstAlias<"dmfc0 $rt, $rd", (DMFC0 GPR64Opnd:$rt, GPR64Opnd:$rd, 0), 0>; +def : MipsInstAlias<"dmtc0 $rt, $rd", (DMTC0 GPR64Opnd:$rt, GPR64Opnd:$rd, 0), 0>; +def : MipsInstAlias<"dmfc2 $rt, $rd", (DMFC2 GPR64Opnd:$rt, GPR64Opnd:$rd, 0), 0>; +def : MipsInstAlias<"dmtc2 $rt, $rd", (DMTC2 GPR64Opnd:$rt, GPR64Opnd:$rd, 0), 0>; diff --git a/lib/Target/Mips/Mips64r6InstrInfo.td b/lib/Target/Mips/Mips64r6InstrInfo.td new file mode 100644 index 000000000000..6b546e864bd3 --- /dev/null +++ b/lib/Target/Mips/Mips64r6InstrInfo.td @@ -0,0 +1,217 @@ +//=- Mips64r6InstrInfo.td - Mips64r6 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 Mips64r6 instructions. +// +//===----------------------------------------------------------------------===// + +// Notes about removals/changes from MIPS32r6: +// Reencoded: dclo, dclz + +//===----------------------------------------------------------------------===// +// +// Instruction Encodings +// +//===----------------------------------------------------------------------===// + +class DALIGN_ENC : SPECIAL3_DALIGN_FM<OPCODE6_DALIGN>; +class DAUI_ENC : DAUI_FM; +class DAHI_ENC : REGIMM_FM<OPCODE5_DAHI>; +class DATI_ENC : REGIMM_FM<OPCODE5_DATI>; +class DBITSWAP_ENC : SPECIAL3_2R_FM<OPCODE6_DBITSWAP>; +class DCLO_R6_ENC : SPECIAL_2R_FM<OPCODE6_DCLO>; +class DCLZ_R6_ENC : SPECIAL_2R_FM<OPCODE6_DCLZ>; +class DDIV_ENC : SPECIAL_3R_FM<0b00010, 0b011110>; +class DDIVU_ENC : SPECIAL_3R_FM<0b00010, 0b011111>; +class DLSA_R6_ENC : SPECIAL_LSA_FM<OPCODE6_DLSA>; +class DMOD_ENC : SPECIAL_3R_FM<0b00011, 0b011110>; +class DMODU_ENC : SPECIAL_3R_FM<0b00011, 0b011111>; +class DMUH_ENC : SPECIAL_3R_FM<0b00011, 0b011100>; +class DMUHU_ENC : SPECIAL_3R_FM<0b00011, 0b011101>; +class DMUL_R6_ENC : SPECIAL_3R_FM<0b00010, 0b011100>; +class DMULU_ENC : SPECIAL_3R_FM<0b00010, 0b011101>; +class LDPC_ENC : PCREL18_FM<OPCODE3_LDPC>; +class LLD_R6_ENC : SPECIAL3_LL_SC_FM<OPCODE6_LLD>; +class SCD_R6_ENC : SPECIAL3_LL_SC_FM<OPCODE6_SCD>; + +//===----------------------------------------------------------------------===// +// +// Instruction Descriptions +// +//===----------------------------------------------------------------------===// + +class AHI_ATI_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$rs); + dag InOperandList = (ins GPROpnd:$rt, simm16:$imm); + string AsmString = !strconcat(instr_asm, "\t$rt, $imm"); + string Constraints = "$rs = $rt"; +} + +class DALIGN_DESC : ALIGN_DESC_BASE<"dalign", GPR64Opnd, uimm3>; +class DAHI_DESC : AHI_ATI_DESC_BASE<"dahi", GPR64Opnd>; +class DATI_DESC : AHI_ATI_DESC_BASE<"dati", GPR64Opnd>; +class DAUI_DESC : AUI_DESC_BASE<"daui", GPR64Opnd>; +class DBITSWAP_DESC : BITSWAP_DESC_BASE<"dbitswap", GPR64Opnd>; +class DCLO_R6_DESC : CLO_R6_DESC_BASE<"dclo", GPR64Opnd>; +class DCLZ_R6_DESC : CLZ_R6_DESC_BASE<"dclz", GPR64Opnd>; +class DDIV_DESC : DIVMOD_DESC_BASE<"ddiv", GPR64Opnd, sdiv>; +class DDIVU_DESC : DIVMOD_DESC_BASE<"ddivu", GPR64Opnd, udiv>; +class DLSA_R6_DESC : LSA_R6_DESC_BASE<"dlsa", GPR64Opnd, uimm2>; +class DMOD_DESC : DIVMOD_DESC_BASE<"dmod", GPR64Opnd, srem>; +class DMODU_DESC : DIVMOD_DESC_BASE<"dmodu", GPR64Opnd, urem>; +class DMUH_DESC : MUL_R6_DESC_BASE<"dmuh", GPR64Opnd, mulhs>; +class DMUHU_DESC : MUL_R6_DESC_BASE<"dmuhu", GPR64Opnd, mulhu>; +class DMUL_R6_DESC : MUL_R6_DESC_BASE<"dmul", GPR64Opnd, mul>; +class DMULU_DESC : MUL_R6_DESC_BASE<"dmulu", GPR64Opnd>; +class LDPC_DESC : PCREL_DESC_BASE<"ldpc", GPR64Opnd, simm18_lsl3>; +class LLD_R6_DESC : LL_R6_DESC_BASE<"lld", GPR64Opnd>; +class SCD_R6_DESC : SC_R6_DESC_BASE<"scd", GPR64Opnd>; +class SELEQZ64_DESC : SELEQNE_Z_DESC_BASE<"seleqz", GPR64Opnd>; +class SELNEZ64_DESC : SELEQNE_Z_DESC_BASE<"selnez", GPR64Opnd>; + +//===----------------------------------------------------------------------===// +// +// Instruction Definitions +// +//===----------------------------------------------------------------------===// + +def DAHI : DAHI_ENC, DAHI_DESC, ISA_MIPS64R6; +def DALIGN : DALIGN_ENC, DALIGN_DESC, ISA_MIPS64R6; +def DATI : DATI_ENC, DATI_DESC, ISA_MIPS64R6; +def DAUI : DAUI_ENC, DAUI_DESC, ISA_MIPS64R6; +def DBITSWAP : DBITSWAP_ENC, DBITSWAP_DESC, ISA_MIPS64R6; +def DCLO_R6 : DCLO_R6_ENC, DCLO_R6_DESC, ISA_MIPS64R6; +def DCLZ_R6 : DCLZ_R6_ENC, DCLZ_R6_DESC, ISA_MIPS64R6; +def DDIV : DDIV_ENC, DDIV_DESC, ISA_MIPS64R6; +def DDIVU : DDIVU_ENC, DDIVU_DESC, ISA_MIPS64R6; +def DLSA_R6 : DLSA_R6_ENC, DLSA_R6_DESC, ISA_MIPS64R6; +def DMOD : DMOD_ENC, DMOD_DESC, ISA_MIPS64R6; +def DMODU : DMODU_ENC, DMODU_DESC, ISA_MIPS64R6; +def DMUH: DMUH_ENC, DMUH_DESC, ISA_MIPS64R6; +def DMUHU: DMUHU_ENC, DMUHU_DESC, ISA_MIPS64R6; +def DMUL_R6: DMUL_R6_ENC, DMUL_R6_DESC, ISA_MIPS64R6; +def DMULU: DMULU_ENC, DMULU_DESC, ISA_MIPS64R6; +def LDPC: LDPC_ENC, LDPC_DESC, ISA_MIPS64R6; +def LLD_R6 : LLD_R6_ENC, LLD_R6_DESC, ISA_MIPS32R6; +def SCD_R6 : SCD_R6_ENC, SCD_R6_DESC, ISA_MIPS32R6; +let DecoderNamespace = "Mips32r6_64r6_GP64" in { + def SELEQZ64 : SELEQZ_ENC, SELEQZ64_DESC, ISA_MIPS32R6, GPR_64; + def SELNEZ64 : SELNEZ_ENC, SELNEZ64_DESC, ISA_MIPS32R6, GPR_64; +} + +//===----------------------------------------------------------------------===// +// +// Instruction Aliases +// +//===----------------------------------------------------------------------===// + +def : MipsInstAlias<"jr $rs", (JALR64 ZERO_64, GPR64Opnd:$rs), 1>, ISA_MIPS64R6; + +//===----------------------------------------------------------------------===// +// +// Patterns and Pseudo Instructions +// +//===----------------------------------------------------------------------===// + +// i64 selects +def : MipsPat<(select i64:$cond, i64:$t, i64:$f), + (OR64 (SELNEZ64 i64:$t, i64:$cond), + (SELEQZ64 i64:$f, i64:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i64:$cond, immz)), i64:$t, i64:$f), + (OR64 (SELEQZ64 i64:$t, i64:$cond), + (SELNEZ64 i64:$f, i64:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (setne i64:$cond, immz)), i64:$t, i64:$f), + (OR64 (SELNEZ64 i64:$t, i64:$cond), + (SELEQZ64 i64:$f, i64:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i64:$cond, immZExt16_64:$imm)), i64:$t, i64:$f), + (OR64 (SELEQZ64 i64:$t, (XORi64 i64:$cond, immZExt16_64:$imm)), + (SELNEZ64 i64:$f, (XORi64 i64:$cond, immZExt16_64:$imm)))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (setne i64:$cond, immZExt16_64:$imm)), i64:$t, i64:$f), + (OR64 (SELNEZ64 i64:$t, (XORi64 i64:$cond, immZExt16_64:$imm)), + (SELEQZ64 i64:$f, (XORi64 i64:$cond, immZExt16_64:$imm)))>, + ISA_MIPS64R6; +def : MipsPat< + (select (i32 (setgt i64:$cond, immSExt16Plus1:$imm)), i64:$t, i64:$f), + (OR64 (SELEQZ64 i64:$t, + (SUBREG_TO_REG (i64 0), (SLTi64 i64:$cond, (Plus1 imm:$imm)), + sub_32)), + (SELNEZ64 i64:$f, + (SUBREG_TO_REG (i64 0), (SLTi64 i64:$cond, (Plus1 imm:$imm)), + sub_32)))>, + ISA_MIPS64R6; +def : MipsPat< + (select (i32 (setugt i64:$cond, immSExt16Plus1:$imm)), i64:$t, i64:$f), + (OR64 (SELEQZ64 i64:$t, + (SUBREG_TO_REG (i64 0), (SLTiu64 i64:$cond, (Plus1 imm:$imm)), + sub_32)), + (SELNEZ64 i64:$f, + (SUBREG_TO_REG (i64 0), (SLTiu64 i64:$cond, (Plus1 imm:$imm)), + sub_32)))>, + ISA_MIPS64R6; + +def : MipsPat<(select (i32 (setne i64:$cond, immz)), i64:$t, immz), + (SELNEZ64 i64:$t, i64:$cond)>, ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i64:$cond, immz)), i64:$t, immz), + (SELEQZ64 i64:$t, i64:$cond)>, ISA_MIPS64R6; +def : MipsPat<(select (i32 (setne i64:$cond, immz)), immz, i64:$f), + (SELEQZ64 i64:$f, i64:$cond)>, ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i64:$cond, immz)), immz, i64:$f), + (SELNEZ64 i64:$f, i64:$cond)>, ISA_MIPS64R6; + +// i64 selects from an i32 comparison +// One complicating factor here is that bits 32-63 of an i32 are undefined. +// FIXME: Ideally, setcc would always produce an i64 on MIPS64 targets. +// This would allow us to remove the sign-extensions here. +def : MipsPat<(select i32:$cond, i64:$t, i64:$f), + (OR64 (SELNEZ64 i64:$t, (SLL64_32 i32:$cond)), + (SELEQZ64 i64:$f, (SLL64_32 i32:$cond)))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immz)), i64:$t, i64:$f), + (OR64 (SELEQZ64 i64:$t, (SLL64_32 i32:$cond)), + (SELNEZ64 i64:$f, (SLL64_32 i32:$cond)))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (setne i32:$cond, immz)), i64:$t, i64:$f), + (OR64 (SELNEZ64 i64:$t, (SLL64_32 i32:$cond)), + (SELEQZ64 i64:$f, (SLL64_32 i32:$cond)))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immZExt16:$imm)), i64:$t, i64:$f), + (OR64 (SELEQZ64 i64:$t, (SLL64_32 (XORi i32:$cond, + immZExt16:$imm))), + (SELNEZ64 i64:$f, (SLL64_32 (XORi i32:$cond, + immZExt16:$imm))))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (setne i32:$cond, immZExt16:$imm)), i64:$t, i64:$f), + (OR64 (SELNEZ64 i64:$t, (SLL64_32 (XORi i32:$cond, + immZExt16:$imm))), + (SELEQZ64 i64:$f, (SLL64_32 (XORi i32:$cond, + immZExt16:$imm))))>, + ISA_MIPS64R6; + +def : MipsPat<(select i32:$cond, i64:$t, immz), + (SELNEZ64 i64:$t, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (setne i32:$cond, immz)), i64:$t, immz), + (SELNEZ64 i64:$t, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immz)), i64:$t, immz), + (SELEQZ64 i64:$t, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select i32:$cond, immz, i64:$f), + (SELEQZ64 i64:$f, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (setne i32:$cond, immz)), immz, i64:$f), + (SELEQZ64 i64:$f, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immz)), immz, i64:$f), + (SELNEZ64 i64:$f, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; diff --git a/lib/Target/Mips/MipsAsmPrinter.cpp b/lib/Target/Mips/MipsAsmPrinter.cpp index 45c439826422..7f21d68bdd1d 100644 --- a/lib/Target/Mips/MipsAsmPrinter.cpp +++ b/lib/Target/Mips/MipsAsmPrinter.cpp @@ -12,9 +12,9 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "mips-asm-printer" #include "InstPrinter/MipsInstPrinter.h" #include "MCTargetDesc/MipsBaseInfo.h" +#include "MCTargetDesc/MipsMCNaCl.h" #include "Mips.h" #include "MipsAsmPrinter.h" #include "MipsInstrInfo.h" @@ -27,35 +27,61 @@ #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineJumpTableInfo.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/IR/Mangler.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSectionELF.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" +#include <string> using namespace llvm; +#define DEBUG_TYPE "mips-asm-printer" + MipsTargetStreamer &MipsAsmPrinter::getTargetStreamer() { - return static_cast<MipsTargetStreamer &>(OutStreamer.getTargetStreamer()); + return static_cast<MipsTargetStreamer &>(*OutStreamer.getTargetStreamer()); } bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &TM.getSubtarget<MipsSubtarget>(); + // Initialize TargetLoweringObjectFile. - if (Subtarget->allowMixed16_32()) - const_cast<TargetLoweringObjectFile&>(getObjFileLowering()) + const_cast<TargetLoweringObjectFile &>(getObjFileLowering()) .Initialize(OutContext, TM); + MipsFI = MF.getInfo<MipsFunctionInfo>(); + if (Subtarget->inMips16Mode()) + for (std::map< + const char *, + const llvm::Mips16HardFloatInfo::FuncSignature *>::const_iterator + it = MipsFI->StubsNeeded.begin(); + it != MipsFI->StubsNeeded.end(); ++it) { + const char *Symbol = it->first; + const llvm::Mips16HardFloatInfo::FuncSignature *Signature = it->second; + if (StubsNeeded.find(Symbol) == StubsNeeded.end()) + StubsNeeded[Symbol] = Signature; + } MCP = MF.getConstantPool(); + + // In NaCl, all indirect jump targets must be aligned to bundle size. + if (Subtarget->isTargetNaCl()) + NaClAlignIndirectJumpTargets(MF); + AsmPrinter::runOnMachineFunction(MF); return true; } @@ -67,7 +93,46 @@ bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) { #include "MipsGenMCPseudoLowering.inc" +// Lower PseudoReturn/PseudoIndirectBranch/PseudoIndirectBranch64 to JR, JR_MM, +// JALR, or JALR64 as appropriate for the target +void MipsAsmPrinter::emitPseudoIndirectBranch(MCStreamer &OutStreamer, + const MachineInstr *MI) { + bool HasLinkReg = false; + MCInst TmpInst0; + + if (Subtarget->hasMips64r6()) { + // MIPS64r6 should use (JALR64 ZERO_64, $rs) + TmpInst0.setOpcode(Mips::JALR64); + HasLinkReg = true; + } else if (Subtarget->hasMips32r6()) { + // MIPS32r6 should use (JALR ZERO, $rs) + TmpInst0.setOpcode(Mips::JALR); + HasLinkReg = true; + } else if (Subtarget->inMicroMipsMode()) + // microMIPS should use (JR_MM $rs) + TmpInst0.setOpcode(Mips::JR_MM); + else { + // Everything else should use (JR $rs) + TmpInst0.setOpcode(Mips::JR); + } + + MCOperand MCOp; + + if (HasLinkReg) { + unsigned ZeroReg = Subtarget->isGP64bit() ? Mips::ZERO_64 : Mips::ZERO; + TmpInst0.addOperand(MCOperand::CreateReg(ZeroReg)); + } + + lowerOperand(MI->getOperand(0), MCOp); + TmpInst0.addOperand(MCOp); + + EmitToStreamer(OutStreamer, TmpInst0); +} + void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { + MipsTargetStreamer &TS = getTargetStreamer(); + TS.setCanHaveModuleDir(false); + if (MI->isDebugValue()) { SmallString<128> Str; raw_svector_ostream OS(Str); @@ -117,6 +182,14 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { if (emitPseudoExpansionLowering(OutStreamer, &*I)) continue; + if (I->getOpcode() == Mips::PseudoReturn || + I->getOpcode() == Mips::PseudoReturn64 || + I->getOpcode() == Mips::PseudoIndirectBranch || + I->getOpcode() == Mips::PseudoIndirectBranch64) { + emitPseudoIndirectBranch(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 @@ -124,12 +197,13 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { // removing another test for this situation downstream in the // callchain. // - if (I->isPseudo() && !Subtarget->inMips16Mode()) + if (I->isPseudo() && !Subtarget->inMips16Mode() + && !isLongBranchPseudo(I->getOpcode())) llvm_unreachable("Pseudo opcode found in EmitInstruction()"); MCInst TmpInst0; MCInstLowering.Lower(I, TmpInst0); - OutStreamer.EmitInstruction(TmpInst0); + EmitToStreamer(OutStreamer, TmpInst0); } while ((++I != E) && I->isInsideBundle()); // Delay slot check } @@ -170,7 +244,7 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { // 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) { +void MipsAsmPrinter::printSavedRegsBitmask() { // CPU and FPU Saved Registers Bitmasks unsigned CPUBitmask = 0, FPUBitmask = 0; int CPUTopSavedRegOff, FPUTopSavedRegOff; @@ -218,20 +292,12 @@ void MipsAsmPrinter::printSavedRegsBitmask(raw_ostream &O) { // CPU Regs are saved below FP Regs. CPUTopSavedRegOff = CPUBitmask ? -CSFPRegsSize - CPURegSize : 0; + MipsTargetStreamer &TS = getTargetStreamer(); // Print CPUBitmask - O << "\t.mask \t"; printHex32(CPUBitmask, O); - O << ',' << CPUTopSavedRegOff << '\n'; + TS.emitMask(CPUBitmask, CPUTopSavedRegOff); // 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)); + TS.emitFMask(FPUBitmask, FPUTopSavedRegOff); } //===----------------------------------------------------------------------===// @@ -246,11 +312,7 @@ void MipsAsmPrinter::emitFrameDirective() { 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()); + getTargetStreamer().emitFrame(stackReg, stackSize, returnReg); } /// Emit Set directives. @@ -265,25 +327,32 @@ const char *MipsAsmPrinter::getCurrentABIString() const { } 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())); - } + MipsTargetStreamer &TS = getTargetStreamer(); + + // NaCl sandboxing requires that indirect call instructions are masked. + // This means that function entry points should be bundle-aligned. + if (Subtarget->isTargetNaCl()) + EmitAlignment(std::max(MF->getAlignment(), MIPS_NACL_BUNDLE_ALIGN)); if (Subtarget->inMicroMipsMode()) - getTargetStreamer().emitMipsHackSTOCG(CurrentFnSym, - (unsigned)ELF::STO_MIPS_MICROMIPS); + TS.emitDirectiveSetMicroMips(); + else + TS.emitDirectiveSetNoMicroMips(); + + if (Subtarget->inMips16Mode()) + TS.emitDirectiveSetMips16(); + else + TS.emitDirectiveSetNoMips16(); + + TS.emitDirectiveEnt(*CurrentFnSym); OutStreamer.EmitLabel(CurrentFnSym); } /// EmitFunctionBodyStart - Targets can override this to emit stuff before /// the first basic block in the function. void MipsAsmPrinter::EmitFunctionBodyStart() { + MipsTargetStreamer &TS = getTargetStreamer(); + MCInstLowering.Initialize(&MF->getContext()); bool IsNakedFunction = @@ -293,34 +362,30 @@ void MipsAsmPrinter::EmitFunctionBodyStart() { 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")); - } + if (!IsNakedFunction) + printSavedRegsBitmask(); + + if (!Subtarget->inMips16Mode()) { + TS.emitDirectiveSetNoReorder(); + TS.emitDirectiveSetNoMacro(); + TS.emitDirectiveSetNoAt(); } } /// EmitFunctionBodyEnd - Targets can override this to emit stuff after /// the last basic block in the function. void MipsAsmPrinter::EmitFunctionBodyEnd() { + MipsTargetStreamer &TS = getTargetStreamer(); + // 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())); + if (!Subtarget->inMips16Mode()) { + TS.emitDirectiveSetAt(); + TS.emitDirectiveSetMacro(); + TS.emitDirectiveSetReorder(); } + TS.emitDirectiveEnd(CurrentFnSym->getName()); // Make sure to terminate any constant pools that were at the end // of the function. if (!InConstantPool) @@ -495,6 +560,7 @@ bool MipsAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum, raw_ostream &O) { + const DataLayout *DL = TM.getDataLayout(); const MachineOperand &MO = MI->getOperand(opNum); bool closeP = false; @@ -542,17 +608,8 @@ void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum, 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" + O << DL->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_" << MO.getIndex(); if (MO.getOffset()) O << "+" << MO.getOffset(); @@ -612,86 +669,329 @@ printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, } 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")); + bool IsABICalls = true; + if (IsABICalls) { + getTargetStreamer().emitDirectiveAbiCalls(); + Reloc::Model RM = TM.getRelocationModel(); + // FIXME: This condition should be a lot more complicated that it is here. + // Ideally it should test for properties of the ABI and not the ABI + // itself. + // For the moment, I'm only correcting enough to make MIPS-IV work. + if (RM == Reloc::Static && !Subtarget->isABI_N64()) + getTargetStreamer().emitDirectiveOptionPic0(); } // Tell the assembler which ABI we are using - if (OutStreamer.hasRawTextSupport()) - OutStreamer.EmitRawText("\t.section .mdebug." + - Twine(getCurrentABIString())); + std::string SectionName = std::string(".mdebug.") + getCurrentABIString(); + OutStreamer.SwitchSection(OutContext.getELFSection( + SectionName, ELF::SHT_PROGBITS, 0, SectionKind::getDataRel())); + + // NaN: At the moment we only support: + // 1. .nan legacy (default) + // 2. .nan 2008 + Subtarget->isNaN2008() ? getTargetStreamer().emitDirectiveNaN2008() + : getTargetStreamer().emitDirectiveNaNLegacy(); // 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")); - } + + if (Subtarget->isABI_EABI()) { + if (Subtarget->isGP32bit()) + OutStreamer.SwitchSection( + OutContext.getELFSection(".gcc_compiled_long32", ELF::SHT_PROGBITS, 0, + SectionKind::getDataRel())); + else + OutStreamer.SwitchSection( + OutContext.getELFSection(".gcc_compiled_long64", ELF::SHT_PROGBITS, 0, + SectionKind::getDataRel())); } - // return to previous section - if (OutStreamer.hasRawTextSupport()) - OutStreamer.EmitRawText(StringRef("\t.previous")); + getTargetStreamer().updateABIInfo(*Subtarget); + // We should always emit a '.module fp=...' but binutils 2.24 does not accept + // it. We therefore emit it when it contradicts the ABI defaults (-mfpxx or + // -mfp64) and omit it otherwise. + if (Subtarget->isABI_O32() && (Subtarget->isABI_FPXX() || + Subtarget->isFP64bit())) + getTargetStreamer().emitDirectiveModuleFP(); + + // We should always emit a '.module [no]oddspreg' but binutils 2.24 does not + // accept it. We therefore emit it when it contradicts the default or an + // option has changed the default (i.e. FPXX) and omit it otherwise. + if (Subtarget->isABI_O32() && (!Subtarget->useOddSPReg() || + Subtarget->isABI_FPXX())) + getTargetStreamer().emitDirectiveModuleOddSPReg(Subtarget->useOddSPReg(), + Subtarget->isABI_O32()); } -static void emitELFHeaderFlagsCG(MipsTargetStreamer &TargetStreamer, - const MipsSubtarget &Subtarget) { - // Update e_header flags - unsigned EFlags = 0; +void MipsAsmPrinter::EmitJal(MCSymbol *Symbol) { + MCInst I; + I.setOpcode(Mips::JAL); + I.addOperand( + MCOperand::CreateExpr(MCSymbolRefExpr::Create(Symbol, OutContext))); + OutStreamer.EmitInstruction(I, getSubtargetInfo()); +} - // TODO: Need to add -mabicalls and -mno-abicalls flags. - // Currently we assume that -mabicalls is the default. - EFlags |= ELF::EF_MIPS_CPIC; +void MipsAsmPrinter::EmitInstrReg(unsigned Opcode, unsigned Reg) { + MCInst I; + I.setOpcode(Opcode); + I.addOperand(MCOperand::CreateReg(Reg)); + OutStreamer.EmitInstruction(I, getSubtargetInfo()); +} - if (Subtarget.inMips16Mode()) - EFlags |= ELF::EF_MIPS_ARCH_ASE_M16; - else - EFlags |= ELF::EF_MIPS_NOREORDER; +void MipsAsmPrinter::EmitInstrRegReg(unsigned Opcode, unsigned Reg1, + unsigned Reg2) { + MCInst I; + // + // Because of the current td files for Mips32, the operands for MTC1 + // appear backwards from their normal assembly order. It's not a trivial + // change to fix this in the td file so we adjust for it here. + // + if (Opcode == Mips::MTC1) { + unsigned Temp = Reg1; + Reg1 = Reg2; + Reg2 = Temp; + } + I.setOpcode(Opcode); + I.addOperand(MCOperand::CreateReg(Reg1)); + I.addOperand(MCOperand::CreateReg(Reg2)); + OutStreamer.EmitInstruction(I, getSubtargetInfo()); +} - // 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; +void MipsAsmPrinter::EmitInstrRegRegReg(unsigned Opcode, unsigned Reg1, + unsigned Reg2, unsigned Reg3) { + MCInst I; + I.setOpcode(Opcode); + I.addOperand(MCOperand::CreateReg(Reg1)); + I.addOperand(MCOperand::CreateReg(Reg2)); + I.addOperand(MCOperand::CreateReg(Reg3)); + OutStreamer.EmitInstruction(I, getSubtargetInfo()); +} - if (Subtarget.inMicroMipsMode()) - EFlags |= ELF::EF_MIPS_MICROMIPS; +void MipsAsmPrinter::EmitMovFPIntPair(unsigned MovOpc, unsigned Reg1, + unsigned Reg2, unsigned FPReg1, + unsigned FPReg2, bool LE) { + if (!LE) { + unsigned temp = Reg1; + Reg1 = Reg2; + Reg2 = temp; + } + EmitInstrRegReg(MovOpc, Reg1, FPReg1); + EmitInstrRegReg(MovOpc, Reg2, FPReg2); +} - // ABI - if (Subtarget.isABI_O32()) - EFlags |= ELF::EF_MIPS_ABI_O32; +void MipsAsmPrinter::EmitSwapFPIntParams(Mips16HardFloatInfo::FPParamVariant PV, + bool LE, bool ToFP) { + using namespace Mips16HardFloatInfo; + unsigned MovOpc = ToFP ? Mips::MTC1 : Mips::MFC1; + switch (PV) { + case FSig: + EmitInstrRegReg(MovOpc, Mips::A0, Mips::F12); + break; + case FFSig: + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F14, LE); + break; + case FDSig: + EmitInstrRegReg(MovOpc, Mips::A0, Mips::F12); + EmitMovFPIntPair(MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE); + break; + case DSig: + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); + break; + case DDSig: + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); + EmitMovFPIntPair(MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE); + break; + case DFSig: + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); + EmitInstrRegReg(MovOpc, Mips::A2, Mips::F14); + break; + case NoSig: + return; + } +} - // 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"); +void +MipsAsmPrinter::EmitSwapFPIntRetval(Mips16HardFloatInfo::FPReturnVariant RV, + bool LE) { + using namespace Mips16HardFloatInfo; + unsigned MovOpc = Mips::MFC1; + switch (RV) { + case FRet: + EmitInstrRegReg(MovOpc, Mips::V0, Mips::F0); + break; + case DRet: + EmitMovFPIntPair(MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); + break; + case CFRet: + EmitMovFPIntPair(MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); + break; + case CDRet: + EmitMovFPIntPair(MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F2, Mips::F3, LE); + break; + case NoFPRet: + break; + } +} + +void MipsAsmPrinter::EmitFPCallStub( + const char *Symbol, const Mips16HardFloatInfo::FuncSignature *Signature) { + MCSymbol *MSymbol = OutContext.GetOrCreateSymbol(StringRef(Symbol)); + using namespace Mips16HardFloatInfo; + bool LE = Subtarget->isLittle(); + // + // .global xxxx + // + OutStreamer.EmitSymbolAttribute(MSymbol, MCSA_Global); + const char *RetType; + // + // make the comment field identifying the return and parameter + // types of the floating point stub + // # Stub function to call rettype xxxx (params) + // + switch (Signature->RetSig) { + case FRet: + RetType = "float"; + break; + case DRet: + RetType = "double"; + break; + case CFRet: + RetType = "complex"; + break; + case CDRet: + RetType = "double complex"; + break; + case NoFPRet: + RetType = ""; + break; + } + const char *Parms; + switch (Signature->ParamSig) { + case FSig: + Parms = "float"; + break; + case FFSig: + Parms = "float, float"; + break; + case FDSig: + Parms = "float, double"; + break; + case DSig: + Parms = "double"; + break; + case DDSig: + Parms = "double, double"; + break; + case DFSig: + Parms = "double, float"; + break; + case NoSig: + Parms = ""; + break; + } + OutStreamer.AddComment("\t# Stub function to call " + Twine(RetType) + " " + + Twine(Symbol) + " (" + Twine(Parms) + ")"); + // + // probably not necessary but we save and restore the current section state + // + OutStreamer.PushSection(); + // + // .section mips16.call.fpxxxx,"ax",@progbits + // + const MCSectionELF *M = OutContext.getELFSection( + ".mips16.call.fp." + std::string(Symbol), ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_EXECINSTR, SectionKind::getText()); + OutStreamer.SwitchSection(M, nullptr); + // + // .align 2 + // + OutStreamer.EmitValueToAlignment(4); + MipsTargetStreamer &TS = getTargetStreamer(); + // + // .set nomips16 + // .set nomicromips + // + TS.emitDirectiveSetNoMips16(); + TS.emitDirectiveSetNoMicroMips(); + // + // .ent __call_stub_fp_xxxx + // .type __call_stub_fp_xxxx,@function + // __call_stub_fp_xxxx: + // + std::string x = "__call_stub_fp_" + std::string(Symbol); + MCSymbol *Stub = OutContext.GetOrCreateSymbol(StringRef(x)); + TS.emitDirectiveEnt(*Stub); + MCSymbol *MType = + OutContext.GetOrCreateSymbol("__call_stub_fp_" + Twine(Symbol)); + OutStreamer.EmitSymbolAttribute(MType, MCSA_ELF_TypeFunction); + OutStreamer.EmitLabel(Stub); + // + // we just handle non pic for now. these function will not be + // called otherwise. when the full stub generation is moved here + // we need to deal with pic. + // + if (Subtarget->getRelocationModel() == Reloc::PIC_) + llvm_unreachable("should not be here if we are compiling pic"); + TS.emitDirectiveSetReorder(); + // + // We need to add a MipsMCExpr class to MCTargetDesc to fully implement + // stubs without raw text but this current patch is for compiler generated + // functions and they all return some value. + // The calling sequence for non pic is different in that case and we need + // to implement %lo and %hi in order to handle the case of no return value + // See the corresponding method in Mips16HardFloat for details. + // + // mov the return address to S2. + // we have no stack space to store it and we are about to make another call. + // We need to make sure that the enclosing function knows to save S2 + // This should have already been handled. + // + // Mov $18, $31 + + EmitInstrRegRegReg(Mips::ADDu, Mips::S2, Mips::RA, Mips::ZERO); + + EmitSwapFPIntParams(Signature->ParamSig, LE, true); + + // Jal xxxx + // + EmitJal(MSymbol); + + // fix return values + EmitSwapFPIntRetval(Signature->RetSig, LE); + // + // do the return + // if (Signature->RetSig == NoFPRet) + // llvm_unreachable("should not be any stubs here with no return value"); + // else + EmitInstrReg(Mips::JR, Mips::S2); - TargetStreamer.emitMipsHackELFFlags(EFlags); + MCSymbol *Tmp = OutContext.CreateTempSymbol(); + OutStreamer.EmitLabel(Tmp); + const MCSymbolRefExpr *E = MCSymbolRefExpr::Create(Stub, OutContext); + const MCSymbolRefExpr *T = MCSymbolRefExpr::Create(Tmp, OutContext); + const MCExpr *T_min_E = MCBinaryExpr::CreateSub(T, E, OutContext); + OutStreamer.EmitELFSize(Stub, T_min_E); + TS.emitDirectiveEnd(x); + OutStreamer.PopSection(); } void MipsAsmPrinter::EmitEndOfAsmFile(Module &M) { - // Emit Mips ELF register info - Subtarget->getMReginfo().emitMipsReginfoSectionCG( - OutStreamer, getObjFileLowering(), *Subtarget); - emitELFHeaderFlagsCG(getTargetStreamer(), *Subtarget); + // Emit needed stubs + // + for (std::map< + const char *, + const llvm::Mips16HardFloatInfo::FuncSignature *>::const_iterator + it = StubsNeeded.begin(); + it != StubsNeeded.end(); ++it) { + const char *Symbol = it->first; + const llvm::Mips16HardFloatInfo::FuncSignature *Signature = it->second; + EmitFPCallStub(Symbol, Signature); + } + // return to the text section + OutStreamer.SwitchSection(OutContext.getObjectFileInfo()->getTextSection()); } void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI, @@ -699,6 +999,34 @@ void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI, // TODO: implement } +// Align all targets of indirect branches on bundle size. Used only if target +// is NaCl. +void MipsAsmPrinter::NaClAlignIndirectJumpTargets(MachineFunction &MF) { + // Align all blocks that are jumped to through jump table. + if (MachineJumpTableInfo *JtInfo = MF.getJumpTableInfo()) { + const std::vector<MachineJumpTableEntry> &JT = JtInfo->getJumpTables(); + for (unsigned I = 0; I < JT.size(); ++I) { + const std::vector<MachineBasicBlock*> &MBBs = JT[I].MBBs; + + for (unsigned J = 0; J < MBBs.size(); ++J) + MBBs[J]->setAlignment(MIPS_NACL_BUNDLE_ALIGN); + } + } + + // If basic block address is taken, block can be target of indirect branch. + for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); + MBB != E; ++MBB) { + if (MBB->hasAddressTaken()) + MBB->setAlignment(MIPS_NACL_BUNDLE_ALIGN); + } +} + +bool MipsAsmPrinter::isLongBranchPseudo(int Opcode) const { + return (Opcode == Mips::LONG_BRANCH_LUi + || Opcode == Mips::LONG_BRANCH_ADDiu + || Opcode == Mips::LONG_BRANCH_DADDiu); +} + // Force static initialization. extern "C" void LLVMInitializeMipsAsmPrinter() { RegisterAsmPrinter<MipsAsmPrinter> X(TheMipsTarget); diff --git a/lib/Target/Mips/MipsAsmPrinter.h b/lib/Target/Mips/MipsAsmPrinter.h index 11c6acd208d1..abbd39b571a5 100644 --- a/lib/Target/Mips/MipsAsmPrinter.h +++ b/lib/Target/Mips/MipsAsmPrinter.h @@ -14,6 +14,7 @@ #ifndef MIPSASMPRINTER_H #define MIPSASMPRINTER_H +#include "Mips16HardFloatInfo.h" #include "MipsMCInstLower.h" #include "MipsMachineFunction.h" #include "MipsSubtarget.h" @@ -39,6 +40,12 @@ private: bool emitPseudoExpansionLowering(MCStreamer &OutStreamer, const MachineInstr *MI); + // Emit PseudoReturn, PseudoReturn64, PseudoIndirectBranch, + // and PseudoIndirectBranch64 as a JR, JR_MM, JALR, or JALR64 as appropriate + // for the target. + void emitPseudoIndirectBranch(MCStreamer &OutStreamer, + const MachineInstr *MI); + // lowerOperand - Convert a MachineOperand into the equivalent MCOperand. bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp); @@ -50,7 +57,31 @@ private: /// pool entries so we can properly mark them as data regions. bool InConstantPool; - bool UsingConstantPools; + std::map<const char *, const llvm::Mips16HardFloatInfo::FuncSignature *> + StubsNeeded; + + void EmitJal(MCSymbol *Symbol); + + void EmitInstrReg(unsigned Opcode, unsigned Reg); + + void EmitInstrRegReg(unsigned Opcode, unsigned Reg1, unsigned Reg2); + + void EmitInstrRegRegReg(unsigned Opcode, unsigned Reg1, unsigned Reg2, + unsigned Reg3); + + void EmitMovFPIntPair(unsigned MovOpc, unsigned Reg1, unsigned Reg2, + unsigned FPReg1, unsigned FPReg2, bool LE); + + void EmitSwapFPIntParams(Mips16HardFloatInfo::FPParamVariant, bool LE, + bool ToFP); + + void EmitSwapFPIntRetval(Mips16HardFloatInfo::FPReturnVariant, bool LE); + + void EmitFPCallStub(const char *, const Mips16HardFloatInfo::FuncSignature *); + + void NaClAlignIndirectJumpTargets(MachineFunction &MF); + + bool isLongBranchPseudo(int Opcode) const; public: @@ -58,51 +89,53 @@ public: 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()); - } + // We initialize the subtarget here and in runOnMachineFunction + // since there are certain target specific flags (ABI) that could + // reside on the TargetMachine, but are on the subtarget currently + // and we need them for the beginning of file output before we've + // seen a single function. + explicit MipsAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) + : AsmPrinter(TM, Streamer), MCP(nullptr), InConstantPool(false), + Subtarget(&TM.getSubtarget<MipsSubtarget>()), MCInstLowering(*this) {} - virtual const char *getPassName() const { + const char *getPassName() const override { return "Mips Assembly Printer"; } - virtual bool runOnMachineFunction(MachineFunction &MF); + bool runOnMachineFunction(MachineFunction &MF) override; - virtual void EmitConstantPool() LLVM_OVERRIDE { + void EmitConstantPool() override { + bool UsingConstantPools = + (Subtarget->inMips16Mode() && Subtarget->useConstantIslands()); 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 EmitInstruction(const MachineInstr *MI) override; + void printSavedRegsBitmask(); void emitFrameDirective(); const char *getCurrentABIString() const; - virtual void EmitFunctionEntryLabel(); - virtual void EmitFunctionBodyStart(); - virtual void EmitFunctionBodyEnd(); - virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock* - MBB) const; + void EmitFunctionEntryLabel() override; + void EmitFunctionBodyStart() override; + void EmitFunctionBodyEnd() override; + bool isBlockOnlyReachableByFallthrough( + const MachineBasicBlock* MBB) const override; bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O); + raw_ostream &O) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O); + raw_ostream &O) override; 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); + const char *Modifier = nullptr); + void EmitStartOfAsmFile(Module &M) override; + void EmitEndOfAsmFile(Module &M) override; void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS); }; } diff --git a/lib/Target/Mips/MipsCallingConv.td b/lib/Target/Mips/MipsCallingConv.td index 66391cb9cb1e..b1cd3c35782f 100644 --- a/lib/Target/Mips/MipsCallingConv.td +++ b/lib/Target/Mips/MipsCallingConv.td @@ -26,9 +26,9 @@ def RetCC_MipsO32 : CallingConv<[ // 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 + // f64 arguments are returned in D0_64 and D2_64 in FP64bit mode or // in D0 and D1 in FP32bit mode. - CCIfType<[f64], CCIfSubtarget<"isFP64bit()", CCAssignToReg<[D0_64, D1_64]>>>, + CCIfType<[f64], CCIfSubtarget<"isFP64bit()", CCAssignToReg<[D0_64, D2_64]>>>, CCIfType<[f64], CCIfSubtarget<"isNotFP64bit()", CCAssignToReg<[D0, D1]>>> ]>; @@ -192,12 +192,24 @@ def CC_Mips_FastCC : CallingConv<[ // 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]>>, + CCIfType<[i32], CCIfSubtarget<"isNotTargetNaCl()", + CCAssignToReg<[A0, A1, A2, A3, T0, T1, T2, T3, T4, T5, T6, T7, T8, V1]>>>, + + // In NaCl, T6, T7 and T8 are reserved and not available as argument + // registers for fastcc. T6 contains the mask for sandboxing control flow + // (indirect jumps and calls). T7 contains the mask for sandboxing memory + // accesses (loads and stores). T8 contains the thread pointer. + CCIfType<[i32], CCIfSubtarget<"isTargetNaCl()", + CCAssignToReg<[A0, A1, A2, A3, T0, T1, T2, T3, T4, T5, 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]>>, + CCIfType<[f32], CCIfSubtarget<"useOddSPReg()", + CCAssignToReg<[F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, + F14, F15, F16, F17, F18, F19]>>>, + + // Don't use odd numbered single-precision registers for -mno-odd-spreg. + CCIfType<[f32], CCIfSubtarget<"noOddSPReg()", + CCAssignToReg<[F0, F2, F4, F6, F8, F10, F12, F14, F16, F18]>>>, // Stack parameter slots for i32 and f32 are 32-bit words and 4-byte aligned. CCIfType<[i32, f32], CCAssignToStack<4, 4>>, @@ -232,18 +244,26 @@ def RetCC_Mips : CallingConv<[ def CSR_SingleFloatOnly : CalleeSavedRegs<(add (sequence "F%u", 31, 20), RA, FP, (sequence "S%u", 7, 0))>; +def CSR_O32_FPXX : CalleeSavedRegs<(add (sequence "D%u", 15, 10), RA, FP, + (sequence "S%u", 7, 0))> { + let OtherPreserved = (add (decimate (sequence "F%u", 30, 20), 2)); +} + 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_O32_FP64 : + CalleeSavedRegs<(add (decimate (sequence "D%u_64", 30, 20), 2), 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, +def CSR_N32 : CalleeSavedRegs<(add D20_64, D22_64, D24_64, D26_64, D28_64, + D30_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)>; + CalleeSavedRegs<(add V0, V1, FP, + (sequence "A%u", 3, 0), (sequence "S%u", 7, 0), + (sequence "D%u", 15, 10))>; diff --git a/lib/Target/Mips/MipsCodeEmitter.cpp b/lib/Target/Mips/MipsCodeEmitter.cpp index ca4163d4e58c..794c71898fa3 100644 --- a/lib/Target/Mips/MipsCodeEmitter.cpp +++ b/lib/Target/Mips/MipsCodeEmitter.cpp @@ -12,7 +12,6 @@ // //===---------------------------------------------------------------------===// -#define DEBUG_TYPE "jit" #include "Mips.h" #include "MCTargetDesc/MipsBaseInfo.h" #include "MipsInstrInfo.h" @@ -24,8 +23,8 @@ #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/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/Passes.h" @@ -41,6 +40,8 @@ using namespace llvm; +#define DEBUG_TYPE "jit" + STATISTIC(NumEmitted, "Number of machine instructions emitted"); namespace { @@ -56,7 +57,7 @@ class MipsCodeEmitter : public MachineFunctionPass { const std::vector<MachineJumpTableEntry> *MJTEs; bool IsPIC; - void getAnalysisUsage(AnalysisUsage &AU) const { + void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired<MachineModuleInfo> (); MachineFunctionPass::getAnalysisUsage(AU); } @@ -65,13 +66,13 @@ class MipsCodeEmitter : public MachineFunctionPass { public: MipsCodeEmitter(TargetMachine &tm, JITCodeEmitter &mce) - : MachineFunctionPass(ID), JTI(0), II(0), TD(0), - TM(tm), MCE(mce), MCPEs(0), MJTEs(0), + : MachineFunctionPass(ID), JTI(nullptr), II(nullptr), TD(nullptr), + TM(tm), MCE(mce), MCPEs(nullptr), MJTEs(nullptr), IsPIC(TM.getRelocationModel() == Reloc::PIC_) {} - bool runOnMachineFunction(MachineFunction &MF); + bool runOnMachineFunction(MachineFunction &MF) override; - virtual const char *getPassName() const { + const char *getPassName() const override { return "Mips Machine Code Emitter"; } @@ -109,20 +110,29 @@ private: unsigned getBranchTargetOpValueMM(const MachineInstr &MI, unsigned OpNo) const; + unsigned getBranchTarget21OpValue(const MachineInstr &MI, + unsigned OpNo) const; + unsigned getBranchTarget26OpValue(const MachineInstr &MI, + unsigned OpNo) const; + unsigned getJumpOffset16OpValue(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 getMSAMemEncoding(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; + unsigned getSimm19Lsl2Encoding(const MachineInstr &MI, unsigned OpNo) const; + unsigned getSimm18Lsl3Encoding(const MachineInstr &MI, unsigned OpNo) const; /// Expand pseudo instructions with accumulator register operands. void expandACCInstr(MachineBasicBlock::instr_iterator MI, MachineBasicBlock &MBB, unsigned Opc) const; + void expandPseudoIndirectBranch(MachineBasicBlock::instr_iterator MI, + MachineBasicBlock &MBB) const; + /// \brief Expand pseudo instruction. Return true if MI was expanded. bool expandPseudos(MachineBasicBlock::instr_iterator &MI, MachineBasicBlock &MBB) const; @@ -140,7 +150,7 @@ bool MipsCodeEmitter::runOnMachineFunction(MachineFunction &MF) { TD = Target.getDataLayout(); Subtarget = &TM.getSubtarget<MipsSubtarget> (); MCPEs = &MF.getConstantPool()->getConstants(); - MJTEs = 0; + MJTEs = nullptr; if (MF.getJumpTableInfo()) MJTEs = &MF.getJumpTableInfo()->getJumpTables(); JTI->Initialize(MF, IsPIC, Subtarget->isLittle()); MCE.setModuleInfo(&getAnalysis<MachineModuleInfo> ()); @@ -203,6 +213,24 @@ unsigned MipsCodeEmitter::getBranchTargetOpValueMM(const MachineInstr &MI, return 0; } +unsigned MipsCodeEmitter::getBranchTarget21OpValue(const MachineInstr &MI, + unsigned OpNo) const { + llvm_unreachable("Unimplemented function."); + return 0; +} + +unsigned MipsCodeEmitter::getBranchTarget26OpValue(const MachineInstr &MI, + unsigned OpNo) const { + llvm_unreachable("Unimplemented function."); + return 0; +} + +unsigned MipsCodeEmitter::getJumpOffset16OpValue(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); @@ -224,6 +252,12 @@ unsigned MipsCodeEmitter::getMemEncodingMMImm12(const MachineInstr &MI, return 0; } +unsigned MipsCodeEmitter::getMSAMemEncoding(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. @@ -243,6 +277,18 @@ unsigned MipsCodeEmitter::getLSAImmEncoding(const MachineInstr &MI, return 0; } +unsigned MipsCodeEmitter::getSimm18Lsl3Encoding(const MachineInstr &MI, + unsigned OpNo) const { + llvm_unreachable("Unimplemented function."); + return 0; +} + +unsigned MipsCodeEmitter::getSimm19Lsl2Encoding(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, @@ -273,14 +319,6 @@ void MipsCodeEmitter::emitGlobalAddress(const GlobalValue *GV, unsigned Reloc, 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(), @@ -338,9 +376,44 @@ void MipsCodeEmitter::expandACCInstr(MachineBasicBlock::instr_iterator MI, .addReg(MI->getOperand(1).getReg()).addReg(MI->getOperand(2).getReg()); } +void MipsCodeEmitter::expandPseudoIndirectBranch( + MachineBasicBlock::instr_iterator MI, MachineBasicBlock &MBB) const { + // This logic is duplicated from MipsAsmPrinter::emitPseudoIndirectBranch() + bool HasLinkReg = false; + unsigned Opcode = 0; + + if (Subtarget->hasMips64r6()) { + // MIPS64r6 should use (JALR64 ZERO_64, $rs) + Opcode = Mips::JALR64; + HasLinkReg = true; + } else if (Subtarget->hasMips32r6()) { + // MIPS32r6 should use (JALR ZERO, $rs) + Opcode = Mips::JALR; + HasLinkReg = true; + } else if (Subtarget->inMicroMipsMode()) + // microMIPS should use (JR_MM $rs) + Opcode = Mips::JR_MM; + else { + // Everything else should use (JR $rs) + Opcode = Mips::JR; + } + + auto MIB = BuildMI(MBB, &*MI, MI->getDebugLoc(), II->get(Opcode)); + + if (HasLinkReg) { + unsigned ZeroReg = Subtarget->isGP64bit() ? Mips::ZERO_64 : Mips::ZERO; + MIB.addReg(ZeroReg); + } + + MIB.addReg(MI->getOperand(0).getReg()); +} + bool MipsCodeEmitter::expandPseudos(MachineBasicBlock::instr_iterator &MI, MachineBasicBlock &MBB) const { switch (MI->getOpcode()) { + default: + llvm_unreachable("Unhandled pseudo"); + return false; case Mips::NOP: BuildMI(MBB, &*MI, MI->getDebugLoc(), II->get(Mips::SLL), Mips::ZERO) .addReg(Mips::ZERO).addImm(0); @@ -381,8 +454,17 @@ bool MipsCodeEmitter::expandPseudos(MachineBasicBlock::instr_iterator &MI, case Mips::PseudoMSUBU: expandACCInstr(MI, MBB, Mips::MSUBU); break; - default: - return false; + case Mips::PseudoReturn: + case Mips::PseudoReturn64: + case Mips::PseudoIndirectBranch: + case Mips::PseudoIndirectBranch64: + expandPseudoIndirectBranch(MI, MBB); + break; + case TargetOpcode::CFI_INSTRUCTION: + case TargetOpcode::IMPLICIT_DEF: + case TargetOpcode::KILL: + // Do nothing + return false; } (MI--)->eraseFromBundle(); diff --git a/lib/Target/Mips/MipsCondMov.td b/lib/Target/Mips/MipsCondMov.td index 2de1430a395f..690f62608504 100644 --- a/lib/Target/Mips/MipsCondMov.td +++ b/lib/Target/Mips/MipsCondMov.td @@ -27,7 +27,7 @@ class CMov_I_I_FT<string opstr, RegisterOperand CRC, RegisterOperand DRC, 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> { + !strconcat(opstr, "\t$fd, $fs, $rt"), [], Itin, FrmFR, opstr> { let Constraints = "$F = $fd"; } @@ -47,7 +47,7 @@ class CMov_F_F_FT<string opstr, RegisterOperand RC, InstrItinClass Itin, 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> { + Itin, FrmFR, opstr> { let Constraints = "$F = $fd"; } @@ -103,143 +103,163 @@ multiclass MovnPats<RegisterClass CRC, RegisterClass DRC, Instruction MOVNInst, } // Instantiation of instructions. -def MOVZ_I_I : MMRel, CMov_I_I_FT<"movz", GPR32Opnd, GPR32Opnd, IIArith>, - ADD_FM<0, 0xa>; +def MOVZ_I_I : MMRel, CMov_I_I_FT<"movz", GPR32Opnd, GPR32Opnd, II_MOVZ>, + ADD_FM<0, 0xa>, INSN_MIPS4_32_NOT_32R6_64R6; -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>; +let isCodeGenOnly = 1 in { + def MOVZ_I_I64 : CMov_I_I_FT<"movz", GPR32Opnd, GPR64Opnd, II_MOVZ>, + ADD_FM<0, 0xa>, INSN_MIPS4_32_NOT_32R6_64R6; + def MOVZ_I64_I : CMov_I_I_FT<"movz", GPR64Opnd, GPR32Opnd, II_MOVZ>, + ADD_FM<0, 0xa>, INSN_MIPS4_32_NOT_32R6_64R6; + def MOVZ_I64_I64 : CMov_I_I_FT<"movz", GPR64Opnd, GPR64Opnd, II_MOVZ>, + ADD_FM<0, 0xa>, INSN_MIPS4_32_NOT_32R6_64R6; } -def MOVN_I_I : MMRel, CMov_I_I_FT<"movn", GPR32Opnd, GPR32Opnd, IIArith>, - ADD_FM<0, 0xb>; +def MOVN_I_I : MMRel, CMov_I_I_FT<"movn", GPR32Opnd, GPR32Opnd, II_MOVN>, + ADD_FM<0, 0xb>, INSN_MIPS4_32_NOT_32R6_64R6; -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>; +let isCodeGenOnly = 1 in { + def MOVN_I_I64 : CMov_I_I_FT<"movn", GPR32Opnd, GPR64Opnd, II_MOVN>, + ADD_FM<0, 0xb>, INSN_MIPS4_32_NOT_32R6_64R6; + def MOVN_I64_I : CMov_I_I_FT<"movn", GPR64Opnd, GPR32Opnd, II_MOVN>, + ADD_FM<0, 0xb>, INSN_MIPS4_32_NOT_32R6_64R6; + def MOVN_I64_I64 : CMov_I_I_FT<"movn", GPR64Opnd, GPR64Opnd, II_MOVN>, + ADD_FM<0, 0xb>, INSN_MIPS4_32_NOT_32R6_64R6; } -def MOVZ_I_S : CMov_I_F_FT<"movz.s", GPR32Opnd, FGR32Opnd, IIFmove>, - CMov_I_F_FM<18, 16>; +def MOVZ_I_S : MMRel, CMov_I_F_FT<"movz.s", GPR32Opnd, FGR32Opnd, II_MOVZ_S>, + CMov_I_F_FM<18, 16>, INSN_MIPS4_32_NOT_32R6_64R6; 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 MOVZ_I64_S : CMov_I_F_FT<"movz.s", GPR64Opnd, FGR32Opnd, II_MOVZ_S>, + CMov_I_F_FM<18, 16>, INSN_MIPS4_32_NOT_32R6_64R6, + AdditionalRequires<[HasMips64]>; -def MOVN_I_S : CMov_I_F_FT<"movn.s", GPR32Opnd, FGR32Opnd, IIFmove>, - CMov_I_F_FM<19, 16>; +def MOVN_I_S : MMRel, CMov_I_F_FT<"movn.s", GPR32Opnd, FGR32Opnd, II_MOVN_S>, + CMov_I_F_FM<19, 16>, INSN_MIPS4_32_NOT_32R6_64R6; 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]>; +def MOVN_I64_S : CMov_I_F_FT<"movn.s", GPR64Opnd, FGR32Opnd, II_MOVN_S>, + CMov_I_F_FM<19, 16>, INSN_MIPS4_32_NOT_32R6_64R6, + AdditionalRequires<[IsGP64bit]>; -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>; -} +def MOVZ_I_D32 : MMRel, CMov_I_F_FT<"movz.d", GPR32Opnd, AFGR64Opnd, + II_MOVZ_D>, CMov_I_F_FM<18, 17>, + INSN_MIPS4_32_NOT_32R6_64R6, FGR_32; +def MOVN_I_D32 : MMRel, CMov_I_F_FT<"movn.d", GPR32Opnd, AFGR64Opnd, + II_MOVN_D>, CMov_I_F_FM<19, 17>, + INSN_MIPS4_32_NOT_32R6_64R6, FGR_32; -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 DecoderNamespace = "Mips64" in { + def MOVZ_I_D64 : CMov_I_F_FT<"movz.d", GPR32Opnd, FGR64Opnd, II_MOVZ_D>, + CMov_I_F_FM<18, 17>, INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; + def MOVN_I_D64 : CMov_I_F_FT<"movn.d", GPR32Opnd, FGR64Opnd, II_MOVN_D>, + CMov_I_F_FM<19, 17>, INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; 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 MOVZ_I64_D64 : CMov_I_F_FT<"movz.d", GPR64Opnd, FGR64Opnd, II_MOVZ_D>, + CMov_I_F_FM<18, 17>, INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; + def MOVN_I64_D64 : CMov_I_F_FT<"movn.d", GPR64Opnd, FGR64Opnd, II_MOVN_D>, + CMov_I_F_FM<19, 17>, INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; } } -def MOVT_I : MMRel, CMov_F_I_FT<"movt", GPR32Opnd, IIArith, MipsCMovFP_T>, - CMov_F_I_FM<1>; +def MOVT_I : MMRel, CMov_F_I_FT<"movt", GPR32Opnd, II_MOVT, MipsCMovFP_T>, + CMov_F_I_FM<1>, INSN_MIPS4_32_NOT_32R6_64R6; 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 MOVT_I64 : CMov_F_I_FT<"movt", GPR64Opnd, II_MOVT, MipsCMovFP_T>, + CMov_F_I_FM<1>, INSN_MIPS4_32_NOT_32R6_64R6, + AdditionalRequires<[IsGP64bit]>; -def MOVF_I : MMRel, CMov_F_I_FT<"movf", GPR32Opnd, IIArith, MipsCMovFP_F>, - CMov_F_I_FM<0>; +def MOVF_I : MMRel, CMov_F_I_FT<"movf", GPR32Opnd, II_MOVF, MipsCMovFP_F>, + CMov_F_I_FM<0>, INSN_MIPS4_32_NOT_32R6_64R6; 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 MOVF_I64 : CMov_F_I_FT<"movf", GPR64Opnd, II_MOVF, MipsCMovFP_F>, + CMov_F_I_FM<0>, INSN_MIPS4_32_NOT_32R6_64R6, + AdditionalRequires<[IsGP64bit]>; -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>; +def MOVT_S : MMRel, CMov_F_F_FT<"movt.s", FGR32Opnd, II_MOVT_S, MipsCMovFP_T>, + CMov_F_F_FM<16, 1>, INSN_MIPS4_32_NOT_32R6_64R6; +def MOVF_S : MMRel, CMov_F_F_FT<"movf.s", FGR32Opnd, II_MOVF_S, MipsCMovFP_F>, + CMov_F_F_FM<16, 0>, INSN_MIPS4_32_NOT_32R6_64R6; -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>; -} +def MOVT_D32 : MMRel, CMov_F_F_FT<"movt.d", AFGR64Opnd, II_MOVT_D, + MipsCMovFP_T>, CMov_F_F_FM<17, 1>, + INSN_MIPS4_32_NOT_32R6_64R6, FGR_32; +def MOVF_D32 : MMRel, CMov_F_F_FT<"movf.d", AFGR64Opnd, II_MOVF_D, + MipsCMovFP_F>, CMov_F_F_FM<17, 0>, + INSN_MIPS4_32_NOT_32R6_64R6, FGR_32; -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>; +let DecoderNamespace = "Mips64" in { + def MOVT_D64 : CMov_F_F_FT<"movt.d", FGR64Opnd, II_MOVT_D, MipsCMovFP_T>, + CMov_F_F_FM<17, 1>, INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; + def MOVF_D64 : CMov_F_F_FT<"movf.d", FGR64Opnd, II_MOVF_D, MipsCMovFP_F>, + CMov_F_F_FM<17, 0>, INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; } // 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 : MovzPats0<GPR32, GPR32, MOVZ_I_I, SLT, SLTu, SLTi, SLTiu>, + INSN_MIPS4_32_NOT_32R6_64R6; +defm : MovzPats1<GPR32, GPR32, MOVZ_I_I, XOR>, INSN_MIPS4_32_NOT_32R6_64R6; +defm : MovzPats2<GPR32, GPR32, MOVZ_I_I, XORi>, INSN_MIPS4_32_NOT_32R6_64R6; -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, GPR64, MOVZ_I_I64, SLT, SLTu, SLTi, SLTiu>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats0<GPR64, GPR32, MOVZ_I_I, SLT64, SLTu64, SLTi64, SLTiu64>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats0<GPR64, GPR64, MOVZ_I_I64, SLT64, SLTu64, SLTi64, SLTiu64>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats1<GPR32, GPR64, MOVZ_I_I64, XOR>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats1<GPR64, GPR32, MOVZ_I64_I, XOR64>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats1<GPR64, GPR64, MOVZ_I64_I64, XOR64>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats2<GPR32, GPR64, MOVZ_I_I64, XORi>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats2<GPR64, GPR32, MOVZ_I64_I, XORi64>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats2<GPR64, GPR64, MOVZ_I64_I64, XORi64>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; -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>; -} +defm : MovnPats<GPR32, GPR32, MOVN_I_I, XOR>, INSN_MIPS4_32_NOT_32R6_64R6; -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>; -} +defm : MovnPats<GPR32, GPR64, MOVN_I_I64, XOR>, INSN_MIPS4_32_NOT_32R6_64R6, + GPR_64; +defm : MovnPats<GPR64, GPR32, MOVN_I64_I, XOR64>, INSN_MIPS4_32_NOT_32R6_64R6, + GPR_64; +defm : MovnPats<GPR64, GPR64, MOVN_I64_I64, XOR64>, INSN_MIPS4_32_NOT_32R6_64R6, + GPR_64; + +defm : MovzPats0<GPR32, FGR32, MOVZ_I_S, SLT, SLTu, SLTi, SLTiu>, + INSN_MIPS4_32_NOT_32R6_64R6; +defm : MovzPats1<GPR32, FGR32, MOVZ_I_S, XOR>, INSN_MIPS4_32_NOT_32R6_64R6; +defm : MovnPats<GPR32, FGR32, MOVN_I_S, XOR>, INSN_MIPS4_32_NOT_32R6_64R6; + +defm : MovzPats0<GPR64, FGR32, MOVZ_I_S, SLT64, SLTu64, SLTi64, SLTiu64>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats1<GPR64, FGR32, MOVZ_I64_S, XOR64>, INSN_MIPS4_32_NOT_32R6_64R6, + GPR_64; +defm : MovnPats<GPR64, FGR32, MOVN_I64_S, XOR64>, INSN_MIPS4_32_NOT_32R6_64R6, + GPR_64; + +defm : MovzPats0<GPR32, AFGR64, MOVZ_I_D32, SLT, SLTu, SLTi, SLTiu>, + INSN_MIPS4_32_NOT_32R6_64R6, FGR_32; +defm : MovzPats1<GPR32, AFGR64, MOVZ_I_D32, XOR>, INSN_MIPS4_32_NOT_32R6_64R6, + FGR_32; +defm : MovnPats<GPR32, AFGR64, MOVN_I_D32, XOR>, INSN_MIPS4_32_NOT_32R6_64R6, + FGR_32; + +defm : MovzPats0<GPR32, FGR64, MOVZ_I_D64, SLT, SLTu, SLTi, SLTiu>, + INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; +defm : MovzPats0<GPR64, FGR64, MOVZ_I_D64, SLT64, SLTu64, SLTi64, SLTiu64>, + INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; +defm : MovzPats1<GPR32, FGR64, MOVZ_I_D64, XOR>, INSN_MIPS4_32_NOT_32R6_64R6, + FGR_64; +defm : MovzPats1<GPR64, FGR64, MOVZ_I64_D64, XOR64>, + INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; +defm : MovnPats<GPR32, FGR64, MOVN_I_D64, XOR>, INSN_MIPS4_32_NOT_32R6_64R6, + FGR_64; +defm : MovnPats<GPR64, FGR64, MOVN_I64_D64, XOR64>, INSN_MIPS4_32_NOT_32R6_64R6, + FGR_64; diff --git a/lib/Target/Mips/MipsConstantIslandPass.cpp b/lib/Target/Mips/MipsConstantIslandPass.cpp index c46bbacf6585..80bf573a9625 100644 --- a/lib/Target/Mips/MipsConstantIslandPass.cpp +++ b/lib/Target/Mips/MipsConstantIslandPass.cpp @@ -17,12 +17,10 @@ // // 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. +// non-linux targets. // // -#define DEBUG_TYPE "mips-constant-islands" - #include "Mips.h" #include "MCTargetDesc/MipsBaseInfo.h" #include "Mips16InstrInfo.h" @@ -34,19 +32,21 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/IR/Function.h" +#include "llvm/IR/InstIterator.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/InstIterator.h" +#include "llvm/Support/Format.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; +#define DEBUG_TYPE "mips-constant-islands" + STATISTIC(NumCPEs, "Number of constpool entries"); STATISTIC(NumSplit, "Number of uncond branches inserted"); STATISTIC(NumCBrFixed, "Number of cond branches fixed"); @@ -77,6 +77,113 @@ static cl::opt<bool> NoLoadRelaxation( cl::desc("Don't relax loads to long loads - for testing purposes"), cl::Hidden); +static unsigned int branchTargetOperand(MachineInstr *MI) { + switch (MI->getOpcode()) { + case Mips::Bimm16: + case Mips::BimmX16: + case Mips::Bteqz16: + case Mips::BteqzX16: + case Mips::Btnez16: + case Mips::BtnezX16: + case Mips::JalB16: + return 0; + case Mips::BeqzRxImm16: + case Mips::BeqzRxImmX16: + case Mips::BnezRxImm16: + case Mips::BnezRxImmX16: + return 1; + } + llvm_unreachable("Unknown branch type"); +} + +static bool isUnconditionalBranch(unsigned int Opcode) { + switch (Opcode) { + default: return false; + case Mips::Bimm16: + case Mips::BimmX16: + case Mips::JalB16: + return true; + } +} + +static unsigned int longformBranchOpcode(unsigned int Opcode) { + switch (Opcode) { + case Mips::Bimm16: + case Mips::BimmX16: + return Mips::BimmX16; + case Mips::Bteqz16: + case Mips::BteqzX16: + return Mips::BteqzX16; + case Mips::Btnez16: + case Mips::BtnezX16: + return Mips::BtnezX16; + case Mips::JalB16: + return Mips::JalB16; + case Mips::BeqzRxImm16: + case Mips::BeqzRxImmX16: + return Mips::BeqzRxImmX16; + case Mips::BnezRxImm16: + case Mips::BnezRxImmX16: + return Mips::BnezRxImmX16; + } + llvm_unreachable("Unknown branch type"); +} + +// +// FIXME: need to go through this whole constant islands port and check the math +// for branch ranges and clean this up and make some functions to calculate things +// that are done many times identically. +// Need to refactor some of the code to call this routine. +// +static unsigned int branchMaxOffsets(unsigned int Opcode) { + unsigned Bits, Scale; + switch (Opcode) { + case Mips::Bimm16: + Bits = 11; + Scale = 2; + break; + case Mips::BimmX16: + Bits = 16; + Scale = 2; + break; + case Mips::BeqzRxImm16: + Bits = 8; + Scale = 2; + break; + case Mips::BeqzRxImmX16: + Bits = 16; + Scale = 2; + break; + case Mips::BnezRxImm16: + Bits = 8; + Scale = 2; + break; + case Mips::BnezRxImmX16: + Bits = 16; + Scale = 2; + break; + case Mips::Bteqz16: + Bits = 8; + Scale = 2; + break; + case Mips::BteqzX16: + Bits = 16; + Scale = 2; + break; + case Mips::Btnez16: + Bits = 8; + Scale = 2; + break; + case Mips::BtnezX16: + Bits = 16; + Scale = 2; + break; + default: + llvm_unreachable("Unknown branch type"); + } + unsigned MaxOffs = ((1 << (Bits-1))-1) * Scale; + return MaxOffs; +} namespace { @@ -258,17 +365,16 @@ namespace { 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){} + : MachineFunctionPass(ID), TM(tm), + IsPIC(TM.getRelocationModel() == Reloc::PIC_), + ABI(TM.getSubtarget<MipsSubtarget>().getTargetABI()), STI(nullptr), + MF(nullptr), MCP(nullptr), PrescannedForConstants(false) {} - virtual const char *getPassName() const { + const char *getPassName() const override { return "Mips Constant Islands"; } - bool runOnMachineFunction(MachineFunction &F); + bool runOnMachineFunction(MachineFunction &F) override; void doInitialPlacement(std::vector<MachineInstr*> &CPEMIs); CPEntry *findConstPoolEntry(unsigned CPI, const MachineInstr *CPEMI); @@ -277,16 +383,12 @@ namespace { 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); @@ -320,14 +422,6 @@ namespace { 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) { @@ -355,9 +449,9 @@ bool MipsConstantIslands::runOnMachineFunction(MachineFunction &mf) { // FIXME: MF = &mf; MCP = mf.getConstantPool(); + STI = &mf.getTarget().getSubtarget<MipsSubtarget>(); DEBUG(dbgs() << "constant island machine function " << "\n"); - if (!TM.getSubtarget<MipsSubtarget>().inMips16Mode() || - !MipsSubtarget::useConstantIslands()) { + if (!STI->inMips16Mode() || !MipsSubtarget::useConstantIslands()) { return false; } TII = (const Mips16InstrInfo*)MF->getTarget().getInstrInfo(); @@ -509,10 +603,10 @@ 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()) + if (std::next(MBBI) == MBB->getParent()->end()) return false; - MachineBasicBlock *NextBB = llvm::next(MBBI); + MachineBasicBlock *NextBB = std::next(MBBI); for (MachineBasicBlock::succ_iterator I = MBB->succ_begin(), E = MBB->succ_end(); I != E; ++I) if (*I == NextBB) @@ -533,7 +627,7 @@ MipsConstantIslands::CPEntry if (CPEs[i].CPEMI == CPEMI) return &CPEs[i]; } - return NULL; + return nullptr; } /// getCPELogAlign - Returns the required alignment of the constant pool entry @@ -603,6 +697,55 @@ initializeFunctionInfo(const std::vector<MachineInstr*> &CPEMIs) { Bits = 16; Scale = 2; isCond = false; + break; + case Mips::BeqzRxImm16: + UOpc=Mips::Bimm16; + Bits = 8; + Scale = 2; + isCond = true; + break; + case Mips::BeqzRxImmX16: + UOpc=Mips::Bimm16; + Bits = 16; + Scale = 2; + isCond = true; + break; + case Mips::BnezRxImm16: + UOpc=Mips::Bimm16; + Bits = 8; + Scale = 2; + isCond = true; + break; + case Mips::BnezRxImmX16: + UOpc=Mips::Bimm16; + Bits = 16; + Scale = 2; + isCond = true; + break; + case Mips::Bteqz16: + UOpc=Mips::Bimm16; + Bits = 8; + Scale = 2; + isCond = true; + break; + case Mips::BteqzX16: + UOpc=Mips::Bimm16; + Bits = 16; + Scale = 2; + isCond = true; + break; + case Mips::Btnez16: + UOpc=Mips::Bimm16; + Bits = 8; + Scale = 2; + isCond = true; + break; + case Mips::BtnezX16: + UOpc=Mips::Bimm16; + Bits = 16; + Scale = 2; + isCond = true; + break; } // Record this immediate branch. unsigned MaxOffs = ((1 << (Bits-1))-1) * Scale; @@ -634,11 +777,11 @@ initializeFunctionInfo(const std::vector<MachineInstr*> &CPEMIs) { Bits = 8; Scale = 4; LongFormOpcode = Mips::LwRxPcTcpX16; - LongFormBits = 16; + LongFormBits = 14; LongFormScale = 1; break; case Mips::LwRxPcTcpX16: - Bits = 16; + Bits = 14; Scale = 1; NegOk = true; break; @@ -776,7 +919,7 @@ MachineBasicBlock *MipsConstantIslands::splitBlockBeforeInstr CompareMBBNumbers); MachineBasicBlock* WaterBB = *IP; if (WaterBB == OrigBB) - WaterList.insert(llvm::next(IP), NewBB); + WaterList.insert(std::next(IP), NewBB); else WaterList.insert(IP, OrigBB); NewWaterList.insert(OrigBB); @@ -921,7 +1064,7 @@ bool MipsConstantIslands::decrementCPEReferenceCount(unsigned CPI, assert(CPE && "Unexpected!"); if (--CPE->RefCount == 0) { removeDeadCPEMI(CPEMI); - CPE->CPEMI = NULL; + CPE->CPEMI = nullptr; --NumCPEs; return true; } @@ -954,7 +1097,7 @@ int MipsConstantIslands::findInRangeCPEntry(CPUser& U, unsigned UserOffset) if (CPEs[i].CPEMI == CPEMI) continue; // Removing CPEs can leave empty entries, skip - if (CPEs[i].CPEMI == NULL) + if (CPEs[i].CPEMI == nullptr) continue; if (isCPEntryInRange(UserMI, UserOffset, CPEs[i].CPEMI, U.getMaxDisp(), U.NegOk)) { @@ -1010,7 +1153,7 @@ int MipsConstantIslands::findLongFormInRangeCPEntry if (CPEs[i].CPEMI == CPEMI) continue; // Removing CPEs can leave empty entries, skip - if (CPEs[i].CPEMI == NULL) + if (CPEs[i].CPEMI == nullptr) continue; if (isCPEntryInRange(UserMI, UserOffset, CPEs[i].CPEMI, U.getLongFormMaxDisp(), U.NegOk)) { @@ -1062,7 +1205,7 @@ bool MipsConstantIslands::findAvailableWater(CPUser &U, unsigned UserOffset, return false; unsigned BestGrowth = ~0u; - for (water_iterator IP = prior(WaterList.end()), B = WaterList.begin();; + for (water_iterator IP = std::prev(WaterList.end()), B = WaterList.begin();; --IP) { MachineBasicBlock* WaterBB = *IP; // Check if water is in range and is either at a lower address than the @@ -1121,7 +1264,7 @@ void MipsConstantIslands::createNewWater(unsigned CPUserIndex, 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)); + NewMBB = std::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 @@ -1174,8 +1317,7 @@ void MipsConstantIslands::createNewWater(unsigned CPUserIndex, //MachineInstr *LastIT = 0; for (unsigned Offset = UserOffset+TII->GetInstSizeInBytes(UserMI); Offset < BaseInsertOffset; - Offset += TII->GetInstSizeInBytes(MI), - MI = llvm::next(MI)) { + Offset += TII->GetInstSizeInBytes(MI), MI = std::next(MI)) { assert(MI != UserMBB->end() && "Fell off end of block"); if (CPUIndex < NumCPUsers && CPUsers[CPUIndex].MI == MI) { CPUser &U = CPUsers[CPUIndex]; @@ -1232,7 +1374,7 @@ bool MipsConstantIslands::handleConstantPoolUser(unsigned CPUserIndex) { NewWaterList.insert(NewIsland); // The new CPE goes before the following block (NewMBB). - NewMBB = llvm::next(MachineFunction::iterator(WaterBB)); + NewMBB = std::next(MachineFunction::iterator(WaterBB)); } else { // No water found. @@ -1250,7 +1392,7 @@ bool MipsConstantIslands::handleConstantPoolUser(unsigned CPUserIndex) { // 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)); + MachineBasicBlock *WaterBB = std::prev(MachineFunction::iterator(NewMBB)); IP = std::find(WaterList.begin(), WaterList.end(), WaterBB); if (IP != WaterList.end()) NewWaterList.erase(WaterBB); @@ -1275,6 +1417,10 @@ bool MipsConstantIslands::handleConstantPoolUser(unsigned CPUserIndex) { // Decrement the old entry, and remove it if refcount becomes 0. decrementCPEReferenceCount(CPI, CPEMI); + // No existing clone of this CPE is within range. + // We will be generating a new clone. Get a UID for it. + unsigned ID = createPICLabelUId(); + // Now that we have an island to add the CPE to, clone the original CPE and // add it to the island. U.HighWaterMark = NewIsland; @@ -1288,11 +1434,9 @@ bool MipsConstantIslands::handleConstantPoolUser(unsigned CPUserIndex) { // Increase the size of the island block to account for the new entry. BBInfo[NewIsland->getNumber()].Size += Size; - adjustBBOffsetsAfter(llvm::prior(MachineFunction::iterator(NewIsland))); + adjustBBOffsetsAfter(std::prev(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) @@ -1341,7 +1485,7 @@ bool MipsConstantIslands::removeUnusedCPEntries() { 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; + CPEs[j].CPEMI = nullptr; MadeChange = true; } } @@ -1380,7 +1524,8 @@ unsigned PCAdj = 4; /// away to fit in its displacement field. bool MipsConstantIslands::fixupImmediateBr(ImmBranch &Br) { MachineInstr *MI = Br.MI; - MachineBasicBlock *DestBB = MI->getOperand(0).getMBB(); + unsigned TargetOperand = branchTargetOperand(MI); + MachineBasicBlock *DestBB = MI->getOperand(TargetOperand).getMBB(); // Check to see if the DestBB is already in-range. if (isBBInRange(MI, DestBB, Br.MaxDisp)) @@ -1399,9 +1544,29 @@ bool MipsConstantIslands::fixupUnconditionalBr(ImmBranch &Br) { MachineInstr *MI = Br.MI; MachineBasicBlock *MBB = MI->getParent(); + MachineBasicBlock *DestBB = MI->getOperand(0).getMBB(); // Use BL to implement far jump. - Br.MaxDisp = ((1 << 16)-1) * 2; - MI->setDesc(TII->get(Mips::BimmX16)); + unsigned BimmX16MaxDisp = ((1 << 16)-1) * 2; + if (isBBInRange(MI, DestBB, BimmX16MaxDisp)) { + Br.MaxDisp = BimmX16MaxDisp; + MI->setDesc(TII->get(Mips::BimmX16)); + } + else { + // need to give the math a more careful look here + // this is really a segment address and not + // a PC relative address. FIXME. But I think that + // just reducing the bits by 1 as I've done is correct. + // The basic block we are branching too much be longword aligned. + // we know that RA is saved because we always save it right now. + // this requirement will be relaxed later but we also have an alternate + // way to implement this that I will implement that does not need jal. + // We should have a way to back out this alignment restriction if we "can" later. + // but it is not harmful. + // + DestBB->setAlignment(2); + Br.MaxDisp = ((1<<24)-1) * 2; + MI->setDesc(TII->get(Mips::JalB16)); + } BBInfo[MBB->getNumber()].Size += 2; adjustBBOffsetsAfter(MBB); HasFarJump = true; @@ -1412,23 +1577,33 @@ MipsConstantIslands::fixupUnconditionalBr(ImmBranch &Br) { 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(); + unsigned TargetOperand = branchTargetOperand(MI); + MachineBasicBlock *DestBB = MI->getOperand(TargetOperand).getMBB(); + unsigned Opcode = MI->getOpcode(); + unsigned LongFormOpcode = longformBranchOpcode(Opcode); + unsigned LongFormMaxOff = branchMaxOffsets(LongFormOpcode); + + // Check to see if the DestBB is already in-range. + if (isBBInRange(MI, DestBB, LongFormMaxOff)) { + Br.MaxDisp = LongFormMaxOff; + MI->setDesc(TII->get(LongFormOpcode)); + return true; + } // Add an unconditional branch to the destination and invert the branch // condition to jump over it: - // blt L1 + // bteqz L1 // => - // bge L2 + // bnez 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, @@ -1436,29 +1611,34 @@ MipsConstantIslands::fixupConditionalBr(ImmBranch &Br) { MachineBasicBlock *MBB = MI->getParent(); MachineInstr *BMI = &MBB->back(); bool NeedSplit = (BMI != MI) || !BBHasFallthrough(MBB); - + unsigned OppositeBranchOpcode = TII->getOppositeBranchOpc(Opcode); + ++NumCBrFixed; if (BMI != MI) { - if (llvm::next(MachineBasicBlock::iterator(MI)) == prior(MBB->end()) && - BMI->getOpcode() == Br.UncondBr) { + if (std::next(MachineBasicBlock::iterator(MI)) == std::prev(MBB->end()) && + isUnconditionalBranch(BMI->getOpcode())) { // Last MI in the BB is an unconditional branch. Can we simply invert the // condition and swap destinations: - // beq L1 + // beqz L1 // b L2 // => - // bne L2 + // bnez L2 // b L1 - MachineBasicBlock *NewDest = BMI->getOperand(0).getMBB(); + unsigned BMITargetOperand = branchTargetOperand(BMI); + MachineBasicBlock *NewDest = + BMI->getOperand(BMITargetOperand).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); + MI->setDesc(TII->get(OppositeBranchOpcode)); + BMI->getOperand(BMITargetOperand).setMBB(DestBB); + MI->getOperand(TargetOperand).setMBB(NewDest); return true; } } } + if (NeedSplit) { splitBlockBeforeInstr(MI); // No need for the branch to the next block. We're adding an unconditional @@ -1468,7 +1648,7 @@ MipsConstantIslands::fixupConditionalBr(ImmBranch &Br) { MBB->back().eraseFromParent(); // BBInfo[SplitBB].Offset is wrong temporarily, fixed below } - MachineBasicBlock *NextBB = llvm::next(MachineFunction::iterator(MBB)); + MachineBasicBlock *NextBB = std::next(MachineFunction::iterator(MBB)); DEBUG(dbgs() << " Insert B to BB#" << DestBB->getNumber() << " also invert condition and change dest. to BB#" @@ -1476,8 +1656,14 @@ MipsConstantIslands::fixupConditionalBr(ImmBranch &Br) { // 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); + if (MI->getNumExplicitOperands() == 2) { + BuildMI(MBB, DebugLoc(), TII->get(OppositeBranchOpcode)) + .addReg(MI->getOperand(0).getReg()) + .addMBB(NextBB); + } else { + BuildMI(MBB, DebugLoc(), TII->get(OppositeBranchOpcode)) + .addMBB(NextBB); + } Br.MI = &MBB->back(); BBInfo[MBB->getNumber()].Size += TII->GetInstSizeInBytes(&MBB->back()); BuildMI(MBB, DebugLoc(), TII->get(Br.UncondBr)).addMBB(DestBB); @@ -1496,13 +1682,13 @@ MipsConstantIslands::fixupConditionalBr(ImmBranch &Br) { 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: { + PrescannedForConstants = true; DEBUG(dbgs() << "constant island constant " << *I << "\n"); J = I->getNumOperands(); DEBUG(dbgs() << "num operands " << J << "\n"); diff --git a/lib/Target/Mips/MipsDSPInstrFormats.td b/lib/Target/Mips/MipsDSPInstrFormats.td index cf09113cd8ad..b5d52ced9d3d 100644 --- a/lib/Target/Mips/MipsDSPInstrFormats.td +++ b/lib/Target/Mips/MipsDSPInstrFormats.td @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// -def HasDSP : Predicate<"Subtarget.hasDSP()">, +def HasDSP : Predicate<"Subtarget->hasDSP()">, AssemblerPredicate<"FeatureDSP">; -def HasDSPR2 : Predicate<"Subtarget.hasDSPR2()">, +def HasDSPR2 : Predicate<"Subtarget->hasDSPR2()">, AssemblerPredicate<"FeatureDSPR2">; // Fields. diff --git a/lib/Target/Mips/MipsDelaySlotFiller.cpp b/lib/Target/Mips/MipsDelaySlotFiller.cpp index ffbd83b1bbbf..bcfbc12df01c 100644 --- a/lib/Target/Mips/MipsDelaySlotFiller.cpp +++ b/lib/Target/Mips/MipsDelaySlotFiller.cpp @@ -11,8 +11,7 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "delay-slot-filler" - +#include "MCTargetDesc/MipsMCNaCl.h" #include "Mips.h" #include "MipsInstrInfo.h" #include "MipsTargetMachine.h" @@ -24,6 +23,7 @@ #include "llvm/CodeGen/MachineBranchProbabilityInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/Support/CommandLine.h" #include "llvm/Target/TargetInstrInfo.h" @@ -32,6 +32,8 @@ using namespace llvm; +#define DEBUG_TYPE "delay-slot-filler" + STATISTIC(FilledSlots, "Number of delay slots filled"); STATISTIC(UsefulSlots, "Number of delay slots filled with instructions that" " are not NOP."); @@ -65,20 +67,6 @@ namespace { 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); @@ -137,7 +125,7 @@ namespace { public: NoMemInstr() : InspectMemInstr(true) {} private: - virtual bool hasHazard_(const MachineInstr &MI) { return true; } + bool hasHazard_(const MachineInstr &MI) override { return true; } }; /// This subclass accepts loads from stacks and constant loads. @@ -145,7 +133,7 @@ namespace { public: LoadFromStackOrConst() : InspectMemInstr(false) {} private: - virtual bool hasHazard_(const MachineInstr &MI); + bool hasHazard_(const MachineInstr &MI) override; }; /// This subclass uses memory dependence information to determine whether a @@ -155,19 +143,21 @@ namespace { MemDefsUses(const MachineFrameInfo *MFI); private: - virtual bool hasHazard_(const MachineInstr &MI); + typedef PointerUnion<const Value *, const PseudoSourceValue *> ValueType; + + bool hasHazard_(const MachineInstr &MI) override; /// 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); + bool updateDefsUses(ValueType V, bool MayStore); /// Get the list of underlying objects of MI's memory operand. bool getUnderlyingObjects(const MachineInstr &MI, - SmallVectorImpl<const Value *> &Objects) const; + SmallVectorImpl<ValueType> &Objects) const; const MachineFrameInfo *MFI; - SmallPtrSet<const Value*, 4> Uses, Defs; + SmallPtrSet<ValueType, 4> Uses, Defs; /// Flags indicating whether loads or stores with no underlying objects have /// been seen. @@ -179,19 +169,26 @@ namespace { Filler(TargetMachine &tm) : MachineFunctionPass(ID), TM(tm) { } - virtual const char *getPassName() const { + const char *getPassName() const override { return "Mips Delay Slot Filler"; } - bool runOnMachineFunction(MachineFunction &F) { + bool runOnMachineFunction(MachineFunction &F) override { bool Changed = false; for (MachineFunction::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI) Changed |= runOnMachineBasicBlock(*FI); + + // This pass invalidates liveness information when it reorders + // instructions to fill delay slot. Without this, -verify-machineinstrs + // will fail. + if (Changed) + F.getRegInfo().invalidateLiveness(); + return Changed; } - void getAnalysisUsage(AnalysisUsage &AU) const { + void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired<MachineBranchProbabilityInfo>(); MachineFunctionPass::getAnalysisUsage(AU); } @@ -412,16 +409,15 @@ bool LoadFromStackOrConst::hasHazard_(const MachineInstr &MI) { if (MI.mayStore()) return true; - if (!MI.hasOneMemOperand() || !(*MI.memoperands_begin())->getValue()) + if (!MI.hasOneMemOperand() || !(*MI.memoperands_begin())->getPseudoValue()) 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(); + if (const PseudoSourceValue *PSV = + (*MI.memoperands_begin())->getPseudoValue()) { + if (isa<FixedStackPseudoSourceValue>(PSV)) + return false; + return !PSV->isConstant(nullptr) && PSV != PseudoSourceValue::getStack(); + } return true; } @@ -432,11 +428,11 @@ MemDefsUses::MemDefsUses(const MachineFrameInfo *MFI_) bool MemDefsUses::hasHazard_(const MachineInstr &MI) { bool HasHazard = false; - SmallVector<const Value *, 4> Objs; + SmallVector<ValueType, 4> Objs; // Check underlying object list. if (getUnderlyingObjects(MI, Objs)) { - for (SmallVectorImpl<const Value *>::const_iterator I = Objs.begin(); + for (SmallVectorImpl<ValueType>::const_iterator I = Objs.begin(); I != Objs.end(); ++I) HasHazard |= updateDefsUses(*I, MI.mayStore()); @@ -453,7 +449,7 @@ bool MemDefsUses::hasHazard_(const MachineInstr &MI) { return HasHazard; } -bool MemDefsUses::updateDefsUses(const Value *V, bool MayStore) { +bool MemDefsUses::updateDefsUses(ValueType V, bool MayStore) { if (MayStore) return !Defs.insert(V) || Uses.count(V) || SeenNoObjStore || SeenNoObjLoad; @@ -463,10 +459,20 @@ bool MemDefsUses::updateDefsUses(const Value *V, bool MayStore) { bool MemDefsUses:: getUnderlyingObjects(const MachineInstr &MI, - SmallVectorImpl<const Value *> &Objects) const { - if (!MI.hasOneMemOperand() || !(*MI.memoperands_begin())->getValue()) + SmallVectorImpl<ValueType> &Objects) const { + if (!MI.hasOneMemOperand() || + (!(*MI.memoperands_begin())->getValue() && + !(*MI.memoperands_begin())->getPseudoValue())) return false; + if (const PseudoSourceValue *PSV = + (*MI.memoperands_begin())->getPseudoValue()) { + if (!PSV->isAliased(MFI)) + return false; + Objects.push_back(PSV); + return true; + } + const Value *V = (*MI.memoperands_begin())->getValue(); SmallVector<Value *, 4> Objs; @@ -474,10 +480,7 @@ getUnderlyingObjects(const MachineInstr &MI, 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)) + if (!isIdentifiedObject(V)) return false; Objects.push_back(*I); @@ -514,8 +517,8 @@ bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { // 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))); + BuildMI(MBB, std::next(I), I->getDebugLoc(), TII->get(Mips::NOP)); + MIBundleBuilder(MBB, I, std::next(I, 2)); } return Changed; @@ -545,6 +548,18 @@ bool Filler::searchRange(MachineBasicBlock &MBB, IterTy Begin, IterTy End, if (delayHasHazard(*I, RegDU, IM)) continue; + if (TM.getSubtarget<MipsSubtarget>().isTargetNaCl()) { + // In NaCl, instructions that must be masked are forbidden in delay slots. + // We only check for loads, stores and SP changes. Calls, returns and + // branches are not checked because non-NaCl targets never put them in + // delay slots. + unsigned AddrIdx; + if ((isBasePlusOffsetMemoryAccess(I->getOpcode(), &AddrIdx) + && baseRegNeedsLoadStoreMask(I->getOperand(AddrIdx).getReg())) + || I->modifiesRegister(Mips::SP, TM.getRegisterInfo())) + continue; + } + Filler = I; return true; } @@ -565,8 +580,8 @@ bool Filler::searchBackward(MachineBasicBlock &MBB, Iter Slot) const { 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))); + MBB.splice(std::next(Slot), &MBB, std::next(Filler).base()); + MIBundleBuilder(MBB, Slot, std::next(Slot, 2)); ++UsefulSlots; return true; } @@ -582,11 +597,11 @@ bool Filler::searchForward(MachineBasicBlock &MBB, Iter Slot) const { RegDU.setCallerSaved(*Slot); - if (!searchRange(MBB, llvm::next(Slot), MBB.end(), RegDU, NM, Filler)) + if (!searchRange(MBB, std::next(Slot), MBB.end(), RegDU, NM, Filler)) return false; - MBB.splice(llvm::next(Slot), &MBB, Filler); - MIBundleBuilder(MBB, Slot, llvm::next(llvm::next(Slot))); + MBB.splice(std::next(Slot), &MBB, Filler); + MIBundleBuilder(MBB, Slot, std::next(Slot, 2)); ++UsefulSlots; return true; } @@ -603,7 +618,7 @@ bool Filler::searchSuccBBs(MachineBasicBlock &MBB, Iter Slot) const { RegDefsUses RegDU(TM); bool HasMultipleSuccs = false; BB2BrMap BrMap; - OwningPtr<InspectMemInstr> IM; + std::unique_ptr<InspectMemInstr> IM; Iter Filler; // Iterate over SuccBB's predecessor list. @@ -637,19 +652,23 @@ bool Filler::searchSuccBBs(MachineBasicBlock &MBB, Iter Slot) const { MachineBasicBlock *Filler::selectSuccBB(MachineBasicBlock &B) const { if (B.succ_empty()) - return NULL; + return nullptr; // 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; + auto &Prob = getAnalysis<MachineBranchProbabilityInfo>(); + MachineBasicBlock *S = *std::max_element(B.succ_begin(), B.succ_end(), + [&](const MachineBasicBlock *Dst0, + const MachineBasicBlock *Dst1) { + return Prob.getEdgeWeight(&B, Dst0) < Prob.getEdgeWeight(&B, Dst1); + }); + return S->isLandingPad() ? nullptr : 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; + MachineBasicBlock *TrueBB = nullptr, *FalseBB = nullptr; SmallVector<MachineInstr*, 2> BranchInstrs; SmallVector<MachineOperand, 2> Cond; @@ -657,11 +676,11 @@ Filler::getBranch(MachineBasicBlock &MBB, const MachineBasicBlock &Dst) const { TII->AnalyzeBranch(MBB, TrueBB, FalseBB, Cond, false, BranchInstrs); if ((R == MipsInstrInfo::BT_None) || (R == MipsInstrInfo::BT_NoBranch)) - return std::make_pair(R, (MachineInstr*)NULL); + return std::make_pair(R, nullptr); if (R != MipsInstrInfo::BT_CondUncond) { if (!hasUnoccupiedSlot(BranchInstrs[0])) - return std::make_pair(MipsInstrInfo::BT_None, (MachineInstr*)NULL); + return std::make_pair(MipsInstrInfo::BT_None, nullptr); assert(((R != MipsInstrInfo::BT_Uncond) || (TrueBB == &Dst))); @@ -678,7 +697,7 @@ Filler::getBranch(MachineBasicBlock &MBB, const MachineBasicBlock &Dst) const { if (hasUnoccupiedSlot(BranchInstrs[1]) && (FalseBB == &Dst)) return std::make_pair(MipsInstrInfo::BT_Uncond, BranchInstrs[1]); - return std::make_pair(MipsInstrInfo::BT_None, (MachineInstr*)NULL); + return std::make_pair(MipsInstrInfo::BT_None, nullptr); } bool Filler::examinePred(MachineBasicBlock &Pred, const MachineBasicBlock &Succ, @@ -714,6 +733,6 @@ bool Filler::delayHasHazard(const MachineInstr &Candidate, RegDefsUses &RegDU, bool Filler::terminateSearch(const MachineInstr &Candidate) const { return (Candidate.isTerminator() || Candidate.isCall() || - Candidate.isLabel() || Candidate.isInlineAsm() || + Candidate.isPosition() || Candidate.isInlineAsm() || Candidate.hasUnmodeledSideEffects()); } diff --git a/lib/Target/Mips/MipsFastISel.cpp b/lib/Target/Mips/MipsFastISel.cpp new file mode 100644 index 000000000000..617801ba8c67 --- /dev/null +++ b/lib/Target/Mips/MipsFastISel.cpp @@ -0,0 +1,400 @@ +//===-- MipsastISel.cpp - Mips FastISel implementation +//---------------------===// + +#include "llvm/CodeGen/FunctionLoweringInfo.h" +#include "llvm/CodeGen/FastISel.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetLibraryInfo.h" +#include "MipsRegisterInfo.h" +#include "MipsISelLowering.h" +#include "MipsMachineFunction.h" +#include "MipsSubtarget.h" +#include "MipsTargetMachine.h" + +using namespace llvm; + +namespace { + +// All possible address modes. +typedef struct Address { + enum { RegBase, FrameIndexBase } BaseType; + + union { + unsigned Reg; + int FI; + } Base; + + int64_t Offset; + + // Innocuous defaults for our address. + Address() : BaseType(RegBase), Offset(0) { Base.Reg = 0; } +} Address; + +class MipsFastISel final : public FastISel { + + /// Subtarget - Keep a pointer to the MipsSubtarget around so that we can + /// make the right decision when generating code for different targets. + Module &M; + const TargetMachine &TM; + const TargetInstrInfo &TII; + const TargetLowering &TLI; + const MipsSubtarget *Subtarget; + MipsFunctionInfo *MFI; + + // Convenience variables to avoid some queries. + LLVMContext *Context; + + bool TargetSupported; + +public: + explicit MipsFastISel(FunctionLoweringInfo &funcInfo, + const TargetLibraryInfo *libInfo) + : FastISel(funcInfo, libInfo), + M(const_cast<Module &>(*funcInfo.Fn->getParent())), + TM(funcInfo.MF->getTarget()), TII(*TM.getInstrInfo()), + TLI(*TM.getTargetLowering()), + Subtarget(&TM.getSubtarget<MipsSubtarget>()) { + MFI = funcInfo.MF->getInfo<MipsFunctionInfo>(); + Context = &funcInfo.Fn->getContext(); + TargetSupported = ((Subtarget->getRelocationModel() == Reloc::PIC_) && + (Subtarget->hasMips32r2() && (Subtarget->isABI_O32()))); + } + + bool TargetSelectInstruction(const Instruction *I) override; + unsigned TargetMaterializeConstant(const Constant *C) override; + + bool ComputeAddress(const Value *Obj, Address &Addr); + +private: + bool EmitLoad(MVT VT, unsigned &ResultReg, Address &Addr, + unsigned Alignment = 0); + bool EmitStore(MVT VT, unsigned SrcReg, Address &Addr, + unsigned Alignment = 0); + bool SelectLoad(const Instruction *I); + bool SelectRet(const Instruction *I); + bool SelectStore(const Instruction *I); + + bool isTypeLegal(Type *Ty, MVT &VT); + bool isLoadTypeLegal(Type *Ty, MVT &VT); + + unsigned MaterializeFP(const ConstantFP *CFP, MVT VT); + unsigned MaterializeGV(const GlobalValue *GV, MVT VT); + unsigned MaterializeInt(const Constant *C, MVT VT); + unsigned Materialize32BitInt(int64_t Imm, const TargetRegisterClass *RC); + + // for some reason, this default is not generated by tablegen + // so we explicitly generate it here. + // + unsigned FastEmitInst_riir(uint64_t inst, const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill, uint64_t imm1, + uint64_t imm2, unsigned Op3, bool Op3IsKill) { + return 0; + } + + MachineInstrBuilder EmitInst(unsigned Opc) { + return BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)); + } + + MachineInstrBuilder EmitInst(unsigned Opc, unsigned DstReg) { + return BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), + DstReg); + } + + MachineInstrBuilder EmitInstStore(unsigned Opc, unsigned SrcReg, + unsigned MemReg, int64_t MemOffset) { + return EmitInst(Opc).addReg(SrcReg).addReg(MemReg).addImm(MemOffset); + } + + MachineInstrBuilder EmitInstLoad(unsigned Opc, unsigned DstReg, + unsigned MemReg, int64_t MemOffset) { + return EmitInst(Opc, DstReg).addReg(MemReg).addImm(MemOffset); + } + +#include "MipsGenFastISel.inc" +}; + +bool MipsFastISel::isTypeLegal(Type *Ty, MVT &VT) { + EVT evt = TLI.getValueType(Ty, true); + // Only handle simple types. + if (evt == MVT::Other || !evt.isSimple()) + return false; + VT = evt.getSimpleVT(); + + // Handle all legal types, i.e. a register that will directly hold this + // value. + return TLI.isTypeLegal(VT); +} + +bool MipsFastISel::isLoadTypeLegal(Type *Ty, MVT &VT) { + if (isTypeLegal(Ty, VT)) + return true; + // We will extend this in a later patch: + // If this is a type than can be sign or zero-extended to a basic operation + // go ahead and accept it now. + if (VT == MVT::i8 || VT == MVT::i16) + return true; + return false; +} + +bool MipsFastISel::ComputeAddress(const Value *Obj, Address &Addr) { + // This construct looks a big awkward but it is how other ports handle this + // and as this function is more fully completed, these cases which + // return false will have additional code in them. + // + if (isa<Instruction>(Obj)) + return false; + else if (isa<ConstantExpr>(Obj)) + return false; + Addr.Base.Reg = getRegForValue(Obj); + return Addr.Base.Reg != 0; +} + +bool MipsFastISel::EmitLoad(MVT VT, unsigned &ResultReg, Address &Addr, + unsigned Alignment) { + // + // more cases will be handled here in following patches. + // + unsigned Opc; + switch (VT.SimpleTy) { + case MVT::i32: { + ResultReg = createResultReg(&Mips::GPR32RegClass); + Opc = Mips::LW; + break; + } + case MVT::i16: { + ResultReg = createResultReg(&Mips::GPR32RegClass); + Opc = Mips::LHu; + break; + } + case MVT::i8: { + ResultReg = createResultReg(&Mips::GPR32RegClass); + Opc = Mips::LBu; + break; + } + case MVT::f32: { + ResultReg = createResultReg(&Mips::FGR32RegClass); + Opc = Mips::LWC1; + break; + } + case MVT::f64: { + ResultReg = createResultReg(&Mips::AFGR64RegClass); + Opc = Mips::LDC1; + break; + } + default: + return false; + } + EmitInstLoad(Opc, ResultReg, Addr.Base.Reg, Addr.Offset); + return true; +} + +// Materialize a constant into a register, and return the register +// number (or zero if we failed to handle it). +unsigned MipsFastISel::TargetMaterializeConstant(const Constant *C) { + EVT CEVT = TLI.getValueType(C->getType(), true); + + // Only handle simple types. + if (!CEVT.isSimple()) + return 0; + MVT VT = CEVT.getSimpleVT(); + + if (const ConstantFP *CFP = dyn_cast<ConstantFP>(C)) + return MaterializeFP(CFP, VT); + else if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) + return MaterializeGV(GV, VT); + else if (isa<ConstantInt>(C)) + return MaterializeInt(C, VT); + + return 0; +} + +bool MipsFastISel::EmitStore(MVT VT, unsigned SrcReg, Address &Addr, + unsigned Alignment) { + // + // more cases will be handled here in following patches. + // + unsigned Opc; + switch (VT.SimpleTy) { + case MVT::i8: + Opc = Mips::SB; + break; + case MVT::i16: + Opc = Mips::SH; + break; + case MVT::i32: + Opc = Mips::SW; + break; + case MVT::f32: + Opc = Mips::SWC1; + break; + case MVT::f64: + Opc = Mips::SDC1; + break; + default: + return false; + } + EmitInstStore(Opc, SrcReg, Addr.Base.Reg, Addr.Offset); + return true; +} + +bool MipsFastISel::SelectLoad(const Instruction *I) { + // Atomic loads need special handling. + if (cast<LoadInst>(I)->isAtomic()) + return false; + + // Verify we have a legal type before going any further. + MVT VT; + if (!isLoadTypeLegal(I->getType(), VT)) + return false; + + // See if we can handle this address. + Address Addr; + if (!ComputeAddress(I->getOperand(0), Addr)) + return false; + + unsigned ResultReg; + if (!EmitLoad(VT, ResultReg, Addr, cast<LoadInst>(I)->getAlignment())) + return false; + UpdateValueMap(I, ResultReg); + return true; +} + +bool MipsFastISel::SelectStore(const Instruction *I) { + Value *Op0 = I->getOperand(0); + unsigned SrcReg = 0; + + // Atomic stores need special handling. + if (cast<StoreInst>(I)->isAtomic()) + return false; + + // Verify we have a legal type before going any further. + MVT VT; + if (!isLoadTypeLegal(I->getOperand(0)->getType(), VT)) + return false; + + // Get the value to be stored into a register. + SrcReg = getRegForValue(Op0); + if (SrcReg == 0) + return false; + + // See if we can handle this address. + Address Addr; + if (!ComputeAddress(I->getOperand(1), Addr)) + return false; + + if (!EmitStore(VT, SrcReg, Addr, cast<StoreInst>(I)->getAlignment())) + return false; + return true; +} + +bool MipsFastISel::SelectRet(const Instruction *I) { + const ReturnInst *Ret = cast<ReturnInst>(I); + + if (!FuncInfo.CanLowerReturn) + return false; + if (Ret->getNumOperands() > 0) { + return false; + } + EmitInst(Mips::RetRA); + return true; +} + +bool MipsFastISel::TargetSelectInstruction(const Instruction *I) { + if (!TargetSupported) + return false; + switch (I->getOpcode()) { + default: + break; + case Instruction::Load: + return SelectLoad(I); + case Instruction::Store: + return SelectStore(I); + case Instruction::Ret: + return SelectRet(I); + } + return false; +} +} + +unsigned MipsFastISel::MaterializeFP(const ConstantFP *CFP, MVT VT) { + int64_t Imm = CFP->getValueAPF().bitcastToAPInt().getZExtValue(); + if (VT == MVT::f32) { + const TargetRegisterClass *RC = &Mips::FGR32RegClass; + unsigned DestReg = createResultReg(RC); + unsigned TempReg = Materialize32BitInt(Imm, &Mips::GPR32RegClass); + EmitInst(Mips::MTC1, DestReg).addReg(TempReg); + return DestReg; + } else if (VT == MVT::f64) { + const TargetRegisterClass *RC = &Mips::AFGR64RegClass; + unsigned DestReg = createResultReg(RC); + unsigned TempReg1 = Materialize32BitInt(Imm >> 32, &Mips::GPR32RegClass); + unsigned TempReg2 = + Materialize32BitInt(Imm & 0xFFFFFFFF, &Mips::GPR32RegClass); + EmitInst(Mips::BuildPairF64, DestReg).addReg(TempReg2).addReg(TempReg1); + return DestReg; + } + return 0; +} + +unsigned MipsFastISel::MaterializeGV(const GlobalValue *GV, MVT VT) { + // For now 32-bit only. + if (VT != MVT::i32) + return 0; + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + unsigned DestReg = createResultReg(RC); + const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV); + bool IsThreadLocal = GVar && GVar->isThreadLocal(); + // TLS not supported at this time. + if (IsThreadLocal) + return 0; + EmitInst(Mips::LW, DestReg).addReg(MFI->getGlobalBaseReg()).addGlobalAddress( + GV, 0, MipsII::MO_GOT); + return DestReg; +} +unsigned MipsFastISel::MaterializeInt(const Constant *C, MVT VT) { + if (VT != MVT::i32 && VT != MVT::i16 && VT != MVT::i8 && VT != MVT::i1) + return 0; + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + const ConstantInt *CI = cast<ConstantInt>(C); + int64_t Imm; + if (CI->isNegative()) + Imm = CI->getSExtValue(); + else + Imm = CI->getZExtValue(); + return Materialize32BitInt(Imm, RC); +} + +unsigned MipsFastISel::Materialize32BitInt(int64_t Imm, + const TargetRegisterClass *RC) { + unsigned ResultReg = createResultReg(RC); + + if (isInt<16>(Imm)) { + unsigned Opc = Mips::ADDiu; + EmitInst(Opc, ResultReg).addReg(Mips::ZERO).addImm(Imm); + return ResultReg; + } else if (isUInt<16>(Imm)) { + EmitInst(Mips::ORi, ResultReg).addReg(Mips::ZERO).addImm(Imm); + return ResultReg; + } + unsigned Lo = Imm & 0xFFFF; + unsigned Hi = (Imm >> 16) & 0xFFFF; + if (Lo) { + // Both Lo and Hi have nonzero bits. + unsigned TmpReg = createResultReg(RC); + EmitInst(Mips::LUi, TmpReg).addImm(Hi); + EmitInst(Mips::ORi, ResultReg).addReg(TmpReg).addImm(Lo); + } else { + EmitInst(Mips::LUi, ResultReg).addImm(Hi); + } + return ResultReg; +} + +namespace llvm { +FastISel *Mips::createFastISel(FunctionLoweringInfo &funcInfo, + const TargetLibraryInfo *libInfo) { + return new MipsFastISel(funcInfo, libInfo); +} +} diff --git a/lib/Target/Mips/MipsFrameLowering.cpp b/lib/Target/Mips/MipsFrameLowering.cpp index eb9d49fefb2f..61afe179df57 100644 --- a/lib/Target/Mips/MipsFrameLowering.cpp +++ b/lib/Target/Mips/MipsFrameLowering.cpp @@ -82,9 +82,8 @@ using namespace llvm; // //===----------------------------------------------------------------------===// -const MipsFrameLowering *MipsFrameLowering::create(MipsTargetMachine &TM, - const MipsSubtarget &ST) { - if (TM.getSubtargetImpl()->inMips16Mode()) +const MipsFrameLowering *MipsFrameLowering::create(const MipsSubtarget &ST) { + if (ST.inMips16Mode()) return llvm::createMips16FrameLowering(ST); return llvm::createMipsSEFrameLowering(ST); @@ -110,7 +109,7 @@ uint64_t MipsFrameLowering::estimateStackSize(const MachineFunction &MF) const { 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) { + for (const MCPhysReg *R = TRI.getCalleeSavedRegs(&MF); *R; ++R) { unsigned Size = TRI.getMinimalPhysRegClass(*R)->getSize(); Offset = RoundUpToAlignment(Offset + Size, Size); } diff --git a/lib/Target/Mips/MipsFrameLowering.h b/lib/Target/Mips/MipsFrameLowering.h index 6a5f79d0dfc4..9d593091e018 100644 --- a/lib/Target/Mips/MipsFrameLowering.h +++ b/lib/Target/Mips/MipsFrameLowering.h @@ -15,7 +15,6 @@ #define MIPS_FRAMEINFO_H #include "Mips.h" -#include "MipsSubtarget.h" #include "llvm/Target/TargetFrameLowering.h" namespace llvm { @@ -29,10 +28,9 @@ public: explicit MipsFrameLowering(const MipsSubtarget &sti, unsigned Alignment) : TargetFrameLowering(StackGrowsDown, Alignment, 0, Alignment), STI(sti) {} - static const MipsFrameLowering *create(MipsTargetMachine &TM, - const MipsSubtarget &ST); + static const MipsFrameLowering *create(const MipsSubtarget &ST); - bool hasFP(const MachineFunction &MF) const; + bool hasFP(const MachineFunction &MF) const override; protected: uint64_t estimateStackSize(const MachineFunction &MF) const; diff --git a/lib/Target/Mips/MipsISelDAGToDAG.cpp b/lib/Target/Mips/MipsISelDAGToDAG.cpp index c417bd593413..0bdabf37f63b 100644 --- a/lib/Target/Mips/MipsISelDAGToDAG.cpp +++ b/lib/Target/Mips/MipsISelDAGToDAG.cpp @@ -11,31 +11,32 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "mips-isel" #include "MipsISelDAGToDAG.h" -#include "Mips16ISelDAGToDAG.h" -#include "MipsSEISelDAGToDAG.h" -#include "Mips.h" #include "MCTargetDesc/MipsBaseInfo.h" +#include "Mips.h" +#include "Mips16ISelDAGToDAG.h" #include "MipsMachineFunction.h" #include "MipsRegisterInfo.h" +#include "MipsSEISelDAGToDAG.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/CFG.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; +#define DEBUG_TYPE "mips-isel" + //===----------------------------------------------------------------------===// // Instruction Selector Implementation //===----------------------------------------------------------------------===// @@ -46,6 +47,7 @@ using namespace llvm; //===----------------------------------------------------------------------===// bool MipsDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &TM.getSubtarget<MipsSubtarget>(); bool Ret = SelectionDAGISel::runOnMachineFunction(MF); processFunctionAfterISel(MF); @@ -93,6 +95,12 @@ bool MipsDAGToDAGISel::selectIntAddrMM(SDValue Addr, SDValue &Base, return false; } +bool MipsDAGToDAGISel::selectIntAddrMSA(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."); @@ -176,7 +184,7 @@ SDNode* MipsDAGToDAGISel::Select(SDNode *Node) { if (Node->isMachineOpcode()) { DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); Node->setNodeId(-1); - return NULL; + return nullptr; } // See if subclasses can handle this node. @@ -195,8 +203,9 @@ SDNode* MipsDAGToDAGISel::Select(SDNode *Node) { #ifndef NDEBUG case ISD::LOAD: case ISD::STORE: - assert(cast<MemSDNode>(Node)->getMemoryVT().getSizeInBits() / 8 <= - cast<MemSDNode>(Node)->getAlignment() && + assert((Subtarget->systemSupportsUnalignedAccess() || + cast<MemSDNode>(Node)->getMemoryVT().getSizeInBits() / 8 <= + cast<MemSDNode>(Node)->getAlignment()) && "Unexpected unaligned loads/stores."); break; #endif @@ -206,7 +215,7 @@ SDNode* MipsDAGToDAGISel::Select(SDNode *Node) { SDNode *ResNode = SelectCode(Node); DEBUG(errs() << "=> "); - if (ResNode == NULL || ResNode == Node) + if (ResNode == nullptr || ResNode == Node) DEBUG(Node->dump(CurDAG)); else DEBUG(ResNode->dump(CurDAG)); diff --git a/lib/Target/Mips/MipsISelDAGToDAG.h b/lib/Target/Mips/MipsISelDAGToDAG.h index a4d9da532b2e..52f4c0d3b9ea 100644 --- a/lib/Target/Mips/MipsISelDAGToDAG.h +++ b/lib/Target/Mips/MipsISelDAGToDAG.h @@ -32,21 +32,21 @@ namespace llvm { class MipsDAGToDAGISel : public SelectionDAGISel { public: explicit MipsDAGToDAGISel(MipsTargetMachine &TM) - : SelectionDAGISel(TM), Subtarget(TM.getSubtarget<MipsSubtarget>()) {} + : SelectionDAGISel(TM), Subtarget(nullptr) {} // Pass Name - virtual const char *getPassName() const { + const char *getPassName() const override { return "MIPS DAG->DAG Pattern Instruction Selection"; } - virtual bool runOnMachineFunction(MachineFunction &MF); + bool runOnMachineFunction(MachineFunction &MF) override; 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; + const MipsSubtarget *Subtarget; private: // Include the pieces autogenerated from the target description. @@ -73,6 +73,10 @@ private: virtual bool selectIntAddrMM(SDValue Addr, SDValue &Base, SDValue &Offset) const; + /// Match addr+simm10 and addr + virtual bool selectIntAddrMSA(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + virtual bool selectAddr16(SDNode *Parent, SDValue N, SDValue &Base, SDValue &Offset, SDValue &Alias); @@ -106,7 +110,7 @@ private: /// starting at bit zero. virtual bool selectVSplatMaskR(SDValue N, SDValue &Imm) const; - virtual SDNode *Select(SDNode *N); + SDNode *Select(SDNode *N) override; virtual std::pair<bool, SDNode*> selectNode(SDNode *Node) = 0; @@ -117,9 +121,9 @@ private: virtual void processFunctionAfterISel(MachineFunction &MF) = 0; - virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, - char ConstraintCode, - std::vector<SDValue> &OutOps); + bool SelectInlineAsmMemoryOperand(const SDValue &Op, + char ConstraintCode, + std::vector<SDValue> &OutOps) override; }; /// createMipsISelDag - This pass converts a legalized DAG into a diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index 1e8250c847fe..40dc8e41b055 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -11,7 +11,6 @@ // selection DAG. // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "mips-lower" #include "MipsISelLowering.h" #include "InstPrinter/MipsInstPrinter.h" #include "MCTargetDesc/MipsBaseInfo.h" @@ -39,6 +38,8 @@ using namespace llvm; +#define DEBUG_TYPE "mips-lower" + STATISTIC(NumTailCalls, "Number of tail calls"); static cl::opt<bool> @@ -50,16 +51,21 @@ 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] = { +cl::opt<bool> +EnableMipsFastISel("mips-fast-isel", cl::Hidden, + cl::desc("Allow mips-fast-isel to be used"), + cl::init(false)); + +static const MCPhysReg O32IntRegs[4] = { Mips::A0, Mips::A1, Mips::A2, Mips::A3 }; -static const uint16_t Mips64IntRegs[8] = { +static const MCPhysReg 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] = { +static const MCPhysReg 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 }; @@ -197,20 +203,23 @@ const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const { case MipsISD::ILVR: return "MipsISD::ILVR"; case MipsISD::PCKEV: return "MipsISD::PCKEV"; case MipsISD::PCKOD: return "MipsISD::PCKOD"; - default: return NULL; + case MipsISD::INSVE: return "MipsISD::INSVE"; + default: return nullptr; } } -MipsTargetLowering:: -MipsTargetLowering(MipsTargetMachine &TM) - : TargetLowering(TM, new MipsTargetObjectFile()), - Subtarget(&TM.getSubtarget<MipsSubtarget>()), - HasMips64(Subtarget->hasMips64()), IsN64(Subtarget->isABI_N64()), - IsO32(Subtarget->isABI_O32()) { +MipsTargetLowering::MipsTargetLowering(MipsTargetMachine &TM, + const MipsSubtarget &STI) + : TargetLowering(TM, new MipsTargetObjectFile()), Subtarget(STI) { // Mips does not have i1 type, so use i32 for // setcc operations results (slt, sgt, ...). setBooleanContents(ZeroOrOneBooleanContent); setBooleanVectorContents(ZeroOrNegativeOneBooleanContent); + // The cmp.cond.fmt instruction in MIPS32r6/MIPS64r6 uses 0 and -1 like MSA + // does. Integer booleans still use 0 and 1. + if (Subtarget.hasMips32r6()) + setBooleanContents(ZeroOrOneBooleanContent, + ZeroOrNegativeOneBooleanContent); // Load extented operations for i1 types must be promoted setLoadExtAction(ISD::EXTLOAD, MVT::i1, Promote); @@ -247,12 +256,7 @@ MipsTargetLowering(MipsTargetMachine &TM) 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) { + if (Subtarget.isGP64bit()) { setOperationAction(ISD::GlobalAddress, MVT::i64, Custom); setOperationAction(ISD::BlockAddress, MVT::i64, Custom); setOperationAction(ISD::GlobalTLSAddress, MVT::i64, Custom); @@ -264,14 +268,14 @@ MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::FP_TO_SINT, MVT::i64, Custom); } - if (!HasMips64) { + if (!Subtarget.isGP64bit()) { 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) + if (Subtarget.isGP64bit()) setOperationAction(ISD::ADD, MVT::i64, Custom); setOperationAction(ISD::SDIV, MVT::i32, Expand); @@ -288,14 +292,20 @@ MipsTargetLowering(MipsTargetMachine &TM) 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::SELECT_CC, MVT::i32, Expand); + setOperationAction(ISD::SELECT_CC, MVT::i64, 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); + if (Subtarget.hasCnMips()) { + setOperationAction(ISD::CTPOP, MVT::i32, Legal); + setOperationAction(ISD::CTPOP, MVT::i64, Legal); + } else { + 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); @@ -307,10 +317,10 @@ MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand); setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Expand); - if (!Subtarget->hasMips32r2()) + if (!Subtarget.hasMips32r2()) setOperationAction(ISD::ROTR, MVT::i32, Expand); - if (!Subtarget->hasMips64r2()) + if (!Subtarget.hasMips64r2()) setOperationAction(ISD::ROTR, MVT::i64, Expand); setOperationAction(ISD::FSIN, MVT::f32, Expand); @@ -331,11 +341,6 @@ MipsTargetLowering(MipsTargetMachine &TM) 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); @@ -353,22 +358,23 @@ MipsTargetLowering(MipsTargetMachine &TM) setInsertFencesForAtomic(true); - if (!Subtarget->hasSEInReg()) { + if (!Subtarget.hasMips32r2()) { setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand); setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); } - if (!Subtarget->hasBitCount()) { + // MIPS16 lacks MIPS32's clz and clo instructions. + if (!Subtarget.hasMips32() || Subtarget.inMips16Mode()) setOperationAction(ISD::CTLZ, MVT::i32, Expand); + if (!Subtarget.hasMips64()) setOperationAction(ISD::CTLZ, MVT::i64, Expand); - } - if (!Subtarget->hasSwap()) { + if (!Subtarget.hasMips32r2()) setOperationAction(ISD::BSWAP, MVT::i32, Expand); + if (!Subtarget.hasMips64r2()) setOperationAction(ISD::BSWAP, MVT::i64, Expand); - } - if (HasMips64) { + if (Subtarget.isGP64bit()) { setLoadExtAction(ISD::SEXTLOAD, MVT::i32, Custom); setLoadExtAction(ISD::ZEXTLOAD, MVT::i32, Custom); setLoadExtAction(ISD::EXTLOAD, MVT::i32, Custom); @@ -384,21 +390,34 @@ MipsTargetLowering(MipsTargetMachine &TM) setTargetDAGCombine(ISD::OR); setTargetDAGCombine(ISD::ADD); - setMinFunctionAlignment(HasMips64 ? 3 : 2); + setMinFunctionAlignment(Subtarget.isGP64bit() ? 3 : 2); - setStackPointerRegisterToSaveRestore(IsN64 ? Mips::SP_64 : Mips::SP); + setStackPointerRegisterToSaveRestore(Subtarget.isABI_N64() ? Mips::SP_64 + : Mips::SP); - setExceptionPointerRegister(IsN64 ? Mips::A0_64 : Mips::A0); - setExceptionSelectorRegister(IsN64 ? Mips::A1_64 : Mips::A1); + setExceptionPointerRegister(Subtarget.isABI_N64() ? Mips::A0_64 : Mips::A0); + setExceptionSelectorRegister(Subtarget.isABI_N64() ? Mips::A1_64 : Mips::A1); MaxStoresPerMemcpy = 16; + + isMicroMips = Subtarget.inMicroMipsMode(); } -const MipsTargetLowering *MipsTargetLowering::create(MipsTargetMachine &TM) { - if (TM.getSubtargetImpl()->inMips16Mode()) - return llvm::createMips16TargetLowering(TM); +const MipsTargetLowering *MipsTargetLowering::create(MipsTargetMachine &TM, + const MipsSubtarget &STI) { + if (STI.inMips16Mode()) + return llvm::createMips16TargetLowering(TM, STI); - return llvm::createMipsSETargetLowering(TM); + return llvm::createMipsSETargetLowering(TM, STI); +} + +// Create a fast isel object. +FastISel * +MipsTargetLowering::createFastISel(FunctionLoweringInfo &funcInfo, + const TargetLibraryInfo *libInfo) const { + if (!EnableMipsFastISel) + return TargetLowering::createFastISel(funcInfo, libInfo); + return Mips::createFastISel(funcInfo, libInfo); } EVT MipsTargetLowering::getSetCCResultType(LLVMContext &, EVT VT) const { @@ -409,7 +428,7 @@ EVT MipsTargetLowering::getSetCCResultType(LLVMContext &, EVT VT) const { static SDValue performDivRemCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, - const MipsSubtarget *Subtarget) { + const MipsSubtarget &Subtarget) { if (DCI.isBeforeLegalizeOps()) return SDValue(); @@ -519,7 +538,7 @@ static SDValue createCMovFP(SelectionDAG &DAG, SDValue Cond, SDValue True, static SDValue performSELECTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, - const MipsSubtarget *Subtarget) { + const MipsSubtarget &Subtarget) { if (DCI.isBeforeLegalizeOps()) return SDValue(); @@ -535,28 +554,74 @@ static SDValue performSELECTCombine(SDNode *N, SelectionDAG &DAG, if (!FalseTy.isInteger()) return SDValue(); - ConstantSDNode *CN = dyn_cast<ConstantSDNode>(False); + ConstantSDNode *FalseC = dyn_cast<ConstantSDNode>(False); - if (!CN || CN->getZExtValue()) + // If the RHS (False) is 0, we swap the order of the operands + // of ISD::SELECT (obviously also inverting the condition) so that we can + // take advantage of conditional moves using the $0 register. + // Example: + // return (a != 0) ? x : 0; + // load $reg, x + // movz $reg, $0, a + if (!FalseC) return SDValue(); const SDLoc DL(N); - ISD::CondCode CC = cast<CondCodeSDNode>(SetCC.getOperand(2))->get(); + + if (!FalseC->getZExtValue()) { + 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); + } + + // If both operands are integer constants there's a possibility that we + // can do some interesting optimizations. SDValue True = N->getOperand(1); + ConstantSDNode *TrueC = dyn_cast<ConstantSDNode>(True); + + if (!TrueC || !True.getValueType().isInteger()) + return SDValue(); + + // We'll also ignore MVT::i64 operands as this optimizations proves + // to be ineffective because of the required sign extensions as the result + // of a SETCC operator is always MVT::i32 for non-vector types. + if (True.getValueType() == MVT::i64) + return SDValue(); + + int64_t Diff = TrueC->getSExtValue() - FalseC->getSExtValue(); + + // 1) (a < x) ? y : y-1 + // slti $reg1, a, x + // addiu $reg2, $reg1, y-1 + if (Diff == 1) + return DAG.getNode(ISD::ADD, DL, SetCC.getValueType(), SetCC, False); - SetCC = DAG.getSetCC(DL, SetCC.getValueType(), SetCC.getOperand(0), - SetCC.getOperand(1), ISD::getSetCCInverse(CC, true)); + // 2) (a < x) ? y-1 : y + // slti $reg1, a, x + // xor $reg1, $reg1, 1 + // addiu $reg2, $reg1, y-1 + if (Diff == -1) { + ISD::CondCode CC = cast<CondCodeSDNode>(SetCC.getOperand(2))->get(); + SetCC = DAG.getSetCC(DL, SetCC.getValueType(), SetCC.getOperand(0), + SetCC.getOperand(1), ISD::getSetCCInverse(CC, true)); + return DAG.getNode(ISD::ADD, DL, SetCC.getValueType(), SetCC, True); + } - return DAG.getNode(ISD::SELECT, DL, FalseTy, SetCC, False, True); + // Couldn't optimize. + return SDValue(); } static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, - const MipsSubtarget *Subtarget) { + 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()) + if (DCI.isBeforeLegalizeOps() || !Subtarget.hasExtractInsert()) return SDValue(); SDValue ShiftRight = N->getOperand(0), Mask = N->getOperand(1); @@ -592,12 +657,12 @@ static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG, static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, - const MipsSubtarget *Subtarget) { + 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()) + if (DCI.isBeforeLegalizeOps() || !Subtarget.hasExtractInsert()) return SDValue(); SDValue And0 = N->getOperand(0), And1 = N->getOperand(1); @@ -646,7 +711,7 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, static SDValue performADDCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, - const MipsSubtarget *Subtarget) { + const MipsSubtarget &Subtarget) { // (add v0, (add v1, abs_lo(tjt))) => (add (add v0, v1), abs_lo(tjt)) if (DCI.isBeforeLegalizeOps()) @@ -728,7 +793,6 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const 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); @@ -759,10 +823,10 @@ addLiveIn(MachineFunction &MF, unsigned PReg, const TargetRegisterClass *RC) return VReg; } -static MachineBasicBlock *expandPseudoDIV(MachineInstr *MI, - MachineBasicBlock &MBB, - const TargetInstrInfo &TII, - bool Is64Bit) { +static MachineBasicBlock *insertDivByZeroTrap(MachineInstr *MI, + MachineBasicBlock &MBB, + const TargetInstrInfo &TII, + bool Is64Bit) { if (NoZeroDivCheck) return &MBB; @@ -770,7 +834,7 @@ static MachineBasicBlock *expandPseudoDIV(MachineInstr *MI, MachineBasicBlock::iterator I(MI); MachineInstrBuilder MIB; MachineOperand &Divisor = MI->getOperand(2); - MIB = BuildMI(MBB, llvm::next(I), MI->getDebugLoc(), TII.get(Mips::TEQ)) + MIB = BuildMI(MBB, std::next(I), MI->getDebugLoc(), TII.get(Mips::TEQ)) .addReg(Divisor.getReg(), getKillRegState(Divisor.isKill())) .addReg(Mips::ZERO).addImm(7); @@ -780,6 +844,10 @@ static MachineBasicBlock *expandPseudoDIV(MachineInstr *MI, // Clear Divisor's kill flag. Divisor.setIsKill(false); + + // We would normally delete the original instruction here but in this case + // we only needed to inject an additional instruction rather than replace it. + return &MBB; } @@ -862,10 +930,22 @@ MipsTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, return emitAtomicCmpSwap(MI, BB, 8); case Mips::PseudoSDIV: case Mips::PseudoUDIV: - return expandPseudoDIV(MI, *BB, *getTargetMachine().getInstrInfo(), false); + case Mips::DIV: + case Mips::DIVU: + case Mips::MOD: + case Mips::MODU: + return insertDivByZeroTrap(MI, *BB, *getTargetMachine().getInstrInfo(), + false); case Mips::PseudoDSDIV: case Mips::PseudoDUDIV: - return expandPseudoDIV(MI, *BB, *getTargetMachine().getInstrInfo(), true); + case Mips::DDIV: + case Mips::DDIVU: + case Mips::DMOD: + case Mips::DMODU: + return insertDivByZeroTrap(MI, *BB, *getTargetMachine().getInstrInfo(), + true); + case Mips::SEL_D: + return emitSEL_D(MI, BB); } } @@ -885,16 +965,20 @@ MipsTargetLowering::emitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB, unsigned LL, SC, AND, NOR, ZERO, BEQ; if (Size == 4) { - LL = Mips::LL; - SC = Mips::SC; + if (isMicroMips) { + LL = Mips::LL_MM; + SC = Mips::SC_MM; + } else { + LL = Subtarget.hasMips32r6() ? Mips::LL_R6 : Mips::LL; + SC = Subtarget.hasMips32r6() ? Mips::SC_R6 : Mips::SC; + } AND = Mips::AND; NOR = Mips::NOR; ZERO = Mips::ZERO; BEQ = Mips::BEQ; - } - else { - LL = Mips::LLD; - SC = Mips::SCD; + } else { + LL = Subtarget.hasMips64r6() ? Mips::LLD_R6 : Mips::LLD; + SC = Subtarget.hasMips64r6() ? Mips::SCD_R6 : Mips::SCD; AND = Mips::AND64; NOR = Mips::NOR64; ZERO = Mips::ZERO_64; @@ -920,7 +1004,7 @@ MipsTargetLowering::emitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB, // Transfer the remainder of BB and its successor edges to exitMBB. exitMBB->splice(exitMBB->begin(), BB, - llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); + std::next(MachineBasicBlock::iterator(MI)), BB->end()); exitMBB->transferSuccessorsAndUpdatePHIs(BB); // thisMBB: @@ -956,11 +1040,39 @@ MipsTargetLowering::emitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB, return exitMBB; } -MachineBasicBlock * -MipsTargetLowering::emitAtomicBinaryPartword(MachineInstr *MI, - MachineBasicBlock *BB, - unsigned Size, unsigned BinOpcode, - bool Nand) const { +MachineBasicBlock *MipsTargetLowering::emitSignExtendToI32InReg( + MachineInstr *MI, MachineBasicBlock *BB, unsigned Size, unsigned DstReg, + unsigned SrcReg) const { + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + DebugLoc DL = MI->getDebugLoc(); + + if (Subtarget.hasMips32r2() && Size == 1) { + BuildMI(BB, DL, TII->get(Mips::SEB), DstReg).addReg(SrcReg); + return BB; + } + + if (Subtarget.hasMips32r2() && Size == 2) { + BuildMI(BB, DL, TII->get(Mips::SEH), DstReg).addReg(SrcReg); + return BB; + } + + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + unsigned ScrReg = RegInfo.createVirtualRegister(RC); + + assert(Size < 32); + int64_t ShiftImm = 32 - (Size * 8); + + BuildMI(BB, DL, TII->get(Mips::SLL), ScrReg).addReg(SrcReg).addImm(ShiftImm); + BuildMI(BB, DL, TII->get(Mips::SRA), DstReg).addReg(ScrReg).addImm(ShiftImm); + + return BB; +} + +MachineBasicBlock *MipsTargetLowering::emitAtomicBinaryPartword( + MachineInstr *MI, MachineBasicBlock *BB, unsigned Size, unsigned BinOpcode, + bool Nand) const { assert((Size == 1 || Size == 2) && "Unsupported size for EmitAtomicBinaryPartial."); @@ -990,7 +1102,6 @@ MipsTargetLowering::emitAtomicBinaryPartword(MachineInstr *MI, 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 @@ -1006,7 +1117,7 @@ MipsTargetLowering::emitAtomicBinaryPartword(MachineInstr *MI, // Transfer the remainder of BB and its successor edges to exitMBB. exitMBB->splice(exitMBB->begin(), BB, - llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); + std::next(MachineBasicBlock::iterator(MI)), BB->end()); exitMBB->transferSuccessorsAndUpdatePHIs(BB); BB->addSuccessor(loopMBB); @@ -1030,7 +1141,7 @@ MipsTargetLowering::emitAtomicBinaryPartword(MachineInstr *MI, 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()) { + if (Subtarget.isLittle()) { BuildMI(BB, DL, TII->get(Mips::SLL), ShiftAmt).addReg(PtrLSB2).addImm(3); } else { unsigned Off = RegInfo.createVirtualRegister(RC); @@ -1096,19 +1207,14 @@ MipsTargetLowering::emitAtomicBinaryPartword(MachineInstr *MI, // sinkMBB: // and maskedoldval1,oldval,mask // srl srlres,maskedoldval1,shiftamt - // sll sllres,srlres,24 - // sra dest,sllres,24 + // sign_extend dest,srlres 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); + BB = emitSignExtendToI32InReg(MI, BB, Size, Dest, SrlRes); MI->eraseFromParent(); // The instruction is gone now. @@ -1128,8 +1234,8 @@ MachineBasicBlock * MipsTargetLowering::emitAtomicCmpSwap(MachineInstr *MI, unsigned LL, SC, ZERO, BNE, BEQ; if (Size == 4) { - LL = Mips::LL; - SC = Mips::SC; + LL = isMicroMips ? Mips::LL_MM : Mips::LL; + SC = isMicroMips ? Mips::SC_MM : Mips::SC; ZERO = Mips::ZERO; BNE = Mips::BNE; BEQ = Mips::BEQ; @@ -1161,7 +1267,7 @@ MachineBasicBlock * MipsTargetLowering::emitAtomicCmpSwap(MachineInstr *MI, // Transfer the remainder of BB and its successor edges to exitMBB. exitMBB->splice(exitMBB->begin(), BB, - llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); + std::next(MachineBasicBlock::iterator(MI)), BB->end()); exitMBB->transferSuccessorsAndUpdatePHIs(BB); // thisMBB: @@ -1229,7 +1335,6 @@ MipsTargetLowering::emitAtomicCmpSwapPartword(MachineInstr *MI, 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 @@ -1247,7 +1352,7 @@ MipsTargetLowering::emitAtomicCmpSwapPartword(MachineInstr *MI, // Transfer the remainder of BB and its successor edges to exitMBB. exitMBB->splice(exitMBB->begin(), BB, - llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); + std::next(MachineBasicBlock::iterator(MI)), BB->end()); exitMBB->transferSuccessorsAndUpdatePHIs(BB); BB->addSuccessor(loop1MBB); @@ -1276,7 +1381,7 @@ MipsTargetLowering::emitAtomicCmpSwapPartword(MachineInstr *MI, 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()) { + if (Subtarget.isLittle()) { BuildMI(BB, DL, TII->get(Mips::SLL), ShiftAmt).addReg(PtrLSB2).addImm(3); } else { unsigned Off = RegInfo.createVirtualRegister(RC); @@ -1326,23 +1431,44 @@ MipsTargetLowering::emitAtomicCmpSwapPartword(MachineInstr *MI, // sinkMBB: // srl srlres,maskedoldval0,shiftamt - // sll sllres,srlres,24 - // sra dest,sllres,24 + // sign_extend dest,srlres 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); + BB = emitSignExtendToI32InReg(MI, BB, Size, Dest, SrlRes); MI->eraseFromParent(); // The instruction is gone now. return exitMBB; } +MachineBasicBlock *MipsTargetLowering::emitSEL_D(MachineInstr *MI, + MachineBasicBlock *BB) const { + MachineFunction *MF = BB->getParent(); + const TargetRegisterInfo *TRI = getTargetMachine().getRegisterInfo(); + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + DebugLoc DL = MI->getDebugLoc(); + MachineBasicBlock::iterator II(MI); + + unsigned Fc = MI->getOperand(1).getReg(); + const auto &FGR64RegClass = TRI->getRegClass(Mips::FGR64RegClassID); + + unsigned Fc2 = RegInfo.createVirtualRegister(FGR64RegClass); + + BuildMI(*BB, II, DL, TII->get(Mips::SUBREG_TO_REG), Fc2) + .addImm(0) + .addReg(Fc) + .addImm(Mips::sub_lo); + + // We don't erase the original instruction, we just replace the condition + // register with the 64-bit super-register. + MI->getOperand(1).setReg(Fc2); + + return BB; +} + //===----------------------------------------------------------------------===// // Misc Lower Operation implementation //===----------------------------------------------------------------------===// @@ -1365,7 +1491,8 @@ SDValue MipsTargetLowering::lowerBR_JT(SDValue Op, SelectionDAG &DAG) const { 0); Chain = Addr.getValue(1); - if ((getTargetMachine().getRelocationModel() == Reloc::PIC_) || IsN64) { + if ((getTargetMachine().getRelocationModel() == Reloc::PIC_) || + Subtarget.isABI_N64()) { // For PIC, the sequence is: // BRIND(load(Jumptable + index) + RelocBase) // RelocBase can be JumpTable, GOT or some sort of global base. @@ -1383,6 +1510,7 @@ SDValue MipsTargetLowering::lowerBRCOND(SDValue Op, SelectionDAG &DAG) const { SDValue Dest = Op.getOperand(2); SDLoc DL(Op); + assert(!Subtarget.hasMips32r6() && !Subtarget.hasMips64r6()); SDValue CondRes = createFPCmp(DAG, Op.getOperand(1)); // Return if flag is not set by a floating point comparison. @@ -1402,6 +1530,7 @@ SDValue MipsTargetLowering::lowerBRCOND(SDValue Op, SelectionDAG &DAG) const { SDValue MipsTargetLowering:: lowerSELECT(SDValue Op, SelectionDAG &DAG) const { + assert(!Subtarget.hasMips32r6() && !Subtarget.hasMips64r6()); SDValue Cond = createFPCmp(DAG, Op.getOperand(0)); // Return if flag is not set by a floating point comparison. @@ -1427,6 +1556,7 @@ lowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const } SDValue MipsTargetLowering::lowerSETCC(SDValue Op, SelectionDAG &DAG) const { + assert(!Subtarget.hasMips32r6() && !Subtarget.hasMips64r6()); SDValue Cond = createFPCmp(DAG, Op); assert(Cond.getOpcode() == MipsISD::FPCmp && @@ -1446,7 +1576,8 @@ SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op, GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op); const GlobalValue *GV = N->getGlobal(); - if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !IsN64) { + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && + !Subtarget.isABI_N64()) { const MipsTargetObjectFile &TLOF = (const MipsTargetObjectFile&)getObjFileLowering(); @@ -1455,7 +1586,7 @@ SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op, 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); + DAG.getVTList(MVT::i32), GA); SDValue GPReg = DAG.getRegister(Mips::GP, MVT::i32); return DAG.getNode(ISD::ADD, DL, MVT::i32, GPReg, GPRelNode); } @@ -1465,7 +1596,8 @@ SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op, } if (GV->hasInternalLinkage() || (GV->hasLocalLinkage() && !isa<Function>(GV))) - return getAddrLocal(N, Ty, DAG, HasMips64); + return getAddrLocal(N, Ty, DAG, + Subtarget.isABI_N32() || Subtarget.isABI_N64()); if (LargeGOT) return getAddrGlobalLargeGOT(N, Ty, DAG, MipsII::MO_GOT_HI16, @@ -1473,7 +1605,9 @@ SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op, MachinePointerInfo::getGOT()); return getAddrGlobal(N, Ty, DAG, - HasMips64 ? MipsII::MO_GOT_DISP : MipsII::MO_GOT16, + (Subtarget.isABI_N32() || Subtarget.isABI_N64()) + ? MipsII::MO_GOT_DISP + : MipsII::MO_GOT16, DAG.getEntryNode(), MachinePointerInfo::getGOT()); } @@ -1482,10 +1616,12 @@ SDValue MipsTargetLowering::lowerBlockAddress(SDValue Op, BlockAddressSDNode *N = cast<BlockAddressSDNode>(Op); EVT Ty = Op.getValueType(); - if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !IsN64) + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && + !Subtarget.isABI_N64()) return getAddrNonPIC(N, Ty, DAG); - return getAddrLocal(N, Ty, DAG, HasMips64); + return getAddrLocal(N, Ty, DAG, + Subtarget.isABI_N32() || Subtarget.isABI_N64()); } SDValue MipsTargetLowering:: @@ -1521,11 +1657,9 @@ lowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const 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); + TargetLowering::CallLoweringInfo CLI(DAG); + CLI.setDebugLoc(DL).setChain(DAG.getEntryNode()) + .setCallee(CallingConv::C, PtrTy, TlsGetAddr, std::move(Args), 0); std::pair<SDValue, SDValue> CallResult = LowerCallTo(CLI); SDValue Ret = CallResult.first; @@ -1575,10 +1709,12 @@ lowerJumpTable(SDValue Op, SelectionDAG &DAG) const JumpTableSDNode *N = cast<JumpTableSDNode>(Op); EVT Ty = Op.getValueType(); - if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !IsN64) + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && + !Subtarget.isABI_N64()) return getAddrNonPIC(N, Ty, DAG); - return getAddrLocal(N, Ty, DAG, HasMips64); + return getAddrLocal(N, Ty, DAG, + Subtarget.isABI_N32() || Subtarget.isABI_N64()); } SDValue MipsTargetLowering:: @@ -1596,10 +1732,12 @@ lowerConstantPool(SDValue Op, SelectionDAG &DAG) const ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); EVT Ty = Op.getValueType(); - if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !IsN64) + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && + !Subtarget.isABI_N64()) return getAddrNonPIC(N, Ty, DAG); - return getAddrLocal(N, Ty, DAG, HasMips64); + return getAddrLocal(N, Ty, DAG, + Subtarget.isABI_N32() || Subtarget.isABI_N64()); } SDValue MipsTargetLowering::lowerVASTART(SDValue Op, SelectionDAG &DAG) const { @@ -1714,69 +1852,10 @@ static SDValue lowerFCOPYSIGN64(SDValue Op, SelectionDAG &DAG, SDValue MipsTargetLowering::lowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const { - if (Subtarget->hasMips64()) - return lowerFCOPYSIGN64(Op, DAG, Subtarget->hasExtractInsert()); + if (Subtarget.isGP64bit()) + 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()); + return lowerFCOPYSIGN32(Op, DAG, Subtarget.hasExtractInsert()); } SDValue MipsTargetLowering:: @@ -1789,13 +1868,17 @@ lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { MFI->setFrameAddressIsTaken(true); EVT VT = Op.getValueType(); SDLoc DL(Op); - SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, - IsN64 ? Mips::FP_64 : Mips::FP, VT); + SDValue FrameAddr = + DAG.getCopyFromReg(DAG.getEntryNode(), DL, + Subtarget.isABI_N64() ? Mips::FP_64 : Mips::FP, VT); return FrameAddr; } SDValue MipsTargetLowering::lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const { + if (verifyReturnAddressArgumentIsConstant(Op, DAG)) + return SDValue(); + // check the depth assert((cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() == 0) && "Return address can be determined only for current frame."); @@ -1803,7 +1886,7 @@ SDValue MipsTargetLowering::lowerRETURNADDR(SDValue Op, MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo *MFI = MF.getFrameInfo(); MVT VT = Op.getSimpleValueType(); - unsigned RA = IsN64 ? Mips::RA_64 : Mips::RA; + unsigned RA = Subtarget.isABI_N64() ? Mips::RA_64 : Mips::RA; MFI->setReturnAddressIsTaken(true); // Return RA, which contains the return address. Mark it an implicit live-in. @@ -1825,12 +1908,12 @@ SDValue MipsTargetLowering::lowerEH_RETURN(SDValue Op, SelectionDAG &DAG) SDValue Offset = Op.getOperand(1); SDValue Handler = Op.getOperand(2); SDLoc DL(Op); - EVT Ty = IsN64 ? MVT::i64 : MVT::i32; + EVT Ty = Subtarget.isABI_N64() ? 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; + unsigned OffsetReg = Subtarget.isABI_N64() ? Mips::V1_64 : Mips::V1; + unsigned AddrReg = Subtarget.isABI_N64() ? 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, @@ -1877,7 +1960,7 @@ SDValue MipsTargetLowering::lowerShiftLeftParts(SDValue Op, Hi = DAG.getNode(ISD::SELECT, DL, MVT::i32, Cond, ShiftLeftLo, Or); SDValue Ops[2] = {Lo, Hi}; - return DAG.getMergeValues(Ops, 2, DL); + return DAG.getMergeValues(Ops, DL); } SDValue MipsTargetLowering::lowerShiftRightParts(SDValue Op, SelectionDAG &DAG, @@ -1918,7 +2001,7 @@ SDValue MipsTargetLowering::lowerShiftRightParts(SDValue Op, SelectionDAG &DAG, ShiftRightHi); SDValue Ops[2] = {Lo, Hi}; - return DAG.getMergeValues(Ops, 2, DL); + return DAG.getMergeValues(Ops, DL); } static SDValue createLoadLR(unsigned Opc, SelectionDAG &DAG, LoadSDNode *LD, @@ -1934,7 +2017,7 @@ static SDValue createLoadLR(unsigned Opc, SelectionDAG &DAG, LoadSDNode *LD, DAG.getConstant(Offset, BasePtrVT)); SDValue Ops[] = { Chain, Ptr, Src }; - return DAG.getMemIntrinsicNode(Opc, DL, VTList, Ops, 3, MemVT, + return DAG.getMemIntrinsicNode(Opc, DL, VTList, Ops, MemVT, LD->getMemOperand()); } @@ -1943,12 +2026,15 @@ SDValue MipsTargetLowering::lowerLOAD(SDValue Op, SelectionDAG &DAG) const { LoadSDNode *LD = cast<LoadSDNode>(Op); EVT MemVT = LD->getMemoryVT(); + if (Subtarget.systemSupportsUnalignedAccess()) + return Op; + // 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(); + bool IsLittle = Subtarget.isLittle(); EVT VT = Op.getValueType(); ISD::LoadExtType ExtType = LD->getExtensionType(); SDValue Chain = LD->getChain(), Undef = DAG.getUNDEF(VT); @@ -1997,7 +2083,7 @@ SDValue MipsTargetLowering::lowerLOAD(SDValue Op, SelectionDAG &DAG) const { 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); + return DAG.getMergeValues(Ops, DL); } static SDValue createStoreLR(unsigned Opc, SelectionDAG &DAG, StoreSDNode *SD, @@ -2012,7 +2098,7 @@ static SDValue createStoreLR(unsigned Opc, SelectionDAG &DAG, StoreSDNode *SD, DAG.getConstant(Offset, BasePtrVT)); SDValue Ops[] = { Chain, Value, Ptr }; - return DAG.getMemIntrinsicNode(Opc, DL, VTList, Ops, 3, MemVT, + return DAG.getMemIntrinsicNode(Opc, DL, VTList, Ops, MemVT, SD->getMemOperand()); } @@ -2066,9 +2152,10 @@ SDValue MipsTargetLowering::lowerSTORE(SDValue Op, SelectionDAG &DAG) const { EVT MemVT = SD->getMemoryVT(); // Lower unaligned integer stores. - if ((SD->getAlignment() < MemVT.getSizeInBits() / 8) && + if (!Subtarget.systemSupportsUnalignedAccess() && + (SD->getAlignment() < MemVT.getSizeInBits() / 8) && ((MemVT == MVT::i32) || (MemVT == MVT::i64))) - return lowerUnalignedIntStore(SD, DAG, Subtarget->isLittle()); + return lowerUnalignedIntStore(SD, DAG, Subtarget.isLittle()); return lowerFP_TO_SINT_STORE(SD, DAG); } @@ -2123,12 +2210,12 @@ SDValue MipsTargetLowering::lowerFP_TO_SINT(SDValue Op, static bool CC_MipsO32(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, - CCState &State, const uint16_t *F64Regs) { + CCState &State, const MCPhysReg *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 }; + static const MCPhysReg IntRegs[] = { Mips::A0, Mips::A1, Mips::A2, Mips::A3 }; + static const MCPhysReg F32Regs[] = { Mips::F12, Mips::F14 }; // Do not process byval args here. if (ArgFlags.isByVal()) @@ -2200,7 +2287,7 @@ static bool CC_MipsO32(unsigned ValNo, MVT ValVT, MVT LocVT, 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 }; + static const MCPhysReg F64Regs[] = { Mips::D6, Mips::D7 }; return CC_MipsO32(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State, F64Regs); } @@ -2208,7 +2295,7 @@ static bool CC_MipsO32_FP32(unsigned ValNo, MVT ValVT, 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 }; + static const MCPhysReg F64Regs[] = { Mips::D12_64, Mips::D14_64 }; return CC_MipsO32(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State, F64Regs); } @@ -2254,8 +2341,8 @@ getOpndList(SmallVectorImpl<SDValue> &Ops, // 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; + unsigned GPReg = Subtarget.isABI_N64() ? Mips::GP_64 : Mips::GP; + EVT Ty = Subtarget.isABI_N64() ? MVT::i64 : MVT::i32; RegsToPass.push_back(std::make_pair(GPReg, getGlobalReg(CLI.DAG, Ty))); } @@ -2281,11 +2368,11 @@ getOpndList(SmallVectorImpl<SDValue> &Ops, 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 (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")) { + if (F && F->hasFnAttribute("__Mips16RetHelper")) { Mask = MipsRegisterInfo::getMips16RetHelperMask(); } } @@ -2324,12 +2411,12 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, getTargetMachine(), ArgLocs, *DAG.getContext()); MipsCC::SpecialCallingConvType SpecialCallingConv = getSpecialCallingConv(Callee); - MipsCC MipsCCInfo(CallConv, IsO32, Subtarget->isFP64bit(), CCInfo, - SpecialCallingConv); + MipsCC MipsCCInfo(CallConv, Subtarget.isABI_O32(), Subtarget.isFP64bit(), + CCInfo, SpecialCallingConv); MipsCCInfo.analyzeCallOperands(Outs, IsVarArg, - Subtarget->mipsSEUsesSoftFloat(), - Callee.getNode(), CLI.Args); + Subtarget.abiUsesSoftFloat(), + Callee.getNode(), CLI.getArgs()); // Get a count of how many bytes are to be pushed on the stack. unsigned NextStackOffset = CCInfo.getNextStackOffset(); @@ -2340,6 +2427,10 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, isEligibleForTailCallOptimization(MipsCCInfo, NextStackOffset, *MF.getInfo<MipsFunctionInfo>()); + if (!IsTailCall && CLI.CS && CLI.CS->isMustTailCall()) + report_fatal_error("failed to perform tail call elimination on a call " + "site marked musttail"); + if (IsTailCall) ++NumTailCalls; @@ -2353,9 +2444,9 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, if (!IsTailCall) Chain = DAG.getCALLSEQ_START(Chain, NextStackOffsetVal, DL); - SDValue StackPtr = DAG.getCopyFromReg(Chain, DL, - IsN64 ? Mips::SP_64 : Mips::SP, - getPointerTy()); + SDValue StackPtr = DAG.getCopyFromReg( + Chain, DL, Subtarget.isABI_N64() ? Mips::SP_64 : Mips::SP, + getPointerTy()); // With EABI is it possible to have 16 args on registers. std::deque< std::pair<unsigned, SDValue> > RegsToPass; @@ -2377,7 +2468,7 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, 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()); + MipsCCInfo, *ByValArg, Flags, Subtarget.isLittle()); ++ByValArg; continue; } @@ -2396,7 +2487,7 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, Arg, DAG.getConstant(0, MVT::i32)); SDValue Hi = DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, Arg, DAG.getConstant(1, MVT::i32)); - if (!Subtarget->isLittle()) + if (!Subtarget.isLittle()) std::swap(Lo, Hi); unsigned LocRegLo = VA.getLocReg(); unsigned LocRegHigh = getNextIntArgReg(LocRegLo); @@ -2436,13 +2527,14 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, // 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()); + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains); // 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 IsPICCall = + (Subtarget.isABI_N64() || IsPIC); // true if calls are translated to + // jalr $25 bool GlobalOrExternal = false, InternalLinkage = false; SDValue CalleeLo; EVT Ty = Callee.getValueType(); @@ -2453,7 +2545,8 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, InternalLinkage = Val->hasInternalLinkage(); if (InternalLinkage) - Callee = getAddrLocal(G, Ty, DAG, HasMips64); + Callee = getAddrLocal(G, Ty, DAG, + Subtarget.isABI_N32() || Subtarget.isABI_N64()); else if (LargeGOT) Callee = getAddrGlobalLargeGOT(G, Ty, DAG, MipsII::MO_CALL_HI16, MipsII::MO_CALL_LO16, Chain, @@ -2469,7 +2562,7 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) { const char *Sym = S->getSymbol(); - if (!IsN64 && !IsPIC) // !N64 && static + if (!Subtarget.isABI_N64() && !IsPIC) // !N64 && static Callee = DAG.getTargetExternalSymbol(Sym, getPointerTy(), MipsII::MO_NO_FLAG); else if (LargeGOT) @@ -2490,9 +2583,9 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, CLI, Callee, Chain); if (IsTailCall) - return DAG.getNode(MipsISD::TailCall, DL, MVT::Other, &Ops[0], Ops.size()); + return DAG.getNode(MipsISD::TailCall, DL, MVT::Other, Ops); - Chain = DAG.getNode(MipsISD::JmpLink, DL, NodeTys, &Ops[0], Ops.size()); + Chain = DAG.getNode(MipsISD::JmpLink, DL, NodeTys, Ops); SDValue InFlag = Chain.getValue(1); // Create the CALLSEQ_END node. @@ -2520,9 +2613,10 @@ MipsTargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag, SmallVector<CCValAssign, 16> RVLocs; CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), getTargetMachine(), RVLocs, *DAG.getContext()); - MipsCC MipsCCInfo(CallConv, IsO32, Subtarget->isFP64bit(), CCInfo); + MipsCC MipsCCInfo(CallConv, Subtarget.isABI_O32(), Subtarget.isFP64bit(), + CCInfo); - MipsCCInfo.analyzeCallResult(Ins, Subtarget->mipsSEUsesSoftFloat(), + MipsCCInfo.analyzeCallResult(Ins, Subtarget.abiUsesSoftFloat(), CallNode, RetTy); // Copy all of the result registers out of their specified physreg. @@ -2567,10 +2661,11 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, SmallVector<CCValAssign, 16> ArgLocs; CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), getTargetMachine(), ArgLocs, *DAG.getContext()); - MipsCC MipsCCInfo(CallConv, IsO32, Subtarget->isFP64bit(), CCInfo); + MipsCC MipsCCInfo(CallConv, Subtarget.isABI_O32(), Subtarget.isFP64bit(), + CCInfo); Function::const_arg_iterator FuncArg = DAG.getMachineFunction().getFunction()->arg_begin(); - bool UseSoftFloat = Subtarget->mipsSEUsesSoftFloat(); + bool UseSoftFloat = Subtarget.abiUsesSoftFloat(); MipsCCInfo.analyzeFormalArguments(Ins, UseSoftFloat, FuncArg); MipsFI->setFormalArgInfo(CCInfo.getNextStackOffset(), @@ -2629,11 +2724,12 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, (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) { + else if (Subtarget.isABI_O32() && 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()) + if (!Subtarget.isLittle()) std::swap(ArgValue, ArgValue2); ArgValue = DAG.getNode(MipsISD::BuildPairF64, DL, MVT::f64, ArgValue, ArgValue2); @@ -2659,18 +2755,21 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, } } - // 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); + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + // 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 (Ins[i].Flags.isSRet()) { + unsigned Reg = MipsFI->getSRetReturnReg(); + if (!Reg) { + Reg = MF.getRegInfo().createVirtualRegister( + getRegClassFor(Subtarget.isABI_N64() ? MVT::i64 : MVT::i32)); + MipsFI->setSRetReturnReg(Reg); + } + SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), DL, Reg, InVals[i]); + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Copy, Chain); + break; } - SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), DL, Reg, InVals[0]); - Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Copy, Chain); } if (IsVarArg) @@ -2680,8 +2779,7 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, // 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()); + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains); } return Chain; @@ -2716,10 +2814,11 @@ MipsTargetLowering::LowerReturn(SDValue Chain, // CCState - Info about the registers and stack slot. CCState CCInfo(CallConv, IsVarArg, MF, getTargetMachine(), RVLocs, *DAG.getContext()); - MipsCC MipsCCInfo(CallConv, IsO32, Subtarget->isFP64bit(), CCInfo); + MipsCC MipsCCInfo(CallConv, Subtarget.isABI_O32(), Subtarget.isFP64bit(), + CCInfo); // Analyze return values. - MipsCCInfo.analyzeReturn(Outs, Subtarget->mipsSEUsesSoftFloat(), + MipsCCInfo.analyzeReturn(Outs, Subtarget.abiUsesSoftFloat(), MF.getFunction()->getReturnType()); SDValue Flag; @@ -2752,7 +2851,7 @@ MipsTargetLowering::LowerReturn(SDValue Chain, 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; + unsigned V0 = Subtarget.isABI_N64() ? Mips::V0_64 : Mips::V0; Chain = DAG.getCopyToReg(Chain, DL, V0, Val, Flag); Flag = Chain.getValue(1); @@ -2766,7 +2865,7 @@ MipsTargetLowering::LowerReturn(SDValue Chain, RetOps.push_back(Flag); // Return on Mips is always a "jr $ra" - return DAG.getNode(MipsISD::Ret, DL, MVT::Other, &RetOps[0], RetOps.size()); + return DAG.getNode(MipsISD::Ret, DL, MVT::Other, RetOps); } //===----------------------------------------------------------------------===// @@ -2816,7 +2915,7 @@ MipsTargetLowering::getSingleConstraintMatchWeight( 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) + if (!CallOperandVal) return CW_Default; Type *type = CallOperandVal->getType(); // Look at the constraint type. @@ -2830,7 +2929,7 @@ MipsTargetLowering::getSingleConstraintMatchWeight( weight = CW_Register; break; case 'f': // FPU or MSA register - if (Subtarget->hasMSA() && type->isVectorTy() && + if (Subtarget.hasMSA() && type->isVectorTy() && cast<VectorType>(type)->getBitWidth() == 128) weight = CW_Register; else if (type->isFloatTy()) @@ -2894,12 +2993,12 @@ parseRegForInlineAsmConstraint(const StringRef &C, MVT VT) const { std::pair<bool, bool> R = parsePhysicalReg(C, Prefix, Reg); if (!R.first) - return std::make_pair((unsigned)0, (const TargetRegisterClass*)0); + return std::make_pair(0U, nullptr); 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); + return std::make_pair(0U, nullptr); RC = TRI->getRegClass(Prefix == "hi" ? Mips::HI32RegClassID : Mips::LO32RegClassID); @@ -2909,7 +3008,7 @@ parseRegForInlineAsmConstraint(const StringRef &C, MVT VT) const { // No numeric characters follow the name. if (R.second) - return std::make_pair((unsigned)0, (const TargetRegisterClass *)0); + return std::make_pair(0U, nullptr); Reg = StringSwitch<unsigned long long>(Prefix) .Case("$msair", Mips::MSAIR) @@ -2923,20 +3022,20 @@ parseRegForInlineAsmConstraint(const StringRef &C, MVT VT) const { .Default(0); if (!Reg) - return std::make_pair((unsigned)0, (const TargetRegisterClass *)0); + return std::make_pair(0U, nullptr); RC = TRI->getRegClass(Mips::MSACtrlRegClassID); return std::make_pair(Reg, RC); } if (!R.second) - return std::make_pair((unsigned)0, (const TargetRegisterClass*)0); + return std::make_pair(0U, nullptr); 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; + VT = (Subtarget.isFP64bit() || !(Reg % 2)) ? MVT::f64 : MVT::f32; RC = getRegClassFor(VT); @@ -2969,16 +3068,16 @@ getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const case 'y': // Same as 'r'. Exists for compatibility. case 'r': if (VT == MVT::i32 || VT == MVT::i16 || VT == MVT::i8) { - if (Subtarget->inMips16Mode()) + if (Subtarget.inMips16Mode()) return std::make_pair(0U, &Mips::CPU16RegsRegClass); return std::make_pair(0U, &Mips::GPR32RegClass); } - if (VT == MVT::i64 && !HasMips64) + if (VT == MVT::i64 && !Subtarget.isGP64bit()) return std::make_pair(0U, &Mips::GPR32RegClass); - if (VT == MVT::i64 && HasMips64) + if (VT == MVT::i64 && Subtarget.isGP64bit()) return std::make_pair(0U, &Mips::GPR64RegClass); // This will generate an error message - return std::make_pair(0u, static_cast<const TargetRegisterClass*>(0)); + return std::make_pair(0U, nullptr); case 'f': // FPU or MSA register if (VT == MVT::v16i8) return std::make_pair(0U, &Mips::MSA128BRegClass); @@ -2990,8 +3089,8 @@ getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const 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()) + else if ((VT == MVT::f64) && (!Subtarget.isSingleFloat())) { + if (Subtarget.isFP64bit()) return std::make_pair(0U, &Mips::FGR64RegClass); return std::make_pair(0U, &Mips::AFGR64RegClass); } @@ -3008,7 +3107,7 @@ getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const 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)); + return std::make_pair(0U, nullptr); } } @@ -3027,7 +3126,7 @@ void MipsTargetLowering::LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint, std::vector<SDValue>&Ops, SelectionDAG &DAG) const { - SDValue Result(0, 0); + SDValue Result; // Only support length 1 constraints for now. if (Constraint.length() > 1) return; @@ -3147,7 +3246,7 @@ EVT MipsTargetLowering::getOptimalMemOpType(uint64_t Size, unsigned DstAlign, bool IsMemset, bool ZeroMemset, bool MemcpyStrSrc, MachineFunction &MF) const { - if (Subtarget->hasMips64()) + if (Subtarget.hasMips64()) return MVT::i64; return MVT::i32; @@ -3162,7 +3261,7 @@ bool MipsTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const { } unsigned MipsTargetLowering::getJumpTableEncoding() const { - if (IsN64) + if (Subtarget.isABI_N64()) return MachineJumpTableInfo::EK_GPRel64BlockAddress; return TargetLowering::getJumpTableEncoding(); @@ -3211,12 +3310,12 @@ static bool originalTypeIsF128(const Type *Ty, const SDNode *CallNode) { MipsTargetLowering::MipsCC::SpecialCallingConvType MipsTargetLowering::getSpecialCallingConv(SDValue Callee) const { MipsCC::SpecialCallingConvType SpecialCallingConv = - MipsCC::NoSpecialCallingConv;; - if (Subtarget->inMips16HardFloat()) { + 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")) { + if (F && F->hasFnAttribute("__Mips16RetHelper")) { SpecialCallingConv = MipsCC::Mips16RetHelperConv; } } @@ -3267,7 +3366,7 @@ analyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Args, dbgs() << "Call operand #" << I << " has unhandled type " << EVT(ArgVT).getEVTString(); #endif - llvm_unreachable(0); + llvm_unreachable(nullptr); } } } @@ -3290,7 +3389,7 @@ analyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Args, continue; } - MVT RegVT = getRegVT(ArgVT, FuncArg->getType(), 0, IsSoftFloat); + MVT RegVT = getRegVT(ArgVT, FuncArg->getType(), nullptr, IsSoftFloat); if (!FixedFn(I, ArgVT, RegVT, CCValAssign::Full, ArgFlags, CCInfo)) continue; @@ -3299,7 +3398,7 @@ analyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Args, dbgs() << "Formal Arg #" << I << " has unhandled type " << EVT(ArgVT).getEVTString(); #endif - llvm_unreachable(0); + llvm_unreachable(nullptr); } } @@ -3324,7 +3423,7 @@ analyzeReturn(const SmallVectorImpl<Ty> &RetVals, bool IsSoftFloat, dbgs() << "Call result #" << I << " has unhandled type " << EVT(VT).getEVTString() << '\n'; #endif - llvm_unreachable(0); + llvm_unreachable(nullptr); } } } @@ -3338,7 +3437,7 @@ analyzeCallResult(const SmallVectorImpl<ISD::InputArg> &Ins, bool IsSoftFloat, void MipsTargetLowering::MipsCC:: analyzeReturn(const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsSoftFloat, const Type *RetTy) const { - analyzeReturn(Outs, IsSoftFloat, 0, RetTy); + analyzeReturn(Outs, IsSoftFloat, nullptr, RetTy); } void MipsTargetLowering::MipsCC::handleByValArg(unsigned ValNo, MVT ValVT, @@ -3372,7 +3471,7 @@ unsigned MipsTargetLowering::MipsCC::reservedArgArea() const { return (IsO32 && (CallConv != CallingConv::Fast)) ? 16 : 0; } -const uint16_t *MipsTargetLowering::MipsCC::intArgRegs() const { +const MCPhysReg *MipsTargetLowering::MipsCC::intArgRegs() const { return IsO32 ? O32IntRegs : Mips64IntRegs; } @@ -3389,7 +3488,7 @@ 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 { +const MCPhysReg *MipsTargetLowering::MipsCC::shadowRegs() const { return IsO32 ? O32IntRegs : Mips64DPRegs; } @@ -3397,7 +3496,7 @@ void MipsTargetLowering::MipsCC::allocateRegs(ByValArgInfo &ByVal, unsigned ByValSize, unsigned Align) { unsigned RegSize = regSize(), NumIntArgRegs = numIntArgRegs(); - const uint16_t *IntArgRegs = intArgRegs(), *ShadowRegs = shadowRegs(); + const MCPhysReg *IntArgRegs = intArgRegs(), *ShadowRegs = shadowRegs(); assert(!(ByValSize % RegSize) && !(Align % RegSize) && "Byval argument's size and alignment should be a multiple of" "RegSize."); @@ -3482,21 +3581,22 @@ passByValArg(SDValue Chain, SDLoc DL, 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); + unsigned ByValSizeInBytes = Flags.getByValSize(); + unsigned OffsetInBytes = 0; // From beginning of struct + unsigned RegSizeInBytes = CC.regSize(); + unsigned Alignment = std::min(Flags.getByValAlign(), RegSizeInBytes); + EVT PtrTy = getPointerTy(), RegTy = MVT::getIntegerVT(RegSizeInBytes * 8); if (ByVal.NumRegs) { - const uint16_t *ArgRegs = CC.intArgRegs(); - bool LeftoverBytes = (ByVal.NumRegs * RegSize > ByValSize); + const MCPhysReg *ArgRegs = CC.intArgRegs(); + bool LeftoverBytes = (ByVal.NumRegs * RegSizeInBytes > ByValSizeInBytes); unsigned I = 0; // Copy words to registers. - for (; I < ByVal.NumRegs - LeftoverBytes; ++I, Offset += RegSize) { + for (; I < ByVal.NumRegs - LeftoverBytes; + ++I, OffsetInBytes += RegSizeInBytes) { SDValue LoadPtr = DAG.getNode(ISD::ADD, DL, PtrTy, Arg, - DAG.getConstant(Offset, PtrTy)); + DAG.getConstant(OffsetInBytes, PtrTy)); SDValue LoadVal = DAG.getLoad(RegTy, DL, Chain, LoadPtr, MachinePointerInfo(), false, false, false, Alignment); @@ -3506,38 +3606,38 @@ passByValArg(SDValue Chain, SDLoc DL, } // Return if the struct has been fully copied. - if (ByValSize == Offset) + if (ByValSizeInBytes == OffsetInBytes) 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."); + assert((ByValSizeInBytes > OffsetInBytes) && + (ByValSizeInBytes < OffsetInBytes + RegSizeInBytes) && + "Size of the remainder should be smaller than RegSizeInBytes."); SDValue Val; - for (unsigned LoadSize = RegSize / 2, TotalSizeLoaded = 0; - Offset < ByValSize; LoadSize /= 2) { - unsigned RemSize = ByValSize - Offset; + for (unsigned LoadSizeInBytes = RegSizeInBytes / 2, TotalBytesLoaded = 0; + OffsetInBytes < ByValSizeInBytes; LoadSizeInBytes /= 2) { + unsigned RemainingSizeInBytes = ByValSizeInBytes - OffsetInBytes; - if (RemSize < LoadSize) + if (RemainingSizeInBytes < LoadSizeInBytes) 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); + DAG.getConstant(OffsetInBytes, PtrTy)); + SDValue LoadVal = DAG.getExtLoad( + ISD::ZEXTLOAD, DL, RegTy, Chain, LoadPtr, MachinePointerInfo(), + MVT::getIntegerVT(LoadSizeInBytes * 8), false, false, Alignment); MemOpChains.push_back(LoadVal.getValue(1)); // Shift the loaded value. unsigned Shamt; if (isLittle) - Shamt = TotalSizeLoaded; + Shamt = TotalBytesLoaded * 8; else - Shamt = (RegSize - (TotalSizeLoaded + LoadSize)) * 8; + Shamt = (RegSizeInBytes - (TotalBytesLoaded + LoadSizeInBytes)) * 8; SDValue Shift = DAG.getNode(ISD::SHL, DL, RegTy, LoadVal, DAG.getConstant(Shamt, MVT::i32)); @@ -3547,9 +3647,9 @@ passByValArg(SDValue Chain, SDLoc DL, else Val = Shift; - Offset += LoadSize; - TotalSizeLoaded += LoadSize; - Alignment = std::min(Alignment, LoadSize); + OffsetInBytes += LoadSizeInBytes; + TotalBytesLoaded += LoadSizeInBytes; + Alignment = std::min(Alignment, LoadSizeInBytes); } unsigned ArgReg = ArgRegs[ByVal.FirstIdx + I]; @@ -3559,14 +3659,14 @@ passByValArg(SDValue Chain, SDLoc DL, } // Copy remainder of byval arg to it with memcpy. - unsigned MemCpySize = ByValSize - Offset; + unsigned MemCpySize = ByValSizeInBytes - OffsetInBytes; SDValue Src = DAG.getNode(ISD::ADD, DL, PtrTy, Arg, - DAG.getConstant(Offset, PtrTy)); + DAG.getConstant(OffsetInBytes, 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)); + MachinePointerInfo(), MachinePointerInfo()); MemOpChains.push_back(Chain); } @@ -3574,7 +3674,7 @@ 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 MCPhysReg *ArgRegs = CC.intArgRegs(); const CCState &CCInfo = CC.getCCInfo(); unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs, NumRegs); unsigned RegSize = CC.regSize(); @@ -3608,7 +3708,8 @@ void MipsTargetLowering::writeVarArgRegs(std::vector<SDValue> &OutChains, 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); + cast<StoreSDNode>(Store.getNode())->getMemOperand()->setValue( + (Value *)nullptr); OutChains.push_back(Store); } } diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h index 65f68f04315d..10e4e0b48644 100644 --- a/lib/Target/Mips/MipsISelLowering.h +++ b/lib/Target/Mips/MipsISelLowering.h @@ -15,9 +15,8 @@ #ifndef MipsISELLOWERING_H #define MipsISELLOWERING_H -#include "Mips.h" -#include "MipsSubtarget.h" #include "MCTargetDesc/MipsBaseInfo.h" +#include "Mips.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/IR/Function.h" @@ -184,6 +183,9 @@ namespace llvm { PCKEV, // Pack even elements PCKOD, // Pack odd elements + // Vector Lane Copy + INSVE, // Copy element from one vector to another + // Combined (XOR (OR $a, $b), -1) VNOR, @@ -207,39 +209,49 @@ namespace llvm { // TargetLowering Implementation //===--------------------------------------------------------------------===// class MipsFunctionInfo; + class MipsSubtarget; class MipsTargetLowering : public TargetLowering { + bool isMicroMips; public: - explicit MipsTargetLowering(MipsTargetMachine &TM); + explicit MipsTargetLowering(MipsTargetMachine &TM, + const MipsSubtarget &STI); - static const MipsTargetLowering *create(MipsTargetMachine &TM); + static const MipsTargetLowering *create(MipsTargetMachine &TM, + const MipsSubtarget &STI); - virtual MVT getScalarShiftAmountTy(EVT LHSTy) const { return MVT::i32; } + /// createFastISel - This method returns a target specific FastISel object, + /// or null if the target does not support "fast" ISel. + FastISel *createFastISel(FunctionLoweringInfo &funcInfo, + const TargetLibraryInfo *libInfo) const override; - virtual void LowerOperationWrapper(SDNode *N, - SmallVectorImpl<SDValue> &Results, - SelectionDAG &DAG) const; + MVT getScalarShiftAmountTy(EVT LHSTy) const override { return MVT::i32; } + + void LowerOperationWrapper(SDNode *N, + SmallVectorImpl<SDValue> &Results, + SelectionDAG &DAG) const override; /// LowerOperation - Provide custom lowering hooks for some operations. - virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; /// 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; + void ReplaceNodeResults(SDNode *N, SmallVectorImpl<SDValue>&Results, + SelectionDAG &DAG) const override; /// getTargetNodeName - This method returns the name of a target specific // DAG node. - virtual const char *getTargetNodeName(unsigned Opcode) const; + const char *getTargetNodeName(unsigned Opcode) const override; /// getSetCCResultType - get the ISD::SETCC result ValueType - EVT getSetCCResultType(LLVMContext &Context, EVT VT) const; + EVT getSetCCResultType(LLVMContext &Context, EVT VT) const override; - virtual SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const; + SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override; - virtual MachineBasicBlock * - EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const; + MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *MBB) const override; struct LTStr { bool operator()(const char *S1, const char *S2) const { @@ -254,17 +266,17 @@ namespace llvm { // computing a local symbol's address: // // (add (load (wrapper $gp, %got(sym)), %lo(sym)) - template<class NodeTy> + template <class NodeTy> SDValue getAddrLocal(NodeTy *N, EVT Ty, SelectionDAG &DAG, - bool HasMips64) const { + bool IsN32OrN64) const { SDLoc DL(N); - unsigned GOTFlag = HasMips64 ? MipsII::MO_GOT_PAGE : MipsII::MO_GOT; + unsigned GOTFlag = IsN32OrN64 ? 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; + unsigned LoFlag = IsN32OrN64 ? 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); @@ -378,7 +390,7 @@ namespace llvm { unsigned reservedArgArea() const; /// Return pointer to array of integer argument registers. - const uint16_t *intArgRegs() const; + const MCPhysReg *intArgRegs() const; typedef SmallVectorImpl<ByValArgInfo>::const_iterator byval_iterator; byval_iterator byval_begin() const { return ByValArgs.begin(); } @@ -399,7 +411,7 @@ namespace llvm { /// Return the function that analyzes variable argument list functions. llvm::CCAssignFn *varArgFn() const; - const uint16_t *shadowRegs() const; + const MCPhysReg *shadowRegs() const; void allocateRegs(ByValArgInfo &ByVal, unsigned ByValSize, unsigned Align); @@ -426,9 +438,7 @@ namespace llvm { SDValue lowerSTORE(SDValue Op, SelectionDAG &DAG) const; // Subtarget Info - const MipsSubtarget *Subtarget; - - bool HasMips64, IsN64, IsO32; + const MipsSubtarget &Subtarget; private: // Create a TargetGlobalAddress node. @@ -515,41 +525,39 @@ namespace llvm { void writeVarArgRegs(std::vector<SDValue> &OutChains, const MipsCC &CC, SDValue Chain, SDLoc DL, SelectionDAG &DAG) const; - virtual SDValue + SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc dl, SelectionDAG &DAG, - SmallVectorImpl<SDValue> &InVals) const; + SmallVectorImpl<SDValue> &InVals) const override; 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; + SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl<SDValue> &InVals) const override; - virtual bool - CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, - bool isVarArg, - const SmallVectorImpl<ISD::OutputArg> &Outs, - LLVMContext &Context) const; + bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, + bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + LLVMContext &Context) const override; - virtual SDValue - LowerReturn(SDValue Chain, - CallingConv::ID CallConv, bool isVarArg, - const SmallVectorImpl<ISD::OutputArg> &Outs, - const SmallVectorImpl<SDValue> &OutVals, - SDLoc dl, SelectionDAG &DAG) const; + SDValue LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + SDLoc dl, SelectionDAG &DAG) const override; // Inline asm support - ConstraintType getConstraintType(const std::string &Constraint) const; + ConstraintType + getConstraintType(const std::string &Constraint) const override; /// 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; + AsmOperandInfo &info, const char *constraint) const override; /// This function parses registers that appear in inline-asm constraints. /// It returns pair (0, 0) on failure. @@ -558,33 +566,39 @@ namespace llvm { std::pair<unsigned, const TargetRegisterClass*> getRegForInlineAsmConstraint(const std::string &Constraint, - MVT VT) const; + MVT VT) const override; /// 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; + void LowerAsmOperandForConstraint(SDValue Op, + std::string &Constraint, + std::vector<SDValue> &Ops, + SelectionDAG &DAG) const override; - virtual bool isLegalAddressingMode(const AddrMode &AM, Type *Ty) const; + bool isLegalAddressingMode(const AddrMode &AM, Type *Ty) const override; - virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const; + bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override; - virtual EVT getOptimalMemOpType(uint64_t Size, unsigned DstAlign, - unsigned SrcAlign, - bool IsMemset, bool ZeroMemset, - bool MemcpyStrSrc, - MachineFunction &MF) const; + EVT getOptimalMemOpType(uint64_t Size, unsigned DstAlign, + unsigned SrcAlign, + bool IsMemset, bool ZeroMemset, + bool MemcpyStrSrc, + MachineFunction &MF) const override; /// 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; + bool isFPImmLegal(const APFloat &Imm, EVT VT) const override; + + unsigned getJumpTableEncoding() const override; - virtual unsigned getJumpTableEncoding() const; + /// Emit a sign-extension using sll/sra, seb, or seh appropriately. + MachineBasicBlock *emitSignExtendToI32InReg(MachineInstr *MI, + MachineBasicBlock *BB, + unsigned Size, unsigned DstReg, + unsigned SrcRec) const; MachineBasicBlock *emitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB, unsigned Size, unsigned BinOpcode, bool Nand = false) const; @@ -595,11 +609,19 @@ namespace llvm { MachineBasicBlock *BB, unsigned Size) const; MachineBasicBlock *emitAtomicCmpSwapPartword(MachineInstr *MI, MachineBasicBlock *BB, unsigned Size) const; + MachineBasicBlock *emitSEL_D(MachineInstr *MI, MachineBasicBlock *BB) const; }; /// Create MipsTargetLowering objects. - const MipsTargetLowering *createMips16TargetLowering(MipsTargetMachine &TM); - const MipsTargetLowering *createMipsSETargetLowering(MipsTargetMachine &TM); + const MipsTargetLowering * + createMips16TargetLowering(MipsTargetMachine &TM, const MipsSubtarget &STI); + const MipsTargetLowering * + createMipsSETargetLowering(MipsTargetMachine &TM, const MipsSubtarget &STI); + + namespace Mips { + FastISel *createFastISel(FunctionLoweringInfo &funcInfo, + const TargetLibraryInfo *libInfo); + } } #endif // MipsISELLOWERING_H diff --git a/lib/Target/Mips/MipsInstrFPU.td b/lib/Target/Mips/MipsInstrFPU.td index 9f7ce9aa72b0..29d8e30be483 100644 --- a/lib/Target/Mips/MipsInstrFPU.td +++ b/lib/Target/Mips/MipsInstrFPU.td @@ -57,15 +57,25 @@ let PrintMethod = "printFCCOperand", DecoderMethod = "DecodeCondCode" in // Feature predicates. //===----------------------------------------------------------------------===// -def IsFP64bit : Predicate<"Subtarget.isFP64bit()">, +def IsFP64bit : Predicate<"Subtarget->isFP64bit()">, AssemblerPredicate<"FeatureFP64Bit">; -def NotFP64bit : Predicate<"!Subtarget.isFP64bit()">, +def NotFP64bit : Predicate<"!Subtarget->isFP64bit()">, AssemblerPredicate<"!FeatureFP64Bit">; -def IsSingleFloat : Predicate<"Subtarget.isSingleFloat()">, +def IsSingleFloat : Predicate<"Subtarget->isSingleFloat()">, AssemblerPredicate<"FeatureSingleFloat">; -def IsNotSingleFloat : Predicate<"!Subtarget.isSingleFloat()">, +def IsNotSingleFloat : Predicate<"!Subtarget->isSingleFloat()">, AssemblerPredicate<"!FeatureSingleFloat">; +//===----------------------------------------------------------------------===// +// Mips FGR size adjectives. +// They are mutually exclusive. +//===----------------------------------------------------------------------===// + +class FGR_32 { list<Predicate> FGRPredicates = [NotFP64bit]; } +class FGR_64 { list<Predicate> FGRPredicates = [IsFP64bit]; } + +//===----------------------------------------------------------------------===// + // FP immediate patterns. def fpimm0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(+0.0); @@ -93,16 +103,17 @@ 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> { + [(set RC:$fd, (OpNode RC:$fs, RC:$ft))], Itin, FrmFR, opstr> { 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]> { + def _D32 : MMRel, ADDS_FT<opstr, AFGR64Opnd, Itin, IsComm, OpNode>, + AdditionalRequires<[NotFP64bit]>; + def _D64 : ADDS_FT<opstr, FGR64Opnd, Itin, + IsComm, OpNode>, + AdditionalRequires<[IsFP64bit]> { string DecoderNamespace = "Mips64"; } } @@ -110,24 +121,24 @@ multiclass ADDS_M<string opstr, InstrItinClass Itin, bit IsComm, 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>, + [(set DstRC:$fd, (OpNode SrcRC:$fs))], Itin, FrmFR, opstr>, 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 _D32 : MMRel, ABSS_FT<opstr, AFGR64Opnd, AFGR64Opnd, Itin, OpNode>, + AdditionalRequires<[NotFP64bit]>; def _D64 : ABSS_FT<opstr, FGR64Opnd, FGR64Opnd, Itin, OpNode>, - Requires<[IsFP64bit, HasStdEnc]> { + AdditionalRequires<[IsFP64bit]> { string DecoderNamespace = "Mips64"; } } multiclass ROUND_M<string opstr, InstrItinClass Itin> { - def _D32 : ABSS_FT<opstr, FGR32Opnd, AFGR64Opnd, Itin>, - Requires<[NotFP64bit, HasStdEnc]>; + def _D32 : MMRel, ABSS_FT<opstr, FGR32Opnd, AFGR64Opnd, Itin>, + AdditionalRequires<[NotFP64bit]>; def _D64 : ABSS_FT<opstr, FGR32Opnd, FGR64Opnd, Itin>, - Requires<[IsFP64bit, HasStdEnc]> { + AdditionalRequires<[IsFP64bit]> { let DecoderNamespace = "Mips64"; } } @@ -135,17 +146,26 @@ multiclass ROUND_M<string opstr, InstrItinClass Itin> { 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>; + [(set DstRC:$rt, (OpNode SrcRC:$fs))], Itin, FrmFR, opstr>; 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>; + [(set DstRC:$fs, (OpNode SrcRC:$rt))], Itin, FrmFR, opstr>; + +class MTC1_64_FT<string opstr, RegisterOperand DstRC, RegisterOperand SrcRC, + InstrItinClass Itin> : + InstSE<(outs DstRC:$fs), (ins DstRC:$fs_in, SrcRC:$rt), + !strconcat(opstr, "\t$rt, $fs"), [], Itin, FrmFR, opstr> { + // $fs_in is part of a white lie to work around a widespread bug in the FPU + // implementation. See expandBuildPairF64 for details. + let Constraints = "$fs = $fs_in"; +} 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> { + [(set RC:$rt, (OpNode addrDefault:$addr))], Itin, FrmFI, opstr> { let DecoderMethod = "DecodeFMem"; let mayLoad = 1; } @@ -153,7 +173,7 @@ class LW_FT<string opstr, RegisterOperand RC, InstrItinClass Itin, 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> { + [(OpNode RC:$rt, addrDefault:$addr)], Itin, FrmFI, opstr> { let DecoderMethod = "DecodeFMem"; let mayStore = 1; } @@ -162,20 +182,22 @@ 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>; + [(set RC:$fd, (OpNode (fmul RC:$fs, RC:$ft), RC:$fr))], Itin, + FrmFR, opstr>; 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>; + Itin, FrmFR, opstr>; 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> { + [(set DRC:$fd, (OpNode (add iPTR:$base, iPTR:$index)))], Itin, + FrmFI, opstr> { let AddedComplexity = 20; } @@ -183,15 +205,17 @@ 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> { + [(OpNode DRC:$fs, (add iPTR:$base, iPTR:$index))], Itin, + FrmFI, opstr> { let AddedComplexity = 20; } -class BC1F_FT<string opstr, InstrItinClass Itin, +class BC1F_FT<string opstr, DAGOperand opnd, InstrItinClass Itin, SDPatternOperator Op = null_frag> : - InstSE<(outs), (ins FCCRegsOpnd:$fcc, brtarget:$offset), + InstSE<(outs), (ins FCCRegsOpnd:$fcc, opnd:$offset), !strconcat(opstr, "\t$fcc, $offset"), - [(MipsFPBrcond Op, FCCRegsOpnd:$fcc, bb:$offset)], Itin, FrmFI> { + [(MipsFPBrcond Op, FCCRegsOpnd:$fcc, bb:$offset)], Itin, + FrmFI, opstr> { let isBranch = 1; let isTerminator = 1; let hasDelaySlot = 1; @@ -202,129 +226,129 @@ 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> { + [(OpNode RC:$fs, RC:$ft, imm:$cond)], Itin, FrmFR, + !strconcat("c.$cond.", typestr)> { let Defs = [FCC0]; let isCodeGenOnly = 1; } -class C_COND_FT<string CondStr, string Typestr, RegisterOperand RC> : +class C_COND_FT<string CondStr, string Typestr, RegisterOperand RC, + InstrItinClass itin> : InstSE<(outs), (ins RC:$fs, RC:$ft), - !strconcat("c.", CondStr, ".", Typestr, "\t$fs, $ft"), [], IIFcmp, + !strconcat("c.", CondStr, ".", Typestr, "\t$fs, $ft"), [], itin, 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>; +multiclass C_COND_M<string TypeStr, RegisterOperand RC, bits<5> fmt, + InstrItinClass itin> { + def C_F_#NAME : C_COND_FT<"f", TypeStr, RC, itin>, C_COND_FM<fmt, 0>; + def C_UN_#NAME : C_COND_FT<"un", TypeStr, RC, itin>, C_COND_FM<fmt, 1>; + def C_EQ_#NAME : C_COND_FT<"eq", TypeStr, RC, itin>, C_COND_FM<fmt, 2>; + def C_UEQ_#NAME : C_COND_FT<"ueq", TypeStr, RC, itin>, C_COND_FM<fmt, 3>; + def C_OLT_#NAME : C_COND_FT<"olt", TypeStr, RC, itin>, C_COND_FM<fmt, 4>; + def C_ULT_#NAME : C_COND_FT<"ult", TypeStr, RC, itin>, C_COND_FM<fmt, 5>; + def C_OLE_#NAME : C_COND_FT<"ole", TypeStr, RC, itin>, C_COND_FM<fmt, 6>; + def C_ULE_#NAME : C_COND_FT<"ule", TypeStr, RC, itin>, C_COND_FM<fmt, 7>; + def C_SF_#NAME : C_COND_FT<"sf", TypeStr, RC, itin>, C_COND_FM<fmt, 8>; + def C_NGLE_#NAME : C_COND_FT<"ngle", TypeStr, RC, itin>, C_COND_FM<fmt, 9>; + def C_SEQ_#NAME : C_COND_FT<"seq", TypeStr, RC, itin>, C_COND_FM<fmt, 10>; + def C_NGL_#NAME : C_COND_FT<"ngl", TypeStr, RC, itin>, C_COND_FM<fmt, 11>; + def C_LT_#NAME : C_COND_FT<"lt", TypeStr, RC, itin>, C_COND_FM<fmt, 12>; + def C_NGE_#NAME : C_COND_FT<"nge", TypeStr, RC, itin>, C_COND_FM<fmt, 13>; + def C_LE_#NAME : C_COND_FT<"le", TypeStr, RC, itin>, C_COND_FM<fmt, 14>; + def C_NGT_#NAME : C_COND_FT<"ngt", TypeStr, RC, itin>, C_COND_FM<fmt, 15>; } -defm S : C_COND_M<"s", FGR32Opnd, 16>; -defm D32 : C_COND_M<"d", AFGR64Opnd, 17>, - Requires<[NotFP64bit, HasStdEnc]>; +defm S : C_COND_M<"s", FGR32Opnd, 16, II_C_CC_S>, ISA_MIPS1_NOT_32R6_64R6; +defm D32 : C_COND_M<"d", AFGR64Opnd, 17, II_C_CC_D>, ISA_MIPS1_NOT_32R6_64R6, + AdditionalRequires<[NotFP64bit]>; let DecoderNamespace = "Mips64" in -defm D64 : C_COND_M<"d", FGR64Opnd, 17>, Requires<[IsFP64bit, HasStdEnc]>; +defm D64 : C_COND_M<"d", FGR64Opnd, 17, II_C_CC_D>, ISA_MIPS1_NOT_32R6_64R6, + AdditionalRequires<[IsFP64bit]>; //===----------------------------------------------------------------------===// // 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>, +def ROUND_W_S : MMRel, ABSS_FT<"round.w.s", FGR32Opnd, FGR32Opnd, II_ROUND>, + ABSS_FM<0xc, 16>, ISA_MIPS2; +def TRUNC_W_S : MMRel, ABSS_FT<"trunc.w.s", FGR32Opnd, FGR32Opnd, II_TRUNC>, + ABSS_FM<0xd, 16>, ISA_MIPS2; +def CEIL_W_S : MMRel, ABSS_FT<"ceil.w.s", FGR32Opnd, FGR32Opnd, II_CEIL>, + ABSS_FM<0xe, 16>, ISA_MIPS2; +def FLOOR_W_S : MMRel, ABSS_FT<"floor.w.s", FGR32Opnd, FGR32Opnd, II_FLOOR>, + ABSS_FM<0xf, 16>, ISA_MIPS2; +def CVT_W_S : MMRel, ABSS_FT<"cvt.w.s", FGR32Opnd, FGR32Opnd, II_CVT>, 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>; +defm ROUND_W : ROUND_M<"round.w.d", II_ROUND>, ABSS_FM<0xc, 17>, ISA_MIPS2; +defm TRUNC_W : ROUND_M<"trunc.w.d", II_TRUNC>, ABSS_FM<0xd, 17>, ISA_MIPS2; +defm CEIL_W : ROUND_M<"ceil.w.d", II_CEIL>, ABSS_FM<0xe, 17>, ISA_MIPS2; +defm FLOOR_W : ROUND_M<"floor.w.d", II_FLOOR>, ABSS_FM<0xf, 17>, ISA_MIPS2; +defm CVT_W : ROUND_M<"cvt.w.d", II_CVT>, 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>; +let DecoderNamespace = "Mips64" in { + def ROUND_L_S : ABSS_FT<"round.l.s", FGR64Opnd, FGR32Opnd, II_ROUND>, + ABSS_FM<0x8, 16>, FGR_64; + def ROUND_L_D64 : ABSS_FT<"round.l.d", FGR64Opnd, FGR64Opnd, II_ROUND>, + ABSS_FM<0x8, 17>, FGR_64; + def TRUNC_L_S : ABSS_FT<"trunc.l.s", FGR64Opnd, FGR32Opnd, II_TRUNC>, + ABSS_FM<0x9, 16>, FGR_64; + def TRUNC_L_D64 : ABSS_FT<"trunc.l.d", FGR64Opnd, FGR64Opnd, II_TRUNC>, + ABSS_FM<0x9, 17>, FGR_64; + def CEIL_L_S : ABSS_FT<"ceil.l.s", FGR64Opnd, FGR32Opnd, II_CEIL>, + ABSS_FM<0xa, 16>, FGR_64; + def CEIL_L_D64 : ABSS_FT<"ceil.l.d", FGR64Opnd, FGR64Opnd, II_CEIL>, + ABSS_FM<0xa, 17>, FGR_64; + def FLOOR_L_S : ABSS_FT<"floor.l.s", FGR64Opnd, FGR32Opnd, II_FLOOR>, + ABSS_FM<0xb, 16>, FGR_64; + def FLOOR_L_D64 : ABSS_FT<"floor.l.d", FGR64Opnd, FGR64Opnd, II_FLOOR>, + ABSS_FM<0xb, 17>, FGR_64; } -def CVT_S_W : ABSS_FT<"cvt.s.w", FGR32Opnd, FGR32Opnd, IIFcvt>, +def CVT_S_W : MMRel, ABSS_FT<"cvt.s.w", FGR32Opnd, FGR32Opnd, II_CVT>, 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>; +def CVT_L_S : MMRel, ABSS_FT<"cvt.l.s", FGR64Opnd, FGR32Opnd, II_CVT>, + ABSS_FM<0x25, 16>, INSN_MIPS3_32R2; +def CVT_L_D64: MMRel, ABSS_FT<"cvt.l.d", FGR64Opnd, FGR64Opnd, II_CVT>, + ABSS_FM<0x25, 17>, INSN_MIPS3_32R2; -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>; -} +def CVT_S_D32 : MMRel, ABSS_FT<"cvt.s.d", FGR32Opnd, AFGR64Opnd, II_CVT>, + ABSS_FM<0x20, 17>, FGR_32; +def CVT_D32_W : MMRel, ABSS_FT<"cvt.d.w", AFGR64Opnd, FGR32Opnd, II_CVT>, + ABSS_FM<0x21, 20>, FGR_32; +def CVT_D32_S : MMRel, ABSS_FT<"cvt.d.s", AFGR64Opnd, FGR32Opnd, II_CVT>, + ABSS_FM<0x21, 16>, FGR_32; -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 DecoderNamespace = "Mips64" in { + def CVT_S_D64 : ABSS_FT<"cvt.s.d", FGR32Opnd, FGR64Opnd, II_CVT>, + ABSS_FM<0x20, 17>, FGR_64; + def CVT_S_L : ABSS_FT<"cvt.s.l", FGR32Opnd, FGR64Opnd, II_CVT>, + ABSS_FM<0x20, 21>, FGR_64; + def CVT_D64_W : ABSS_FT<"cvt.d.w", FGR64Opnd, FGR32Opnd, II_CVT>, + ABSS_FM<0x21, 20>, FGR_64; + def CVT_D64_S : ABSS_FT<"cvt.d.s", FGR64Opnd, FGR32Opnd, II_CVT>, + ABSS_FM<0x21, 16>, FGR_64; + def CVT_D64_L : ABSS_FT<"cvt.d.l", FGR64Opnd, FGR64Opnd, II_CVT>, + ABSS_FM<0x21, 21>, FGR_64; } 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>; + def PseudoCVT_S_W : ABSS_FT<"", FGR32Opnd, GPR32Opnd, II_CVT>; + def PseudoCVT_D32_W : ABSS_FT<"", AFGR64Opnd, GPR32Opnd, II_CVT>; + def PseudoCVT_S_L : ABSS_FT<"", FGR64Opnd, GPR64Opnd, II_CVT>; + def PseudoCVT_D64_W : ABSS_FT<"", FGR64Opnd, GPR32Opnd, II_CVT>; + def PseudoCVT_D64_L : ABSS_FT<"", FGR64Opnd, GPR64Opnd, II_CVT>; } -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 FABS_S : MMRel, ABSS_FT<"abs.s", FGR32Opnd, FGR32Opnd, II_ABS, fabs>, + ABSS_FM<0x5, 16>; +def FNEG_S : MMRel, ABSS_FT<"neg.s", FGR32Opnd, FGR32Opnd, II_NEG, fneg>, + ABSS_FM<0x7, 16>; +defm FABS : ABSS_M<"abs.d", II_ABS, fabs>, ABSS_FM<0x5, 17>; +defm FNEG : ABSS_M<"neg.d", II_NEG, 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>; +def FSQRT_S : MMRel, ABSS_FT<"sqrt.s", FGR32Opnd, FGR32Opnd, II_SQRT_S, fsqrt>, + ABSS_FM<0x4, 16>, ISA_MIPS2; +defm FSQRT : ABSS_M<"sqrt.d", II_SQRT_D, fsqrt>, ABSS_FM<0x4, 17>, ISA_MIPS2; // The odd-numbered registers are only referenced when doing loads, // stores, and moves between floating-point and integer registers. @@ -332,137 +356,168 @@ defm FSQRT : ABSS_M<"sqrt.d", IIFsqrtDouble, fsqrt>, ABSS_FM<0x4, 17>; // 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 CFC1 : MMRel, MFC1_FT<"cfc1", GPR32Opnd, CCROpnd, II_CFC1>, MFC1_FM<2>; +def CTC1 : MMRel, MTC1_FT<"ctc1", CCROpnd, GPR32Opnd, II_CTC1>, MFC1_FM<6>; +def MFC1 : MMRel, MFC1_FT<"mfc1", GPR32Opnd, FGR32Opnd, II_MFC1, + bitconvert>, MFC1_FM<0>; +def MTC1 : MMRel, MTC1_FT<"mtc1", FGR32Opnd, GPR32Opnd, II_MTC1, + bitconvert>, MFC1_FM<4>; +def MFHC1_D32 : MMRel, MFC1_FT<"mfhc1", GPR32Opnd, AFGR64Opnd, II_MFHC1>, + MFC1_FM<3>, ISA_MIPS32R2, AdditionalRequires<[NotFP64bit]>; +def MFHC1_D64 : MFC1_FT<"mfhc1", GPR32Opnd, FGR64Opnd, II_MFHC1>, + MFC1_FM<3>, ISA_MIPS32R2, AdditionalRequires<[IsFP64bit]> { + let DecoderNamespace = "Mips64"; +} +def MTHC1_D32 : MMRel, MTC1_64_FT<"mthc1", AFGR64Opnd, GPR32Opnd, II_MTHC1>, + MFC1_FM<7>, ISA_MIPS32R2, AdditionalRequires<[NotFP64bit]>; +def MTHC1_D64 : MTC1_64_FT<"mthc1", FGR64Opnd, GPR32Opnd, II_MTHC1>, + MFC1_FM<7>, ISA_MIPS32R2, AdditionalRequires<[IsFP64bit]> { + let DecoderNamespace = "Mips64"; +} +def DMFC1 : MFC1_FT<"dmfc1", GPR64Opnd, FGR64Opnd, II_DMFC1, + bitconvert>, MFC1_FM<1>, ISA_MIPS3; +def DMTC1 : MTC1_FT<"dmtc1", FGR64Opnd, GPR64Opnd, II_DMTC1, + bitconvert>, MFC1_FM<5>, ISA_MIPS3; -def FMOV_S : ABSS_FT<"mov.s", FGR32Opnd, FGR32Opnd, IIFmove>, +def FMOV_S : MMRel, ABSS_FT<"mov.s", FGR32Opnd, FGR32Opnd, II_MOV_S>, 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]> { +def FMOV_D32 : MMRel, ABSS_FT<"mov.d", AFGR64Opnd, AFGR64Opnd, II_MOV_D>, + ABSS_FM<0x6, 17>, AdditionalRequires<[NotFP64bit]>; +def FMOV_D64 : ABSS_FT<"mov.d", FGR64Opnd, FGR64Opnd, II_MOV_D>, + ABSS_FM<0x6, 17>, AdditionalRequires<[IsFP64bit]> { 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>; -} +def LWC1 : MMRel, LW_FT<"lwc1", FGR32Opnd, II_LWC1, load>, LW_FM<0x31>; +def SWC1 : MMRel, SW_FT<"swc1", FGR32Opnd, II_SWC1, 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 DecoderNamespace = "Mips64" in { + def LDC164 : LW_FT<"ldc1", FGR64Opnd, II_LDC1, load>, LW_FM<0x35>, ISA_MIPS2, + FGR_64; + def SDC164 : SW_FT<"sdc1", FGR64Opnd, II_SDC1, store>, LW_FM<0x3d>, ISA_MIPS2, + FGR_64; } -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>; -} +def LDC1 : MMRel, LW_FT<"ldc1", AFGR64Opnd, II_LDC1, load>, LW_FM<0x35>, + ISA_MIPS2, FGR_32; +def SDC1 : MMRel, SW_FT<"sdc1", AFGR64Opnd, II_SDC1, store>, LW_FM<0x3d>, + ISA_MIPS2, FGR_32; + +// Cop2 Memory Instructions +// FIXME: These aren't really FPU instructions and as such don't belong in this +// file +def LWC2 : LW_FT<"lwc2", COP2Opnd, NoItinerary, load>, LW_FM<0x32>, + ISA_MIPS1_NOT_32R6_64R6; +def SWC2 : SW_FT<"swc2", COP2Opnd, NoItinerary, store>, LW_FM<0x3a>, + ISA_MIPS1_NOT_32R6_64R6; +def LDC2 : LW_FT<"ldc2", COP2Opnd, NoItinerary, load>, LW_FM<0x36>, + ISA_MIPS2_NOT_32R6_64R6; +def SDC2 : SW_FT<"sdc2", COP2Opnd, NoItinerary, store>, LW_FM<0x3e>, + ISA_MIPS2_NOT_32R6_64R6; -/// 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>; +// Cop3 Memory Instructions +// FIXME: These aren't really FPU instructions and as such don't belong in this +// file +let DecoderNamespace = "COP3_" in { + def LWC3 : LW_FT<"lwc3", COP3Opnd, NoItinerary, load>, LW_FM<0x33>; + def SWC3 : SW_FT<"swc3", COP3Opnd, NoItinerary, store>, LW_FM<0x3b>; + def LDC3 : LW_FT<"ldc3", COP3Opnd, NoItinerary, load>, LW_FM<0x37>, + ISA_MIPS2; + def SDC3 : SW_FT<"sdc3", COP3Opnd, NoItinerary, store>, LW_FM<0x3f>, + ISA_MIPS2; } // 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>; +// Base register + offset register addressing mode (indicated by "x" in the +// instruction mnemonic) is disallowed under NaCl. +let AdditionalPredicates = [IsNotNaCl] in { + def LWXC1 : MMRel, LWXC1_FT<"lwxc1", FGR32Opnd, II_LWXC1, load>, LWXC1_FM<0>, + INSN_MIPS4_32R2_NOT_32R6_64R6; + def SWXC1 : MMRel, SWXC1_FT<"swxc1", FGR32Opnd, II_SWXC1, store>, SWXC1_FM<8>, + INSN_MIPS4_32R2_NOT_32R6_64R6; } -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 AdditionalPredicates = [NotInMicroMips, IsNotNaCl] in { + def LDXC1 : LWXC1_FT<"ldxc1", AFGR64Opnd, II_LDXC1, load>, LWXC1_FM<1>, + INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_32; + def SDXC1 : SWXC1_FT<"sdxc1", AFGR64Opnd, II_SDXC1, store>, SWXC1_FM<9>, + INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_32; } -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>; +let DecoderNamespace="Mips64" in { + def LDXC164 : LWXC1_FT<"ldxc1", FGR64Opnd, II_LDXC1, load>, LWXC1_FM<1>, + INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_64; + def SDXC164 : SWXC1_FT<"sdxc1", FGR64Opnd, II_SDXC1, store>, SWXC1_FM<9>, + INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_64; } // 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 AdditionalPredicates = [IsNotNaCl] in { + def LUXC1 : MMRel, LWXC1_FT<"luxc1", AFGR64Opnd, II_LUXC1>, LWXC1_FM<0x5>, + INSN_MIPS5_32R2_NOT_32R6_64R6, FGR_32; + def SUXC1 : MMRel, SWXC1_FT<"suxc1", AFGR64Opnd, II_SUXC1>, SWXC1_FM<0xd>, + INSN_MIPS5_32R2_NOT_32R6_64R6, FGR_32; } -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>; +let DecoderNamespace="Mips64" in { + def LUXC164 : LWXC1_FT<"luxc1", FGR64Opnd, II_LUXC1>, LWXC1_FM<0x5>, + INSN_MIPS5_32R2_NOT_32R6_64R6, FGR_64; + def SUXC164 : SWXC1_FT<"suxc1", FGR64Opnd, II_SUXC1>, SWXC1_FM<0xd>, + INSN_MIPS5_32R2_NOT_32R6_64R6, FGR_64; } /// Floating-point Aritmetic -def FADD_S : ADDS_FT<"add.s", FGR32Opnd, IIFadd, 1, fadd>, +def FADD_S : MMRel, ADDS_FT<"add.s", FGR32Opnd, II_ADD_S, 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>, +defm FADD : ADDS_M<"add.d", II_ADD_D, 1, fadd>, ADDS_FM<0x00, 17>; +def FDIV_S : MMRel, ADDS_FT<"div.s", FGR32Opnd, II_DIV_S, 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>, +defm FDIV : ADDS_M<"div.d", II_DIV_D, 0, fdiv>, ADDS_FM<0x03, 17>; +def FMUL_S : MMRel, ADDS_FT<"mul.s", FGR32Opnd, II_MUL_S, 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>, +defm FMUL : ADDS_M<"mul.d", II_MUL_D, 1, fmul>, ADDS_FM<0x02, 17>; +def FSUB_S : MMRel, ADDS_FT<"sub.s", FGR32Opnd, II_SUB_S, 0, fsub>, ADDS_FM<0x01, 16>; -defm FSUB : ADDS_M<"sub.d", IIFadd, 0, fsub>, ADDS_FM<0x01, 17>; +defm FSUB : ADDS_M<"sub.d", II_SUB_D, 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>; -} +def MADD_S : MMRel, MADDS_FT<"madd.s", FGR32Opnd, II_MADD_S, fadd>, + MADDS_FM<4, 0>, ISA_MIPS32R2_NOT_32R6_64R6; +def MSUB_S : MMRel, MADDS_FT<"msub.s", FGR32Opnd, II_MSUB_S, fsub>, + MADDS_FM<5, 0>, ISA_MIPS32R2_NOT_32R6_64R6; -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 AdditionalPredicates = [NoNaNsFPMath] in { + def NMADD_S : MMRel, NMADDS_FT<"nmadd.s", FGR32Opnd, II_NMADD_S, fadd>, + MADDS_FM<6, 0>, ISA_MIPS32R2_NOT_32R6_64R6; + def NMSUB_S : MMRel, NMADDS_FT<"nmsub.s", FGR32Opnd, II_NMSUB_S, fsub>, + MADDS_FM<7, 0>, ISA_MIPS32R2_NOT_32R6_64R6; } -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>; -} +def MADD_D32 : MMRel, MADDS_FT<"madd.d", AFGR64Opnd, II_MADD_D, fadd>, + MADDS_FM<4, 1>, ISA_MIPS32R2_NOT_32R6_64R6, FGR_32; +def MSUB_D32 : MMRel, MADDS_FT<"msub.d", AFGR64Opnd, II_MSUB_D, fsub>, + MADDS_FM<5, 1>, ISA_MIPS32R2_NOT_32R6_64R6, FGR_32; -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 AdditionalPredicates = [NoNaNsFPMath] in { + def NMADD_D32 : MMRel, NMADDS_FT<"nmadd.d", AFGR64Opnd, II_NMADD_D, fadd>, + MADDS_FM<6, 1>, ISA_MIPS32R2_NOT_32R6_64R6, FGR_32; + def NMSUB_D32 : MMRel, NMADDS_FT<"nmsub.d", AFGR64Opnd, II_NMSUB_D, fsub>, + MADDS_FM<7, 1>, ISA_MIPS32R2_NOT_32R6_64R6, FGR_32; } -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 isCodeGenOnly=1 in { + def MADD_D64 : MADDS_FT<"madd.d", FGR64Opnd, II_MADD_D, fadd>, + MADDS_FM<4, 1>, ISA_MIPS32R2_NOT_32R6_64R6, FGR_64; + def MSUB_D64 : MADDS_FT<"msub.d", FGR64Opnd, II_MSUB_D, fsub>, + MADDS_FM<5, 1>, ISA_MIPS32R2_NOT_32R6_64R6, FGR_64; } -let Predicates = [HasMips32r2, IsFP64bit, NoNaNsFPMath, HasStdEnc], +let AdditionalPredicates = [NoNaNsFPMath], 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>; + def NMADD_D64 : NMADDS_FT<"nmadd.d", FGR64Opnd, II_NMADD_D, fadd>, + MADDS_FM<6, 1>, ISA_MIPS32R2_NOT_32R6_64R6, FGR_64; + def NMSUB_D64 : NMADDS_FT<"nmsub.d", FGR64Opnd, II_NMSUB_D, fsub>, + MADDS_FM<7, 1>, ISA_MIPS32R2_NOT_32R6_64R6, FGR_64; } //===----------------------------------------------------------------------===// @@ -473,8 +528,10 @@ let Predicates = [HasMips32r2, IsFP64bit, NoNaNsFPMath, HasStdEnc], 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>; +def BC1F : MMRel, BC1F_FT<"bc1f", brtarget, IIBranch, MIPS_BRANCH_F>, + BC1F_FM<0, 0>, ISA_MIPS1_NOT_32R6_64R6; +def BC1T : MMRel, BC1F_FT<"bc1t", brtarget, IIBranch, MIPS_BRANCH_T>, + BC1F_FM<0, 1>, ISA_MIPS1_NOT_32R6_64R6; //===----------------------------------------------------------------------===// // Floating Point Flag Conditions @@ -499,12 +556,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]>; +def FCMP_S32 : MMRel, CEQS_FT<"s", FGR32, II_C_CC_S, MipsFPCmp>, CEQS_FM<16>, + ISA_MIPS1_NOT_32R6_64R6; +def FCMP_D32 : MMRel, CEQS_FT<"d", AFGR64, II_C_CC_D, MipsFPCmp>, CEQS_FM<17>, + ISA_MIPS1_NOT_32R6_64R6, AdditionalRequires<[NotFP64bit]>; let DecoderNamespace = "Mips64" in -def FCMP_D64 : CEQS_FT<"d", FGR64, IIFcmp, MipsFPCmp>, CEQS_FM<17>, - Requires<[IsFP64bit, HasStdEnc]>; +def FCMP_D64 : CEQS_FT<"d", FGR64, II_C_CC_D, MipsFPCmp>, CEQS_FM<17>, + ISA_MIPS1_NOT_32R6_64R6, AdditionalRequires<[IsFP64bit]>; //===----------------------------------------------------------------------===// // Floating Point Pseudo-Instructions @@ -517,9 +575,9 @@ class BuildPairF64Base<RegisterOperand RO> : [(set RO:$dst, (MipsBuildPairF64 GPR32Opnd:$lo, GPR32Opnd:$hi))]>; def BuildPairF64 : BuildPairF64Base<AFGR64Opnd>, - Requires<[NotFP64bit, HasStdEnc]>; + AdditionalRequires<[NotFP64bit]>; def BuildPairF64_64 : BuildPairF64Base<FGR64Opnd>, - Requires<[IsFP64bit, HasStdEnc]>; + AdditionalRequires<[IsFP64bit]>; // This pseudo instr gets expanded into 2 mfc1 instrs after register // allocation. @@ -530,15 +588,17 @@ class ExtractElementF64Base<RegisterOperand RO> : [(set GPR32Opnd:$dst, (MipsExtractElementF64 RO:$src, imm:$n))]>; def ExtractElementF64 : ExtractElementF64Base<AFGR64Opnd>, - Requires<[NotFP64bit, HasStdEnc]>; + AdditionalRequires<[NotFP64bit]>; def ExtractElementF64_64 : ExtractElementF64Base<FGR64Opnd>, - Requires<[IsFP64bit, HasStdEnc]>; + AdditionalRequires<[IsFP64bit]>; //===----------------------------------------------------------------------===// // InstAliases. //===----------------------------------------------------------------------===// -def : InstAlias<"bc1t $offset", (BC1T FCC0, brtarget:$offset)>; -def : InstAlias<"bc1f $offset", (BC1F FCC0, brtarget:$offset)>; +def : MipsInstAlias<"bc1t $offset", (BC1T FCC0, brtarget:$offset)>, + ISA_MIPS1_NOT_32R6_64R6; +def : MipsInstAlias<"bc1f $offset", (BC1F FCC0, brtarget:$offset)>, + ISA_MIPS1_NOT_32R6_64R6; //===----------------------------------------------------------------------===// // Floating Point Patterns @@ -551,55 +611,45 @@ def : MipsPat<(f32 (sint_to_fp 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)>; -} +def : MipsPat<(f64 (sint_to_fp GPR32Opnd:$src)), + (PseudoCVT_D32_W GPR32Opnd:$src)>, FGR_32; +def : MipsPat<(MipsTruncIntFP AFGR64Opnd:$src), + (TRUNC_W_D32 AFGR64Opnd:$src)>, FGR_32; +def : MipsPat<(f32 (fround AFGR64Opnd:$src)), + (CVT_S_D32 AFGR64Opnd:$src)>, FGR_32; +def : MipsPat<(f64 (fextend FGR32Opnd:$src)), + (CVT_D32_S FGR32Opnd:$src)>, FGR_32; -let Predicates = [IsFP64bit, HasStdEnc] in { - def : MipsPat<(f64 fpimm0), (DMTC1 ZERO_64)>; - def : MipsPat<(f64 fpimm0neg), (FNEG_D64 (DMTC1 ZERO_64))>; +def : MipsPat<(f64 fpimm0), (DMTC1 ZERO_64)>, FGR_64; +def : MipsPat<(f64 fpimm0neg), (FNEG_D64 (DMTC1 ZERO_64))>, FGR_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<(f64 (sint_to_fp GPR32Opnd:$src)), + (PseudoCVT_D64_W GPR32Opnd:$src)>, FGR_64; +def : MipsPat<(f32 (sint_to_fp GPR64Opnd:$src)), + (EXTRACT_SUBREG (PseudoCVT_S_L GPR64Opnd:$src), sub_lo)>, FGR_64; +def : MipsPat<(f64 (sint_to_fp GPR64Opnd:$src)), + (PseudoCVT_D64_L GPR64Opnd:$src)>, FGR_64; - 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<(MipsTruncIntFP FGR64Opnd:$src), + (TRUNC_W_D64 FGR64Opnd:$src)>, FGR_64; +def : MipsPat<(MipsTruncIntFP FGR32Opnd:$src), + (TRUNC_L_S FGR32Opnd:$src)>, FGR_64; +def : MipsPat<(MipsTruncIntFP FGR64Opnd:$src), + (TRUNC_L_D64 FGR64Opnd:$src)>, FGR_64; - def : MipsPat<(f32 (fround FGR64Opnd:$src)), - (CVT_S_D64 FGR64Opnd:$src)>; - def : MipsPat<(f64 (fextend FGR32Opnd:$src)), - (CVT_D64_S FGR32Opnd:$src)>; -} +def : MipsPat<(f32 (fround FGR64Opnd:$src)), + (CVT_S_D64 FGR64Opnd:$src)>, FGR_64; +def : MipsPat<(f64 (fextend FGR32Opnd:$src)), + (CVT_D64_S FGR32Opnd:$src)>, FGR_64; // 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>; - } + def : LoadRegImmPat<LWC1, f32, load>; + def : StoreRegImmPat<SWC1, f32>; - let Predicates = [IsFP64bit, HasStdEnc] in { - def : LoadRegImmPat<LDC164, f64, load>; - def : StoreRegImmPat<SDC164, f64>; - } + def : LoadRegImmPat<LDC164, f64, load>, FGR_64; + def : StoreRegImmPat<SDC164, f64>, FGR_64; - let Predicates = [NotFP64bit, HasStdEnc] in { - def : LoadRegImmPat<LDC1, f64, load>; - def : StoreRegImmPat<SDC1, f64>; - } + def : LoadRegImmPat<LDC1, f64, load>, FGR_32; + def : StoreRegImmPat<SDC1, f64>, FGR_32; } diff --git a/lib/Target/Mips/MipsInstrFormats.td b/lib/Target/Mips/MipsInstrFormats.td index 737a018c67af..6a01ae560f3a 100644 --- a/lib/Target/Mips/MipsInstrFormats.td +++ b/lib/Target/Mips/MipsInstrFormats.td @@ -93,8 +93,8 @@ class MipsInst<dag outs, dag ins, string asmstr, list<dag> pattern, // 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]; + MipsInst<outs, ins, asmstr, pattern, itin, f>, PredicateControl { + let EncodingPredicates = [HasStdEnc]; string BaseOpcode = opstr; string Arch; } @@ -109,9 +109,9 @@ class MipsPseudo<dag outs, dag ins, list<dag> pattern, // 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]; + InstrItinClass itin = IIPseudo> : + MipsPseudo<outs, ins, pattern, itin>, PredicateControl { + let EncodingPredicates = [HasStdEnc]; } // Pseudo-instructions for alternate assembly syntax (never used by codegen). @@ -375,7 +375,7 @@ class LUI_FM : StdArch { let Inst{15-0} = imm16; } -class JALR_FM : StdArch { +class JALR_FM { bits<5> rd; bits<5> rs; @@ -401,7 +401,7 @@ class BGEZAL_FM<bits<5> funct> : StdArch { let Inst{15-0} = offset; } -class SYNC_FM { +class SYNC_FM : StdArch { bits<5> stype; bits<32> Inst; @@ -479,11 +479,91 @@ class TEQI_FM<bits<5> funct> : StdArch { let Inst{20-16} = funct; let Inst{15-0} = imm16; } + +class WAIT_FM : StdArch { + bits<32> Inst; + + let Inst{31-26} = 0x10; + let Inst{25} = 1; + let Inst{24-6} = 0; + let Inst{5-0} = 0x20; +} + +class EXTS_FM<bits<6> funct> : StdArch { + bits<5> rt; + bits<5> rs; + bits<5> pos; + bits<5> lenm1; + + bits<32> Inst; + + let Inst{31-26} = 0x1c; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = lenm1; + let Inst{10-6} = pos; + let Inst{5-0} = funct; +} + +class MTMR_FM<bits<6> funct> : StdArch { + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0x1c; + let Inst{25-21} = rs; + let Inst{20-6} = 0; + let Inst{5-0} = funct; +} + +class POP_FM<bits<6> funct> : StdArch { + bits<5> rd; + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0x1c; + let Inst{25-21} = rs; + let Inst{20-16} = 0; + let Inst{15-11} = rd; + let Inst{10-6} = 0; + let Inst{5-0} = funct; +} + +class SEQ_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; +} + +class SEQI_FM<bits<6> funct> : StdArch { + bits<5> rs; + bits<5> rt; + bits<10> imm10; + + bits<32> Inst; + + let Inst{31-26} = 0x1c; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-6} = imm10; + let Inst{5-0} = funct; +} + //===----------------------------------------------------------------------===// // System calls format <op|code_|funct> //===----------------------------------------------------------------------===// -class SYS_FM<bits<6> funct> +class SYS_FM<bits<6> funct> : StdArch { bits<20> code_; bits<32> Inst; @@ -496,7 +576,7 @@ class SYS_FM<bits<6> funct> // Break instruction format <op|code_1|funct> //===----------------------------------------------------------------------===// -class BRK_FM<bits<6> funct> +class BRK_FM<bits<6> funct> : StdArch { bits<10> code_1; bits<10> code_2; @@ -511,7 +591,7 @@ class BRK_FM<bits<6> funct> // Exception return format <Cop0|1|0|funct> //===----------------------------------------------------------------------===// -class ER_FM<bits<6> funct> +class ER_FM<bits<6> funct> : StdArch { bits<32> Inst; let Inst{31-26} = 0x10; @@ -525,7 +605,7 @@ class ER_FM<bits<6> funct> // Enable/disable interrupt instruction format <Cop0|MFMC0|rt|12|0|sc|0|0> //===----------------------------------------------------------------------===// -class EI_FM<bits<1> sc> +class EI_FM<bits<1> sc> : StdArch { bits<32> Inst; bits<5> rt; @@ -569,7 +649,7 @@ class FFI<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern>: let Inst{15-0} = imm16; } -class ADDS_FM<bits<6> funct, bits<5> fmt> { +class ADDS_FM<bits<6> funct, bits<5> fmt> : StdArch { bits<5> fd; bits<5> fs; bits<5> ft; @@ -584,7 +664,7 @@ class ADDS_FM<bits<6> funct, bits<5> fmt> { let Inst{5-0} = funct; } -class ABSS_FM<bits<6> funct, bits<5> fmt> { +class ABSS_FM<bits<6> funct, bits<5> fmt> : StdArch { bits<5> fd; bits<5> fs; @@ -598,7 +678,7 @@ class ABSS_FM<bits<6> funct, bits<5> fmt> { let Inst{5-0} = funct; } -class MFC1_FM<bits<5> funct> { +class MFC1_FM<bits<5> funct> : StdArch { bits<5> rt; bits<5> fs; @@ -623,7 +703,7 @@ class LW_FM<bits<6> op> : StdArch { let Inst{15-0} = addr{15-0}; } -class MADDS_FM<bits<3> funct, bits<3> fmt> { +class MADDS_FM<bits<3> funct, bits<3> fmt> : StdArch { bits<5> fd; bits<5> fr; bits<5> fs; @@ -640,7 +720,7 @@ class MADDS_FM<bits<3> funct, bits<3> fmt> { let Inst{2-0} = fmt; } -class LWXC1_FM<bits<6> funct> { +class LWXC1_FM<bits<6> funct> : StdArch { bits<5> fd; bits<5> base; bits<5> index; @@ -655,7 +735,7 @@ class LWXC1_FM<bits<6> funct> { let Inst{5-0} = funct; } -class SWXC1_FM<bits<6> funct> { +class SWXC1_FM<bits<6> funct> : StdArch { bits<5> fs; bits<5> base; bits<5> index; @@ -670,7 +750,7 @@ class SWXC1_FM<bits<6> funct> { let Inst{5-0} = funct; } -class BC1F_FM<bit nd, bit tf> { +class BC1F_FM<bit nd, bit tf> : StdArch { bits<3> fcc; bits<16> offset; @@ -684,7 +764,7 @@ class BC1F_FM<bit nd, bit tf> { let Inst{15-0} = offset; } -class CEQS_FM<bits<5> fmt> { +class CEQS_FM<bits<5> fmt> : StdArch { bits<5> fs; bits<5> ft; bits<4> cond; @@ -704,7 +784,7 @@ 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> { +class CMov_I_F_FM<bits<6> funct, bits<5> fmt> : StdArch { bits<5> fd; bits<5> fs; bits<5> rt; @@ -736,7 +816,7 @@ class CMov_F_I_FM<bit tf> : StdArch { let Inst{5-0} = 1; } -class CMov_F_F_FM<bits<5> fmt, bit tf> { +class CMov_F_F_FM<bits<5> fmt, bit tf> : StdArch { bits<5> fd; bits<5> fs; bits<3> fcc; @@ -752,3 +832,75 @@ class CMov_F_F_FM<bits<5> fmt, bit tf> { let Inst{10-6} = fd; let Inst{5-0} = 0x11; } + +class BARRIER_FM<bits<5> op> : StdArch { + bits<32> Inst; + + let Inst{31-26} = 0; // SPECIAL + let Inst{25-21} = 0; + let Inst{20-16} = 0; // rt = 0 + let Inst{15-11} = 0; // rd = 0 + let Inst{10-6} = op; // Operation + let Inst{5-0} = 0; // SLL +} + +class SDBBP_FM : StdArch { + bits<20> code_; + + bits<32> Inst; + + let Inst{31-26} = 0b011100; // SPECIAL2 + let Inst{25-6} = code_; + let Inst{5-0} = 0b111111; // SDBBP +} + +class JR_HB_FM<bits<6> op> : StdArch{ + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0; // SPECIAL + let Inst{25-21} = rs; + let Inst{20-11} = 0; + let Inst{10} = 1; + let Inst{9-6} = 0; + let Inst{5-0} = op; +} + +class JALR_HB_FM<bits<6> op> : StdArch { + bits<5> rd; + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0; // SPECIAL + let Inst{25-21} = rs; + let Inst{20-16} = 0; + let Inst{15-11} = rd; + let Inst{10} = 1; + let Inst{9-6} = 0; + let Inst{5-0} = op; +} + +class COP0_TLB_FM<bits<6> op> : StdArch { + bits<32> Inst; + + let Inst{31-26} = 0x10; // COP0 + let Inst{25} = 1; // CO + let Inst{24-6} = 0; + let Inst{5-0} = op; // Operation +} + +class CACHEOP_FM<bits<6> op> : StdArch { + bits<21> addr; + bits<5> hint; + bits<5> base = addr{20-16}; + bits<16> offset = addr{15-0}; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = base; + let Inst{20-16} = hint; + let Inst{15-0} = offset; +} diff --git a/lib/Target/Mips/MipsInstrInfo.cpp b/lib/Target/Mips/MipsInstrInfo.cpp index 0ebad0584757..dcc0e24e080b 100644 --- a/lib/Target/Mips/MipsInstrInfo.cpp +++ b/lib/Target/Mips/MipsInstrInfo.cpp @@ -22,23 +22,23 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetRegistry.h" +using namespace llvm; + #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) {} +MipsInstrInfo::MipsInstrInfo(const MipsSubtarget &STI, unsigned UncondBr) + : MipsGenInstrInfo(Mips::ADJCALLSTACKDOWN, Mips::ADJCALLSTACKUP), + Subtarget(STI), UncondBrOpc(UncondBr) {} -const MipsInstrInfo *MipsInstrInfo::create(MipsTargetMachine &TM) { - if (TM.getSubtargetImpl()->inMips16Mode()) - return llvm::createMips16InstrInfo(TM); +const MipsInstrInfo *MipsInstrInfo::create(MipsSubtarget &STI) { + if (STI.inMips16Mode()) + return llvm::createMips16InstrInfo(STI); - return llvm::createMipsSEInstrInfo(TM); + return llvm::createMipsSEInstrInfo(STI); } bool MipsInstrInfo::isZeroImm(const MachineOperand &op) const { @@ -94,10 +94,10 @@ bool MipsInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, return (BT == BT_None) || (BT == BT_Indirect); } -void MipsInstrInfo::BuildCondBr(MachineBasicBlock &MBB, - MachineBasicBlock *TBB, DebugLoc DL, - const SmallVectorImpl<MachineOperand>& Cond) - const { +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); @@ -113,11 +113,9 @@ void MipsInstrInfo::BuildCondBr(MachineBasicBlock &MBB, MIB.addMBB(TBB); } -unsigned MipsInstrInfo:: -InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, - MachineBasicBlock *FBB, - const SmallVectorImpl<MachineOperand> &Cond, - DebugLoc DL) const { +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"); @@ -145,9 +143,7 @@ InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, return 1; } -unsigned MipsInstrInfo:: -RemoveBranch(MachineBasicBlock &MBB) const -{ +unsigned MipsInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const { MachineBasicBlock::reverse_iterator I = MBB.rbegin(), REnd = MBB.rend(); MachineBasicBlock::reverse_iterator FirstBr; unsigned removed; @@ -160,7 +156,7 @@ RemoveBranch(MachineBasicBlock &MBB) const // Up to 2 branches are removed. // Note that indirect branches are not removed. - for(removed = 0; I != REnd && removed < 2; ++I, ++removed) + for (removed = 0; I != REnd && removed < 2; ++I, ++removed) if (!getAnalyzableBrOpc(I->getOpcode())) break; @@ -171,20 +167,18 @@ RemoveBranch(MachineBasicBlock &MBB) const /// ReverseBranchCondition - Return the inverse opcode of the /// specified Branch instruction. -bool MipsInstrInfo:: -ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const -{ +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 { +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(); @@ -195,7 +189,7 @@ AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, 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; + TBB = FBB = nullptr; return BT_NoBranch; } @@ -209,7 +203,7 @@ AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, // Get the second to last instruction in the block. unsigned SecondLastOpc = 0; - MachineInstr *SecondLastInst = NULL; + MachineInstr *SecondLastInst = nullptr; if (++I != REnd) { SecondLastInst = &*I; diff --git a/lib/Target/Mips/MipsInstrInfo.h b/lib/Target/Mips/MipsInstrInfo.h index d9ac961cd33c..bdf2fd37ed8c 100644 --- a/lib/Target/Mips/MipsInstrInfo.h +++ b/lib/Target/Mips/MipsInstrInfo.h @@ -9,6 +9,10 @@ // // This file contains the Mips implementation of the TargetInstrInfo class. // +// FIXME: We need to override TargetInstrInfo::getInlineAsmLength method in +// order for MipsLongBranch pass to work correctly when the code has inline +// assembly. The returned value doesn't have to be the asm instruction's exact +// size in bytes; MipsLongBranch only expects it to be the correct upper bound. //===----------------------------------------------------------------------===// #ifndef MIPSINSTRUCTIONINFO_H @@ -29,7 +33,7 @@ namespace llvm { class MipsInstrInfo : public MipsGenInstrInfo { virtual void anchor(); protected: - MipsTargetMachine &TM; + const MipsSubtarget &Subtarget; unsigned UncondBrOpc; public: @@ -42,25 +46,25 @@ public: BT_Indirect // One indirct branch. }; - explicit MipsInstrInfo(MipsTargetMachine &TM, unsigned UncondBrOpc); + explicit MipsInstrInfo(const MipsSubtarget &STI, unsigned UncondBrOpc); - static const MipsInstrInfo *create(MipsTargetMachine &TM); + static const MipsInstrInfo *create(MipsSubtarget &STI); /// Branch Analysis - virtual bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, - MachineBasicBlock *&FBB, - SmallVectorImpl<MachineOperand> &Cond, - bool AllowModify) const; + bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const override; - virtual unsigned RemoveBranch(MachineBasicBlock &MBB) const; + unsigned RemoveBranch(MachineBasicBlock &MBB) const override; - virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, - MachineBasicBlock *FBB, - const SmallVectorImpl<MachineOperand> &Cond, - DebugLoc DL) const; + unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond, + DebugLoc DL) const override; - virtual - bool ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const; + bool + ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override; BranchType AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, @@ -69,8 +73,8 @@ public: SmallVectorImpl<MachineInstr*> &BranchInstrs) const; /// Insert nop instruction when hazard condition is found - virtual void insertNoop(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI) const; + void insertNoop(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const override; /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As /// such, whenever a client has an instance of instruction info, it should @@ -83,19 +87,19 @@ public: /// 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 { + void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const override { 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 { + void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const override { loadRegFromStack(MBB, MBBI, DestReg, FrameIndex, RC, TRI, 0); } @@ -136,8 +140,8 @@ private: }; /// Create MipsInstrInfo objects. -const MipsInstrInfo *createMips16InstrInfo(MipsTargetMachine &TM); -const MipsInstrInfo *createMipsSEInstrInfo(MipsTargetMachine &TM); +const MipsInstrInfo *createMips16InstrInfo(const MipsSubtarget &STI); +const MipsInstrInfo *createMipsSEInstrInfo(const MipsSubtarget &STI); } diff --git a/lib/Target/Mips/MipsInstrInfo.td b/lib/Target/Mips/MipsInstrInfo.td index ebdbaa416fcc..8e9472c2d9d8 100644 --- a/lib/Target/Mips/MipsInstrInfo.td +++ b/lib/Target/Mips/MipsInstrInfo.td @@ -146,52 +146,146 @@ def MipsSDR : SDNode<"MipsISD::SDR", SDTStore, //===----------------------------------------------------------------------===// // 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()">, +def HasMips2 : Predicate<"Subtarget->hasMips2()">, + AssemblerPredicate<"FeatureMips2">; +def HasMips3_32 : Predicate<"Subtarget->hasMips3_32()">, + AssemblerPredicate<"FeatureMips3_32">; +def HasMips3_32r2 : Predicate<"Subtarget->hasMips3_32r2()">, + AssemblerPredicate<"FeatureMips3_32r2">; +def HasMips3 : Predicate<"Subtarget->hasMips3()">, + AssemblerPredicate<"FeatureMips3">; +def HasMips4_32 : Predicate<"Subtarget->hasMips4_32()">, + AssemblerPredicate<"FeatureMips4_32">; +def HasMips4_32r2 : Predicate<"Subtarget->hasMips4_32r2()">, + AssemblerPredicate<"FeatureMips4_32r2">; +def HasMips5_32r2 : Predicate<"Subtarget->hasMips5_32r2()">, + AssemblerPredicate<"FeatureMips5_32r2">; +def HasMips32 : Predicate<"Subtarget->hasMips32()">, AssemblerPredicate<"FeatureMips32">; -def HasMips32r2 : Predicate<"Subtarget.hasMips32r2()">, +def HasMips32r2 : Predicate<"Subtarget->hasMips32r2()">, AssemblerPredicate<"FeatureMips32r2">; -def HasMips64 : Predicate<"Subtarget.hasMips64()">, +def HasMips32r6 : Predicate<"Subtarget->hasMips32r6()">, + AssemblerPredicate<"FeatureMips32r6">; +def NotMips32r6 : Predicate<"!Subtarget->hasMips32r6()">, + AssemblerPredicate<"!FeatureMips32r6">; +def IsGP64bit : Predicate<"Subtarget->isGP64bit()">, + AssemblerPredicate<"FeatureGP64Bit">; +def IsGP32bit : Predicate<"!Subtarget->isGP64bit()">, + AssemblerPredicate<"!FeatureGP64Bit">; +def HasMips64 : Predicate<"Subtarget->hasMips64()">, AssemblerPredicate<"FeatureMips64">; -def NotMips64 : Predicate<"!Subtarget.hasMips64()">, - AssemblerPredicate<"!FeatureMips64">; -def HasMips64r2 : Predicate<"Subtarget.hasMips64r2()">, +def HasMips64r2 : Predicate<"Subtarget->hasMips64r2()">, AssemblerPredicate<"FeatureMips64r2">; -def IsN64 : Predicate<"Subtarget.isABI_N64()">, +def HasMips64r6 : Predicate<"Subtarget->hasMips64r6()">, + AssemblerPredicate<"FeatureMips64r6">; +def NotMips64r6 : Predicate<"!Subtarget->hasMips64r6()">, + AssemblerPredicate<"!FeatureMips64r6">; +def IsN64 : Predicate<"Subtarget->isABI_N64()">, AssemblerPredicate<"FeatureN64">; -def NotN64 : Predicate<"!Subtarget.isABI_N64()">, - AssemblerPredicate<"!FeatureN64">; -def InMips16Mode : Predicate<"Subtarget.inMips16Mode()">, +def InMips16Mode : Predicate<"Subtarget->inMips16Mode()">, AssemblerPredicate<"FeatureMips16">; +def HasCnMips : Predicate<"Subtarget->hasCnMips()">, + AssemblerPredicate<"FeatureCnMips">; 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()">, +def NoNaNsFPMath : Predicate<"TM.Options.NoNaNsFPMath">; +def HasStdEnc : Predicate<"Subtarget->hasStandardEncoding()">, AssemblerPredicate<"!FeatureMips16">; -def NotDSP : Predicate<"!Subtarget.hasDSP()">; -def InMicroMips : Predicate<"Subtarget.inMicroMipsMode()">, +def NotDSP : Predicate<"!Subtarget->hasDSP()">; +def InMicroMips : Predicate<"Subtarget->inMicroMipsMode()">, AssemblerPredicate<"FeatureMicroMips">; -def NotInMicroMips : Predicate<"!Subtarget.inMicroMipsMode()">, +def NotInMicroMips : Predicate<"!Subtarget->inMicroMipsMode()">, AssemblerPredicate<"!FeatureMicroMips">; -def IsLE : Predicate<"Subtarget.isLittle()">; -def IsBE : Predicate<"!Subtarget.isLittle()">; +def IsLE : Predicate<"Subtarget->isLittle()">; +def IsBE : Predicate<"!Subtarget->isLittle()">; +def IsNotNaCl : Predicate<"!Subtarget->isTargetNaCl()">; + +//===----------------------------------------------------------------------===// +// Mips GPR size adjectives. +// They are mutually exclusive. +//===----------------------------------------------------------------------===// + +class GPR_32 { list<Predicate> GPRPredicates = [IsGP32bit]; } +class GPR_64 { list<Predicate> GPRPredicates = [IsGP64bit]; } + +//===----------------------------------------------------------------------===// +// Mips ISA/ASE membership and instruction group membership adjectives. +// They are mutually exclusive. +//===----------------------------------------------------------------------===// + +// FIXME: I'd prefer to use additive predicates to build the instruction sets +// but we are short on assembler feature bits at the moment. Using a +// subtractive predicate will hopefully keep us under the 32 predicate +// limit long enough to develop an alternative way to handle P1||P2 +// predicates. +class ISA_MIPS1_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [NotMips32r6, NotMips64r6]; +} +class ISA_MIPS2 { list<Predicate> InsnPredicates = [HasMips2]; } +class ISA_MIPS2_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips2, NotMips32r6, NotMips64r6]; +} +class ISA_MIPS3 { list<Predicate> InsnPredicates = [HasMips3]; } +class ISA_MIPS3_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips3, NotMips32r6, NotMips64r6]; +} +class ISA_MIPS32 { list<Predicate> InsnPredicates = [HasMips32]; } +class ISA_MIPS32_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips32, NotMips32r6, NotMips64r6]; +} +class ISA_MIPS32R2 { list<Predicate> InsnPredicates = [HasMips32r2]; } +class ISA_MIPS32R2_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips32r2, NotMips32r6, NotMips64r6]; +} +class ISA_MIPS64 { list<Predicate> InsnPredicates = [HasMips64]; } +class ISA_MIPS64_NOT_64R6 { + list<Predicate> InsnPredicates = [HasMips64, NotMips64r6]; +} +class ISA_MIPS64R2 { list<Predicate> InsnPredicates = [HasMips64r2]; } +class ISA_MIPS32R6 { list<Predicate> InsnPredicates = [HasMips32r6]; } +class ISA_MIPS64R6 { list<Predicate> InsnPredicates = [HasMips64r6]; } + +// The portions of MIPS-III that were also added to MIPS32 +class INSN_MIPS3_32 { list<Predicate> InsnPredicates = [HasMips3_32]; } + +// The portions of MIPS-III that were also added to MIPS32 but were removed in +// MIPS32r6 and MIPS64r6. +class INSN_MIPS3_32_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips3_32, NotMips32r6, NotMips64r6]; +} + +// The portions of MIPS-III that were also added to MIPS32 +class INSN_MIPS3_32R2 { list<Predicate> InsnPredicates = [HasMips3_32r2]; } -class MipsPat<dag pattern, dag result> : Pat<pattern, result> { - let Predicates = [HasStdEnc]; +// The portions of MIPS-IV that were also added to MIPS32 but were removed in +// MIPS32r6 and MIPS64r6. +class INSN_MIPS4_32_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips4_32, NotMips32r6, NotMips64r6]; } +// The portions of MIPS-IV that were also added to MIPS32r2 but were removed in +// MIPS32r6 and MIPS64r6. +class INSN_MIPS4_32R2_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips4_32r2, NotMips32r6, NotMips64r6]; +} + +// The portions of MIPS-V that were also added to MIPS32r2 but were removed in +// MIPS32r6 and MIPS64r6. +class INSN_MIPS5_32R2_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips5_32r2, NotMips32r6, NotMips64r6]; +} + +//===----------------------------------------------------------------------===// + +class MipsPat<dag pattern, dag result> : Pat<pattern, result>, PredicateControl { + let EncodingPredicates = [HasStdEnc]; +} + +class MipsInstAlias<string Asm, dag Result, bit Emit = 0b1> : + InstAlias<Asm, Result, Emit>, PredicateControl; + class IsCommutable { bit isCommutable = 1; } @@ -235,23 +329,49 @@ include "MipsInstrFormats.td" // Mips Operand, Complex Patterns and Transformations Definitions. //===----------------------------------------------------------------------===// +def MipsJumpTargetAsmOperand : AsmOperandClass { + let Name = "JumpTarget"; + let ParserMethod = "ParseJumpTarget"; + let PredicateMethod = "isImm"; + let RenderMethod = "addImmOperands"; +} + // Instruction operand types def jmptarget : Operand<OtherVT> { let EncoderMethod = "getJumpTargetOpValue"; + let ParserMatchClass = MipsJumpTargetAsmOperand; } def brtarget : Operand<OtherVT> { let EncoderMethod = "getBranchTargetOpValue"; let OperandType = "OPERAND_PCREL"; let DecoderMethod = "DecodeBranchTarget"; + let ParserMatchClass = MipsJumpTargetAsmOperand; } def calltarget : Operand<iPTR> { let EncoderMethod = "getJumpTargetOpValue"; + let ParserMatchClass = MipsJumpTargetAsmOperand; } +def simm9 : Operand<i32>; +def simm10 : Operand<i32>; +def simm11 : Operand<i32>; + def simm16 : Operand<i32> { let DecoderMethod= "DecodeSimm16"; } +def simm19_lsl2 : Operand<i32> { + let EncoderMethod = "getSimm19Lsl2Encoding"; + let DecoderMethod = "DecodeSimm19Lsl2"; + let ParserMatchClass = MipsJumpTargetAsmOperand; +} + +def simm18_lsl3 : Operand<i32> { + let EncoderMethod = "getSimm18Lsl3Encoding"; + let DecoderMethod = "DecodeSimm18Lsl3"; + let ParserMatchClass = MipsJumpTargetAsmOperand; +} + def simm20 : Operand<i32> { } @@ -265,7 +385,20 @@ def simm16_64 : Operand<i64> { let DecoderMethod = "DecodeSimm16"; } +// Zero +def uimmz : Operand<i32> { + let PrintMethod = "printUnsignedImm"; +} + // Unsigned Operand +def uimm2 : Operand<i32> { + let PrintMethod = "printUnsignedImm"; +} + +def uimm3 : Operand<i32> { + let PrintMethod = "printUnsignedImm"; +} + def uimm5 : Operand<i32> { let PrintMethod = "printUnsignedImm"; } @@ -286,24 +419,30 @@ def MipsMemAsmOperand : AsmOperandClass { let ParserMethod = "parseMemOperand"; } +def MipsMemSimm11AsmOperand : AsmOperandClass { + let Name = "MemOffsetSimm11"; + let SuperClasses = [MipsMemAsmOperand]; + let RenderMethod = "addMemOperands"; + let ParserMethod = "parseMemOperand"; + let PredicateMethod = "isMemWithSimmOffset<11>"; + //let DiagnosticType = "Simm11"; +} + 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; } - -def InvertedImOperand : Operand<i32> { +def InvertedImOperand64 : Operand<i64> { let ParserMatchClass = MipsInvertedImmoperand; } -// Address operand -def mem : Operand<iPTR> { +class mem_generic : Operand<iPTR> { let PrintMethod = "printMemOperand"; let MIOperandInfo = (ops ptr_rc, simm16); let EncoderMethod = "getMemEncoding"; @@ -311,6 +450,26 @@ def mem : Operand<iPTR> { let OperandType = "OPERAND_MEMORY"; } +// Address operand +def mem : mem_generic; + +// MSA specific address operand +def mem_msa : mem_generic { + let MIOperandInfo = (ops ptr_rc, simm10); + let EncoderMethod = "getMSAMemEncoding"; +} + +def mem_simm9 : mem_generic { + let MIOperandInfo = (ops ptr_rc, simm9); + let EncoderMethod = "getMemEncoding"; +} + +def mem_simm11 : mem_generic { + let MIOperandInfo = (ops ptr_rc, simm11); + let EncoderMethod = "getMemEncoding"; + let ParserMatchClass = MipsMemSimm11AsmOperand; +} + def mem_ea : Operand<iPTR> { let PrintMethod = "printMemOperandEA"; let MIOperandInfo = (ops ptr_rc, simm16); @@ -321,7 +480,7 @@ def mem_ea : Operand<iPTR> { def PtrRC : Operand<iPTR> { let MIOperandInfo = (ops ptr_rc); let DecoderMethod = "DecodePtrRegisterClass"; - let ParserMatchClass = PtrRegAsmOperand; + let ParserMatchClass = GPR32AsmOperand; } // size operand of ext instruction @@ -349,6 +508,9 @@ def HI16 : SDNodeXForm<imm, [{ // Plus 1. def Plus1 : SDNodeXForm<imm, [{ return getImm(N, N->getSExtValue() + 1); }]>; +// Node immediate is zero (e.g. insve.d) +def immz : PatLeaf<(imm), [{ return N->getSExtValue() == 0; }]>; + // Node immediate fits as 16-bit sign extended on target immediate. // e.g. addi, andi def immSExt8 : PatLeaf<(imm), [{ return isInt<8>(N->getSExtValue()); }]>; @@ -400,6 +562,8 @@ def addrRegReg : def addrDefault : ComplexPattern<iPTR, 2, "selectAddrDefault", [frameindex]>; +def addrimm10 : ComplexPattern<iPTR, 2, "selectIntAddrMSA", [frameindex]>; + //===----------------------------------------------------------------------===// // Instructions specific format //===----------------------------------------------------------------------===// @@ -413,6 +577,7 @@ class ArithLogicR<string opstr, RegisterOperand RO, bit isComm = 0, [(set RO:$rd, (OpNode RO:$rs, RO:$rt))], Itin, FrmR, opstr> { let isCommutable = isComm; let isReMaterializable = 1; + let TwoOperandAliasConstraint = "$rd = $rs"; } // Arithmetic and logical instructions with 2 register operands. @@ -429,9 +594,9 @@ class ArithLogicI<string opstr, Operand Od, RegisterOperand RO, } // Arithmetic Multiply ADD/SUB -class MArithR<string opstr, bit isComm = 0> : +class MArithR<string opstr, InstrItinClass itin, bit isComm = 0> : InstSE<(outs), (ins GPR32Opnd:$rs, GPR32Opnd:$rt), - !strconcat(opstr, "\t$rs, $rt"), [], IIImult, FrmR, opstr> { + !strconcat(opstr, "\t$rs, $rt"), [], itin, FrmR, opstr> { let Defs = [HI0, LO0]; let Uses = [HI0, LO0]; let isCommutable = isComm; @@ -441,28 +606,32 @@ class MArithR<string opstr, bit isComm = 0> : 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> { + [(set RO:$rd, (not (or RO:$rs, RO:$rt)))], II_NOR, FrmR, opstr> { let isCommutable = 1; } // Shifts class shift_rotate_imm<string opstr, Operand ImmOpnd, - RegisterOperand RO, SDPatternOperator OpNode = null_frag, + RegisterOperand RO, InstrItinClass itin, + 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>; + [(set RO:$rd, (OpNode RO:$rt, PF:$shamt))], itin, FrmR, opstr> { + let TwoOperandAliasConstraint = "$rt = $rd"; +} -class shift_rotate_reg<string opstr, RegisterOperand RO, +class shift_rotate_reg<string opstr, RegisterOperand RO, InstrItinClass itin, 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>; + [(set RO:$rd, (OpNode RO:$rt, GPR32Opnd:$rs))], itin, 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 { + [], II_LUI, FrmI, opstr>, IsAsCheapAsAMove { let neverHasSideEffects = 1; let isReMaterializable = 1; } @@ -533,14 +702,14 @@ 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>; + II_SLT_SLTU, 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>; + II_SLTI_SLTIU, FrmI, opstr>; // Jump class JumpFJ<DAGOperand opnd, string opstr, SDPatternOperator operator, @@ -562,7 +731,7 @@ class UncondBranch<Instruction BEQInst> : let isTerminator = 1; let isBarrier = 1; let hasDelaySlot = 1; - let Predicates = [RelocPIC, HasStdEnc]; + let AdditionalPredicates = [RelocPIC]; let Defs = [AT]; } @@ -574,20 +743,11 @@ class JumpFR<string opstr, RegisterOperand RO, FrmR, opstr>; // Indirect branch -class IndirectBranch<string opstr, RegisterOperand RO> : - JumpFR<opstr, RO, brind> { +class IndirectBranch<string opstr, RegisterOperand RO> : JumpFR<opstr, RO> { 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> : @@ -603,7 +763,7 @@ let isCall=1, hasDelaySlot=1, Defs = [RA] in { class JumpLinkReg<string opstr, RegisterOperand RO>: InstSE<(outs RO:$rd), (ins RO:$rs), !strconcat(opstr, "\t$rd, $rs"), - [], IIBranch, FrmR, opstr>; + [], IIBranch, FrmR>; class BGEZAL_FT<string opstr, DAGOperand opnd, RegisterOperand RO> : InstSE<(outs), (ins RO:$rs, opnd:$offset), @@ -611,6 +771,18 @@ let isCall=1, hasDelaySlot=1, Defs = [RA] in { } +let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, hasDelaySlot = 1, + hasExtraSrcRegAllocReq = 1, Defs = [AT] in { + class TailCall<Instruction JumpInst> : + PseudoSE<(outs), (ins calltarget:$target), [], IIBranch>, + PseudoInstExpansion<(JumpInst jmptarget:$target)>; + + class TailCallReg<RegisterOperand RO, Instruction JRInst, + RegisterOperand ResRO = RO> : + PseudoSE<(outs), (ins RO:$rs), [(MipsTailCall RO:$rs)], IIBranch>, + PseudoInstExpansion<(JRInst ResRO:$rs)>; +} + class BAL_BR_Pseudo<Instruction RealInst> : PseudoSE<(outs), (ins brtarget:$offset), [], IIBranch>, PseudoInstExpansion<(RealInst ZERO, brtarget:$offset)> { @@ -624,36 +796,32 @@ class BAL_BR_Pseudo<Instruction RealInst> : // Syscall class SYS_FT<string opstr> : InstSE<(outs), (ins uimm20:$code_), - !strconcat(opstr, "\t$code_"), [], NoItinerary, FrmI>; + !strconcat(opstr, "\t$code_"), [], NoItinerary, FrmI, opstr>; // Break class BRK_FT<string opstr> : InstSE<(outs), (ins uimm10:$code_1, uimm10:$code_2), - !strconcat(opstr, "\t$code_1, $code_2"), [], NoItinerary, FrmOther>; + !strconcat(opstr, "\t$code_1, $code_2"), [], NoItinerary, + FrmOther, opstr>; // (D)Eret class ER_FT<string opstr> : InstSE<(outs), (ins), - opstr, [], NoItinerary, FrmOther>; + opstr, [], NoItinerary, FrmOther, opstr>; // Interrupts class DEI_FT<string opstr, RegisterOperand RO> : InstSE<(outs RO:$rt), (ins), - !strconcat(opstr, "\t$rt"), [], NoItinerary, FrmOther>; + !strconcat(opstr, "\t$rt"), [], NoItinerary, FrmOther, opstr>; // 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; -} + InstSE<(outs), (ins), opstr, [], NoItinerary, FrmOther, opstr>; // Sync let hasSideEffects = 1 in -class SYNC_FT : +class SYNC_FT<string opstr> : InstSE<(outs), (ins i32imm:$stype), "sync $stype", [(MipsSync imm:$stype)], - NoItinerary, FrmOther>; + NoItinerary, FrmOther, opstr>; let hasSideEffects = 1 in class TEQ_FT<string opstr, RegisterOperand RO> : @@ -690,12 +858,13 @@ class MultDivPseudo<Instruction RealInst, RegisterClass R0, RegisterOperand R1, // Pseudo multiply add/sub instruction with explicit accumulator register // operands. -class MAddSubPseudo<Instruction RealInst, SDPatternOperator OpNode> +class MAddSubPseudo<Instruction RealInst, SDPatternOperator OpNode, + InstrItinClass itin> : PseudoSE<(outs ACC64:$ac), (ins GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64:$acin), [(set ACC64:$ac, (OpNode GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64:$acin))], - IIImult>, + itin>, PseudoInstExpansion<(RealInst GPR32Opnd:$rs, GPR32Opnd:$rt)> { string Constraints = "$acin = $ac"; } @@ -710,21 +879,22 @@ class Div<string opstr, InstrItinClass itin, RegisterOperand RO, // 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>; + [(set DstRC:$rd, (OpNode SrcRC:$hilo))], II_MFHI_MFLO>; class MoveFromLOHI<string opstr, RegisterOperand RO, Register UseReg>: - InstSE<(outs RO:$rd), (ins), !strconcat(opstr, "\t$rd"), [], IIHiLo, FrmR, - opstr> { + InstSE<(outs RO:$rd), (ins), !strconcat(opstr, "\t$rd"), [], II_MFHI_MFLO, + 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>; + [(set DstRC:$lohi, (MipsMTLOHI SrcRC:$lo, SrcRC:$hi))], + II_MTHI_MTLO>; class MoveToLOHI<string opstr, RegisterOperand RO, list<Register> DefRegs>: - InstSE<(outs), (ins RO:$rs), !strconcat(opstr, "\t$rs"), [], IIHiLo, + InstSE<(outs), (ins RO:$rs), !strconcat(opstr, "\t$rs"), [], II_MTHI_MTLO, FrmR, opstr> { let Defs = DefRegs; let neverHasSideEffects = 1; @@ -732,7 +902,8 @@ class MoveToLOHI<string opstr, RegisterOperand RO, list<Register> DefRegs>: 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> { + [(set RO:$rt, addr:$addr)], NoItinerary, FrmI, + !strconcat(opstr, "_lea")> { let isCodeGenOnly = 1; let DecoderMethod = "DecodeMem"; } @@ -740,34 +911,29 @@ class EffectiveAddress<string opstr, RegisterOperand RO> : // 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]>; + [(set RO:$rd, (ctlz RO:$rs))], II_CLZ, FrmR, opstr>; 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]>; - + [(set RO:$rd, (ctlz (not RO:$rs)))], II_CLO, FrmR, opstr>; // Sign Extend in Register. -class SignExtInReg<string opstr, ValueType vt, RegisterOperand RO> : +class SignExtInReg<string opstr, ValueType vt, RegisterOperand RO, + InstrItinClass itin> : 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]; -} + [(set RO:$rd, (sext_inreg RO:$rt, vt))], itin, FrmR, opstr>; // 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>; + II_RDHWR, FrmR>; // Ext and Ins class ExtBase<string opstr, RegisterOperand RO, Operand PosOpnd, @@ -775,17 +941,14 @@ class ExtBase<string opstr, RegisterOperand RO, Operand PosOpnd, 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]; -} + FrmR, opstr>, ISA_MIPS32R2; 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]; + NoItinerary, FrmR, opstr>, ISA_MIPS32R2 { let Constraints = "$src = $rt"; } @@ -876,6 +1039,18 @@ let isPseudo = 1, isCodeGenOnly = 1 in { def STORE_ACC64 : Store<"", ACC64>; } +// We need these two pseudo instructions to avoid offset calculation for long +// branches. See the comment in file MipsLongBranch.cpp for detailed +// explanation. + +// Expands to: lui $dst, %hi($tgt - $baltgt) +def LONG_BRANCH_LUi : PseudoSE<(outs GPR32Opnd:$dst), + (ins brtarget:$tgt, brtarget:$baltgt), []>; + +// Expands to: addiu $dst, $src, %lo($tgt - $baltgt) +def LONG_BRANCH_ADDiu : PseudoSE<(outs GPR32Opnd:$dst), + (ins GPR32Opnd:$src, brtarget:$tgt, brtarget:$baltgt), []>; + //===----------------------------------------------------------------------===// // Instruction definition //===----------------------------------------------------------------------===// @@ -884,88 +1059,95 @@ let isPseudo = 1, isCodeGenOnly = 1 in { //===----------------------------------------------------------------------===// /// Arithmetic Instructions (ALU Immediate) -def ADDiu : MMRel, ArithLogicI<"addiu", simm16, GPR32Opnd, IIArith, immSExt16, +def ADDiu : MMRel, ArithLogicI<"addiu", simm16, GPR32Opnd, II_ADDIU, immSExt16, add>, ADDI_FM<0x9>, IsAsCheapAsAMove; -def ADDi : MMRel, ArithLogicI<"addi", simm16, GPR32Opnd>, ADDI_FM<0x8>; +def ADDi : MMRel, ArithLogicI<"addi", simm16, GPR32Opnd>, ADDI_FM<0x8>, + ISA_MIPS1_NOT_32R6_64R6; 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, +def ANDi : MMRel, ArithLogicI<"andi", uimm16, GPR32Opnd, II_ANDI, immZExt16, and>, ADDI_FM<0xc>; -def ORi : MMRel, ArithLogicI<"ori", uimm16, GPR32Opnd, IILogic, immZExt16, +def ORi : MMRel, ArithLogicI<"ori", uimm16, GPR32Opnd, II_ORI, immZExt16, or>, ADDI_FM<0xd>; -def XORi : MMRel, ArithLogicI<"xori", uimm16, GPR32Opnd, IILogic, immZExt16, +def XORi : MMRel, ArithLogicI<"xori", uimm16, GPR32Opnd, II_XORI, 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>, +def ADDu : MMRel, ArithLogicR<"addu", GPR32Opnd, 1, II_ADDU, add>, ADD_FM<0, 0x21>; -def SUBu : MMRel, ArithLogicR<"subu", GPR32Opnd, 0, IIArith, sub>, +def SUBu : MMRel, ArithLogicR<"subu", GPR32Opnd, 0, II_SUBU, sub>, ADD_FM<0, 0x23>; let Defs = [HI0, LO0] in -def MUL : MMRel, ArithLogicR<"mul", GPR32Opnd, 1, IIImul, mul>, - ADD_FM<0x1c, 2>; +def MUL : MMRel, ArithLogicR<"mul", GPR32Opnd, 1, II_MUL, mul>, + ADD_FM<0x1c, 2>, ISA_MIPS32_NOT_32R6_64R6; 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>, +def AND : MMRel, ArithLogicR<"and", GPR32Opnd, 1, II_AND, and>, ADD_FM<0, 0x24>; -def OR : MMRel, ArithLogicR<"or", GPR32Opnd, 1, IILogic, or>, +def OR : MMRel, ArithLogicR<"or", GPR32Opnd, 1, II_OR, or>, ADD_FM<0, 0x25>; -def XOR : MMRel, ArithLogicR<"xor", GPR32Opnd, 1, IILogic, xor>, +def XOR : MMRel, ArithLogicR<"xor", GPR32Opnd, 1, II_XOR, 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>; +def SLL : MMRel, shift_rotate_imm<"sll", uimm5, GPR32Opnd, II_SLL, shl, + immZExt5>, SRA_FM<0, 0>; +def SRL : MMRel, shift_rotate_imm<"srl", uimm5, GPR32Opnd, II_SRL, srl, + immZExt5>, SRA_FM<2, 0>; +def SRA : MMRel, shift_rotate_imm<"sra", uimm5, GPR32Opnd, II_SRA, sra, + immZExt5>, SRA_FM<3, 0>; +def SLLV : MMRel, shift_rotate_reg<"sllv", GPR32Opnd, II_SLLV, shl>, + SRLV_FM<4, 0>; +def SRLV : MMRel, shift_rotate_reg<"srlv", GPR32Opnd, II_SRLV, srl>, + SRLV_FM<6, 0>; +def SRAV : MMRel, shift_rotate_reg<"srav", GPR32Opnd, II_SRAV, 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>; -} +def ROTR : MMRel, shift_rotate_imm<"rotr", uimm5, GPR32Opnd, II_ROTR, rotr, + immZExt5>, + SRA_FM<2, 1>, ISA_MIPS32R2; +def ROTRV : MMRel, shift_rotate_reg<"rotrv", GPR32Opnd, II_ROTRV, rotr>, + SRLV_FM<6, 1>, ISA_MIPS32R2; /// 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, +def LB : Load<"lb", GPR32Opnd, sextloadi8, II_LB>, MMRel, LW_FM<0x20>; +def LBu : Load<"lbu", GPR32Opnd, zextloadi8, II_LBU, addrDefault>, MMRel, LW_FM<0x24>; -def LH : Load<"lh", GPR32Opnd, sextloadi16, IILoad, addrDefault>, MMRel, +def LH : Load<"lh", GPR32Opnd, sextloadi16, II_LH, 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, +def LHu : Load<"lhu", GPR32Opnd, zextloadi16, II_LHU>, MMRel, LW_FM<0x25>; +def LW : Load<"lw", GPR32Opnd, load, II_LW, 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>; +def SB : Store<"sb", GPR32Opnd, truncstorei8, II_SB>, MMRel, LW_FM<0x28>; +def SH : Store<"sh", GPR32Opnd, truncstorei16, II_SH>, MMRel, LW_FM<0x29>; +def SW : Store<"sw", GPR32Opnd, store, II_SW>, 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>; +let EncodingPredicates = []<Predicate>, // FIXME: Lack of HasStdEnc is probably a bug + AdditionalPredicates = [NotInMicroMips] in { +def LWL : LoadLeftRight<"lwl", MipsLWL, GPR32Opnd, II_LWL>, LW_FM<0x22>, + ISA_MIPS1_NOT_32R6_64R6; +def LWR : LoadLeftRight<"lwr", MipsLWR, GPR32Opnd, II_LWR>, LW_FM<0x26>, + ISA_MIPS1_NOT_32R6_64R6; +def SWL : StoreLeftRight<"swl", MipsSWL, GPR32Opnd, II_SWL>, LW_FM<0x2a>, + ISA_MIPS1_NOT_32R6_64R6; +def SWR : StoreLeftRight<"swr", MipsSWR, GPR32Opnd, II_SWR>, LW_FM<0x2e>, + ISA_MIPS1_NOT_32R6_64R6; } -def SYNC : SYNC_FT, SYNC_FM; +def SYNC : MMRel, SYNC_FT<"sync">, SYNC_FM, ISA_MIPS32; 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>; @@ -973,32 +1155,42 @@ 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 TEQI : MMRel, TEQI_FT<"teqi", GPR32Opnd>, TEQI_FM<0xc>, + ISA_MIPS2_NOT_32R6_64R6; +def TGEI : MMRel, TEQI_FT<"tgei", GPR32Opnd>, TEQI_FM<0x8>, + ISA_MIPS2_NOT_32R6_64R6; +def TGEIU : MMRel, TEQI_FT<"tgeiu", GPR32Opnd>, TEQI_FM<0x9>, + ISA_MIPS2_NOT_32R6_64R6; +def TLTI : MMRel, TEQI_FT<"tlti", GPR32Opnd>, TEQI_FM<0xa>, + ISA_MIPS2_NOT_32R6_64R6; +def TTLTIU : MMRel, TEQI_FT<"tltiu", GPR32Opnd>, TEQI_FM<0xb>, + ISA_MIPS2_NOT_32R6_64R6; +def TNEI : MMRel, TEQI_FT<"tnei", GPR32Opnd>, TEQI_FM<0xe>, + ISA_MIPS2_NOT_32R6_64R6; -def BREAK : BRK_FT<"break">, BRK_FM<0xd>; -def SYSCALL : SYS_FT<"syscall">, SYS_FM<0xc>; +def BREAK : MMRel, BRK_FT<"break">, BRK_FM<0xd>; +def SYSCALL : MMRel, SYS_FT<"syscall">, SYS_FM<0xc>; def TRAP : TrapBase<BREAK>; +def SDBBP : SYS_FT<"sdbbp">, SDBBP_FM, ISA_MIPS32_NOT_32R6_64R6; -def ERET : ER_FT<"eret">, ER_FM<0x18>; -def DERET : ER_FT<"deret">, ER_FM<0x1f>; +def ERET : MMRel, ER_FT<"eret">, ER_FM<0x18>, INSN_MIPS3_32; +def DERET : MMRel, ER_FT<"deret">, ER_FM<0x1f>, ISA_MIPS32; -def EI : DEI_FT<"ei", GPR32Opnd>, EI_FM<1>; -def DI : DEI_FT<"di", GPR32Opnd>, EI_FM<0>; +def EI : MMRel, DEI_FT<"ei", GPR32Opnd>, EI_FM<1>, ISA_MIPS32R2; +def DI : MMRel, DEI_FT<"di", GPR32Opnd>, EI_FM<0>, ISA_MIPS32R2; -def WAIT : WAIT_FT<"wait">; +let EncodingPredicates = []<Predicate>, // FIXME: Lack of HasStdEnc is probably a bug + AdditionalPredicates = [NotInMicroMips] in { +def WAIT : WAIT_FT<"wait">, WAIT_FM; /// Load-linked, Store-conditional -def LL : LLBase<"ll", GPR32Opnd>, LW_FM<0x30>; -def SC : SCBase<"sc", GPR32Opnd>, LW_FM<0x38>; +def LL : LLBase<"ll", GPR32Opnd>, LW_FM<0x30>, ISA_MIPS2_NOT_32R6_64R6; +def SC : SCBase<"sc", GPR32Opnd>, LW_FM<0x38>, ISA_MIPS2_NOT_32R6_64R6; +} /// Jump and Branch Instructions def J : MMRel, JumpFJ<jmptarget, "j", br, bb, "j">, FJ<2>, - Requires<[RelocStatic, HasStdEnc]>, IsBranch; + AdditionalRequires<[RelocStatic]>, 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>; @@ -1013,17 +1205,50 @@ def BLTZ : MMRel, CBranchZero<"bltz", brtarget, setlt, GPR32Opnd>, 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>; +let AdditionalPredicates = [NotInMicroMips] in { + def JALR : JumpLinkReg<"jalr", GPR32Opnd>, JALR_FM; + def JALRPseudo : JumpLinkRegPseudo<GPR32Opnd, JALR, RA>; +} + +// FIXME: JALX really requires either MIPS16 or microMIPS in addition to MIPS32. +def JALX : JumpLink<"jalx", calltarget>, FJ<0x1D>, ISA_MIPS32_NOT_32R6_64R6; +def BGEZAL : MMRel, BGEZAL_FT<"bgezal", brtarget, GPR32Opnd>, BGEZAL_FM<0x11>, + ISA_MIPS1_NOT_32R6_64R6; +def BLTZAL : MMRel, BGEZAL_FT<"bltzal", brtarget, GPR32Opnd>, BGEZAL_FM<0x10>, + ISA_MIPS1_NOT_32R6_64R6; 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 TAILCALL : TailCall<J>; +def TAILCALL_R : TailCallReg<GPR32Opnd, JR>; + +// Indirect branches are matched as PseudoIndirectBranch/PseudoIndirectBranch64 +// then are expanded to JR, JR64, JALR, or JALR64 depending on the ISA. +class PseudoIndirectBranchBase<RegisterOperand RO> : + MipsPseudo<(outs), (ins RO:$rs), [(brind RO:$rs)], IIBranch> { + let isTerminator=1; + let isBarrier=1; + let hasDelaySlot = 1; + let isBranch = 1; + let isIndirectBranch = 1; +} + +def PseudoIndirectBranch : PseudoIndirectBranchBase<GPR32Opnd>; + +// Return instructions are matched as a RetRA instruction, then ar expanded +// into PseudoReturn/PseudoReturn64 after register allocation. Finally, +// MipsAsmPrinter expands this into JR, JR64, JALR, or JALR64 depending on the +// ISA. +class PseudoReturnBase<RegisterOperand RO> : MipsPseudo<(outs), (ins RO:$rs), + [], IIBranch> { + let isTerminator = 1; + let isBarrier = 1; + let hasDelaySlot = 1; + let isReturn = 1; + let isCodeGenOnly = 1; + let hasCtrlDep = 1; + let hasExtraSrcRegAllocReq = 1; +} -def RET : MMRel, RetBase<"ret", GPR32Opnd>, MTLO_FM<8>; +def PseudoReturn : PseudoReturnBase<GPR32Opnd>; // Exception handling related node and instructions. // The conversion sequence is: @@ -1047,30 +1272,41 @@ let Uses = [V0, V1], isTerminator = 1, isReturn = 1, isBarrier = 1 in { } /// 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 MULT : MMRel, Mult<"mult", II_MULT, GPR32Opnd, [HI0, LO0]>, + MULT_FM<0, 0x18>, ISA_MIPS1_NOT_32R6_64R6; +def MULTu : MMRel, Mult<"multu", II_MULTU, GPR32Opnd, [HI0, LO0]>, + MULT_FM<0, 0x19>, ISA_MIPS1_NOT_32R6_64R6; +def SDIV : MMRel, Div<"div", II_DIV, GPR32Opnd, [HI0, LO0]>, + MULT_FM<0, 0x1a>, ISA_MIPS1_NOT_32R6_64R6; +def UDIV : MMRel, Div<"divu", II_DIVU, GPR32Opnd, [HI0, LO0]>, + MULT_FM<0, 0x1b>, ISA_MIPS1_NOT_32R6_64R6; -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>; +def MTHI : MMRel, MoveToLOHI<"mthi", GPR32Opnd, [HI0]>, MTLO_FM<0x11>, + ISA_MIPS1_NOT_32R6_64R6; +def MTLO : MMRel, MoveToLOHI<"mtlo", GPR32Opnd, [LO0]>, MTLO_FM<0x13>, + ISA_MIPS1_NOT_32R6_64R6; +let EncodingPredicates = []<Predicate>, // FIXME: Lack of HasStdEnc is probably a bug + AdditionalPredicates = [NotInMicroMips] in { +def MFHI : MMRel, MoveFromLOHI<"mfhi", GPR32Opnd, AC0>, MFLO_FM<0x10>, + ISA_MIPS1_NOT_32R6_64R6; +def MFLO : MMRel, MoveFromLOHI<"mflo", GPR32Opnd, AC0>, MFLO_FM<0x12>, + ISA_MIPS1_NOT_32R6_64R6; +} /// 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>; +def SEB : MMRel, SignExtInReg<"seb", i8, GPR32Opnd, II_SEB>, + SEB_FM<0x10, 0x20>, ISA_MIPS32R2; +def SEH : MMRel, SignExtInReg<"seh", i16, GPR32Opnd, II_SEH>, + SEB_FM<0x18, 0x20>, ISA_MIPS32R2; /// Count Leading -def CLZ : MMRel, CountLeading0<"clz", GPR32Opnd>, CLO_FM<0x20>; -def CLO : MMRel, CountLeading1<"clo", GPR32Opnd>, CLO_FM<0x21>; +def CLZ : MMRel, CountLeading0<"clz", GPR32Opnd>, CLO_FM<0x20>, + ISA_MIPS32_NOT_32R6_64R6; +def CLO : MMRel, CountLeading1<"clo", GPR32Opnd>, CLO_FM<0x21>, + ISA_MIPS32_NOT_32R6_64R6; /// Word Swap Bytes Within Halfwords -def WSBH : MMRel, SubwordSwap<"wsbh", GPR32Opnd>, SEB_FM<2, 0x20>; +def WSBH : MMRel, SubwordSwap<"wsbh", GPR32Opnd>, SEB_FM<2, 0x20>, ISA_MIPS32R2; /// No operation. def NOP : PseudoSE<(outs), (ins), []>, PseudoInstExpansion<(SLL ZERO, ZERO, 0)>; @@ -1079,30 +1315,40 @@ def NOP : PseudoSE<(outs), (ins), []>, PseudoInstExpansion<(SLL ZERO, ZERO, 0)>; // 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>; +def LEA_ADDiu : MMRel, 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>; +def MADD : MMRel, MArithR<"madd", II_MADD, 1>, MULT_FM<0x1c, 0>, + ISA_MIPS32_NOT_32R6_64R6; +def MADDU : MMRel, MArithR<"maddu", II_MADDU, 1>, MULT_FM<0x1c, 1>, + ISA_MIPS32_NOT_32R6_64R6; +def MSUB : MMRel, MArithR<"msub", II_MSUB>, MULT_FM<0x1c, 4>, + ISA_MIPS32_NOT_32R6_64R6; +def MSUBU : MMRel, MArithR<"msubu", II_MSUBU>, MULT_FM<0x1c, 5>, + ISA_MIPS32_NOT_32R6_64R6; -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>; +let AdditionalPredicates = [NotDSP] in { +def PseudoMULT : MultDivPseudo<MULT, ACC64, GPR32Opnd, MipsMult, II_MULT>, + ISA_MIPS1_NOT_32R6_64R6; +def PseudoMULTu : MultDivPseudo<MULTu, ACC64, GPR32Opnd, MipsMultu, II_MULTU>, + ISA_MIPS1_NOT_32R6_64R6; +def PseudoMFHI : PseudoMFLOHI<GPR32, ACC64, MipsMFHI>, ISA_MIPS1_NOT_32R6_64R6; +def PseudoMFLO : PseudoMFLOHI<GPR32, ACC64, MipsMFLO>, ISA_MIPS1_NOT_32R6_64R6; +def PseudoMTLOHI : PseudoMTLOHI<ACC64, GPR32>, ISA_MIPS1_NOT_32R6_64R6; +def PseudoMADD : MAddSubPseudo<MADD, MipsMAdd, II_MADD>, + ISA_MIPS32_NOT_32R6_64R6; +def PseudoMADDU : MAddSubPseudo<MADDU, MipsMAddu, II_MADDU>, + ISA_MIPS32_NOT_32R6_64R6; +def PseudoMSUB : MAddSubPseudo<MSUB, MipsMSub, II_MSUB>, + ISA_MIPS32_NOT_32R6_64R6; +def PseudoMSUBU : MAddSubPseudo<MSUBU, MipsMSubu, II_MSUBU>, + ISA_MIPS32_NOT_32R6_64R6; } -def PseudoSDIV : MultDivPseudo<SDIV, ACC64, GPR32Opnd, MipsDivRem, IIIdiv, - 0, 1, 1>; -def PseudoUDIV : MultDivPseudo<UDIV, ACC64, GPR32Opnd, MipsDivRemU, IIIdiv, - 0, 1, 1>; +def PseudoSDIV : MultDivPseudo<SDIV, ACC64, GPR32Opnd, MipsDivRem, II_DIV, + 0, 1, 1>, ISA_MIPS1_NOT_32R6_64R6; +def PseudoUDIV : MultDivPseudo<UDIV, ACC64, GPR32Opnd, MipsDivRemU, II_DIVU, + 0, 1, 1>, ISA_MIPS1_NOT_32R6_64R6; def RDHWR : ReadHardware<GPR32Opnd, HWRegsOpnd>, RDHWR_FM; @@ -1110,68 +1356,161 @@ 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 MFC0 : MFC3OP<"mfc0", GPR32Opnd>, MFC3OP_FM<0x10, 0>, ISA_MIPS32; +def MTC0 : MFC3OP<"mtc0", GPR32Opnd>, MFC3OP_FM<0x10, 4>, ISA_MIPS32; def MFC2 : MFC3OP<"mfc2", GPR32Opnd>, MFC3OP_FM<0x12, 0>; def MTC2 : MFC3OP<"mtc2", GPR32Opnd>, MFC3OP_FM<0x12, 4>; +class Barrier<string asmstr> : InstSE<(outs), (ins), asmstr, [], NoItinerary, + FrmOther>; +def SSNOP : Barrier<"ssnop">, BARRIER_FM<1>; +def EHB : Barrier<"ehb">, BARRIER_FM<3>; +def PAUSE : Barrier<"pause">, BARRIER_FM<5>, ISA_MIPS32R2; + +// JR_HB and JALR_HB are defined here using the new style naming +// scheme because some of this code is shared with Mips32r6InstrInfo.td +// and because of that it doesn't follow the naming convention of the +// rest of the file. To avoid a mixture of old vs new style, the new +// style was chosen. +class JR_HB_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs); + dag InOperandList = (ins GPROpnd:$rs); + string AsmString = !strconcat(instr_asm, "\t$rs"); + list<dag> Pattern = []; +} + +class JALR_HB_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs"); + list<dag> Pattern = []; +} + +class JR_HB_DESC : InstSE<(outs), (ins), "", [], NoItinerary, FrmJ>, + JR_HB_DESC_BASE<"jr.hb", GPR32Opnd> { + let isBranch=1; + let isIndirectBranch=1; + let hasDelaySlot=1; + let isTerminator=1; + let isBarrier=1; +} + +class JALR_HB_DESC : InstSE<(outs), (ins), "", [], NoItinerary, FrmJ>, + JALR_HB_DESC_BASE<"jalr.hb", GPR32Opnd> { + let isIndirectBranch=1; + let hasDelaySlot=1; +} + +class JR_HB_ENC : JR_HB_FM<8>; +class JALR_HB_ENC : JALR_HB_FM<9>; + +def JR_HB : JR_HB_DESC, JR_HB_ENC, ISA_MIPS32_NOT_32R6_64R6; +def JALR_HB : JALR_HB_DESC, JALR_HB_ENC, ISA_MIPS32; + +class TLB<string asmstr> : InstSE<(outs), (ins), asmstr, [], NoItinerary, + FrmOther>; +def TLBP : TLB<"tlbp">, COP0_TLB_FM<0x08>; +def TLBR : TLB<"tlbr">, COP0_TLB_FM<0x01>; +def TLBWI : TLB<"tlbwi">, COP0_TLB_FM<0x02>; +def TLBWR : TLB<"tlbwr">, COP0_TLB_FM<0x06>; + +class CacheOp<string instr_asm, Operand MemOpnd, RegisterOperand GPROpnd> : + InstSE<(outs), (ins MemOpnd:$addr, uimm5:$hint), + !strconcat(instr_asm, "\t$hint, $addr"), [], NoItinerary, FrmOther>; + +def CACHE : CacheOp<"cache", mem, GPR32Opnd>, CACHEOP_FM<0b101111>, + INSN_MIPS3_32_NOT_32R6_64R6; +def PREF : CacheOp<"pref", mem, GPR32Opnd>, CACHEOP_FM<0b110011>, + INSN_MIPS3_32_NOT_32R6_64R6; + //===----------------------------------------------------------------------===// // 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)>; +def : MipsInstAlias<"move $dst, $src", + (ADDu GPR32Opnd:$dst, GPR32Opnd:$src,ZERO), 1>, + GPR_32 { + let AdditionalPredicates = [NotInMicroMips]; +} +def : MipsInstAlias<"bal $offset", (BGEZAL ZERO, brtarget:$offset), 0>, + ISA_MIPS1_NOT_32R6_64R6; +def : MipsInstAlias<"addu $rs, $rt, $imm", + (ADDiu GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), 0>; +def : MipsInstAlias<"add $rs, $rt, $imm", + (ADDi GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), 0>; +def : MipsInstAlias<"and $rs, $rt, $imm", + (ANDi GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), 0>; +def : MipsInstAlias<"and $rs, $imm", + (ANDi GPR32Opnd:$rs, GPR32Opnd:$rs, simm16:$imm), 0>; +def : MipsInstAlias<"j $rs", (JR GPR32Opnd:$rs), 0>; +let Predicates = [NotInMicroMips] in { +def : MipsInstAlias<"jalr $rs", (JALR RA, GPR32Opnd:$rs), 0>; +} +def : MipsInstAlias<"jal $rs", (JALR RA, GPR32Opnd:$rs), 0>; +def : MipsInstAlias<"jal $rd,$rs", (JALR GPR32Opnd:$rd, GPR32Opnd:$rs), 0>; +def : MipsInstAlias<"jalr.hb $rs", (JALR_HB RA, GPR32Opnd:$rs), 1>, ISA_MIPS32; +def : MipsInstAlias<"not $rt, $rs", + (NOR GPR32Opnd:$rt, GPR32Opnd:$rs, ZERO), 0>; +def : MipsInstAlias<"neg $rt, $rs", + (SUB GPR32Opnd:$rt, ZERO, GPR32Opnd:$rs), 1>; +def : MipsInstAlias<"negu $rt", + (SUBu GPR32Opnd:$rt, ZERO, GPR32Opnd:$rt), 0>; +def : MipsInstAlias<"negu $rt, $rs", + (SUBu GPR32Opnd:$rt, ZERO, GPR32Opnd:$rs), 1>; +def : MipsInstAlias<"slt $rs, $rt, $imm", + (SLTi GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), 0>; +def : MipsInstAlias<"sltu $rt, $rs, $imm", + (SLTiu GPR32Opnd:$rt, GPR32Opnd:$rs, simm16:$imm), 0>; +def : MipsInstAlias<"xor $rs, $rt, $imm", + (XORi GPR32Opnd:$rs, GPR32Opnd:$rt, uimm16:$imm), 0>; +def : MipsInstAlias<"or $rs, $rt, $imm", + (ORi GPR32Opnd:$rs, GPR32Opnd:$rt, uimm16:$imm), 0>; +def : MipsInstAlias<"or $rs, $imm", + (ORi GPR32Opnd:$rs, GPR32Opnd:$rs, uimm16:$imm), 0>; +def : MipsInstAlias<"nop", (SLL ZERO, ZERO, 0), 1>; +def : MipsInstAlias<"mfc0 $rt, $rd", (MFC0 GPR32Opnd:$rt, GPR32Opnd:$rd, 0), 0>; +def : MipsInstAlias<"mtc0 $rt, $rd", (MTC0 GPR32Opnd:$rt, GPR32Opnd:$rd, 0), 0>; +def : MipsInstAlias<"mfc2 $rt, $rd", (MFC2 GPR32Opnd:$rt, GPR32Opnd:$rd, 0), 0>; +def : MipsInstAlias<"mtc2 $rt, $rd", (MTC2 GPR32Opnd:$rt, GPR32Opnd:$rd, 0), 0>; +def : MipsInstAlias<"b $offset", (BEQ ZERO, ZERO, brtarget:$offset), 0>; +def : MipsInstAlias<"bnez $rs,$offset", + (BNE GPR32Opnd:$rs, ZERO, brtarget:$offset), 0>; +def : MipsInstAlias<"beqz $rs,$offset", + (BEQ GPR32Opnd:$rs, ZERO, brtarget:$offset), 0>; +def : MipsInstAlias<"syscall", (SYSCALL 0), 1>; + +def : MipsInstAlias<"break", (BREAK 0, 0), 1>; +def : MipsInstAlias<"break $imm", (BREAK uimm10:$imm, 0), 1>; +def : MipsInstAlias<"ei", (EI ZERO), 1>; +def : MipsInstAlias<"di", (DI ZERO), 1>; +def : MipsInstAlias<"teq $rs, $rt", (TEQ GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>; +def : MipsInstAlias<"tge $rs, $rt", (TGE GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>; +def : MipsInstAlias<"tgeu $rs, $rt", (TGEU GPR32Opnd:$rs, GPR32Opnd:$rt, 0), + 1>; +def : MipsInstAlias<"tlt $rs, $rt", (TLT GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>; +def : MipsInstAlias<"tltu $rs, $rt", (TLTU GPR32Opnd:$rs, GPR32Opnd:$rt, 0), + 1>; +def : MipsInstAlias<"tne $rs, $rt", (TNE GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>; +def : MipsInstAlias<"sll $rd, $rt, $rs", + (SLLV GPR32Opnd:$rd, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>; +def : MipsInstAlias<"sub, $rd, $rs, $imm", + (ADDi GPR32Opnd:$rd, GPR32Opnd:$rs, + InvertedImOperand:$imm), 0>; +def : MipsInstAlias<"sub $rs, $imm", + (ADDi GPR32Opnd:$rs, GPR32Opnd:$rs, InvertedImOperand:$imm), + 0>; +def : MipsInstAlias<"subu, $rd, $rs, $imm", + (ADDiu GPR32Opnd:$rd, GPR32Opnd:$rs, + InvertedImOperand:$imm), 0>; +def : MipsInstAlias<"subu $rs, $imm", (ADDiu GPR32Opnd:$rs, GPR32Opnd:$rs, + InvertedImOperand:$imm), 0>; +def : MipsInstAlias<"sra $rd, $rt, $rs", + (SRAV GPR32Opnd:$rd, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>; +def : MipsInstAlias<"srl $rd, $rt, $rs", + (SRLV GPR32Opnd:$rd, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>; +def : MipsInstAlias<"sdbbp", (SDBBP 0)>, ISA_MIPS32_NOT_32R6_64R6; +def : MipsInstAlias<"sync", + (SYNC 0), 1>, ISA_MIPS2; //===----------------------------------------------------------------------===// // Assembler Pseudo Instructions //===----------------------------------------------------------------------===// @@ -1217,13 +1556,17 @@ def : MipsPat<(i32 imm:$imm), // Carry MipsPatterns def : MipsPat<(subc GPR32:$lhs, GPR32:$rhs), (SUBu GPR32:$lhs, GPR32:$rhs)>; -let Predicates = [HasStdEnc, NotDSP] in { +let AdditionalPredicates = [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)>; } +// SYNC +def : MipsPat<(MipsSync (i32 immz)), + (SYNC 0)>, ISA_MIPS2; + // Call def : MipsPat<(MipsJmpLink (i32 tglobaladdr:$dst)), (JAL tglobaladdr:$dst)>; @@ -1286,14 +1629,11 @@ 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)>; -} +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 @@ -1387,11 +1727,9 @@ 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>; - } + def : LoadRegImmPat<LBu, i32, zextloadi8>; + def : LoadRegImmPat<LH, i32, sextloadi16>; + def : LoadRegImmPat<LW, i32, load>; } //===----------------------------------------------------------------------===// @@ -1402,6 +1740,9 @@ include "MipsInstrFPU.td" include "Mips64InstrInfo.td" include "MipsCondMov.td" +include "Mips32r6InstrInfo.td" +include "Mips64r6InstrInfo.td" + // // Mips16 @@ -1419,3 +1760,4 @@ include "MipsMSAInstrInfo.td" // Micromips include "MicroMipsInstrFormats.td" include "MicroMipsInstrInfo.td" +include "MicroMipsInstrFPU.td" diff --git a/lib/Target/Mips/MipsJITInfo.cpp b/lib/Target/Mips/MipsJITInfo.cpp index d76cb1da2ddc..2072488206aa 100644 --- a/lib/Target/Mips/MipsJITInfo.cpp +++ b/lib/Target/Mips/MipsJITInfo.cpp @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "jit" #include "MipsJITInfo.h" #include "MipsInstrInfo.h" #include "MipsRelocations.h" @@ -25,6 +24,8 @@ #include <cstdlib> using namespace llvm; +#define DEBUG_TYPE "jit" + void MipsJITInfo::replaceMachineCodeForFunction(void *Old, void *New) { unsigned NewAddr = (intptr_t)New; diff --git a/lib/Target/Mips/MipsJITInfo.h b/lib/Target/Mips/MipsJITInfo.h index ecda3101a003..c9dfd831d2df 100644 --- a/lib/Target/Mips/MipsJITInfo.h +++ b/lib/Target/Mips/MipsJITInfo.h @@ -37,26 +37,26 @@ class MipsJITInfo : public TargetJITInfo { /// overwriting OLD with a branch to NEW. This is used for self-modifying /// code. /// - virtual void replaceMachineCodeForFunction(void *Old, void *New); + void replaceMachineCodeForFunction(void *Old, void *New) override; // getStubLayout - Returns the size and alignment of the largest call stub // on Mips. - virtual StubLayout getStubLayout(); + StubLayout getStubLayout() override; /// 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); + void *emitFunctionStub(const Function *F, void *Fn, + JITCodeEmitter &JCE) override; /// getLazyResolverFunction - Expose the lazy resolver to the JIT. - virtual LazyResolverFn getLazyResolverFunction(JITCompilerFn); + LazyResolverFn getLazyResolverFunction(JITCompilerFn) override; /// 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); + void relocate(void *Function, MachineRelocation *MR, + unsigned NumRelocs, unsigned char *GOTBase) override; /// Initialize - Initialize internal stage for the function being JITted. void Initialize(const MachineFunction &MF, bool isPIC, diff --git a/lib/Target/Mips/MipsLongBranch.cpp b/lib/Target/Mips/MipsLongBranch.cpp index 2efe57847add..27110b6e870e 100644 --- a/lib/Target/Mips/MipsLongBranch.cpp +++ b/lib/Target/Mips/MipsLongBranch.cpp @@ -10,16 +10,12 @@ // 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. +// FIXME: Fix pc-region jump instructions which cross 256MB segment boundaries. //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "mips-long-branch" - #include "Mips.h" #include "MCTargetDesc/MipsBaseInfo.h" +#include "MCTargetDesc/MipsMCNaCl.h" #include "MipsTargetMachine.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/MachineFunctionPass.h" @@ -33,6 +29,8 @@ using namespace llvm; +#define DEBUG_TYPE "mips-long-branch" + STATISTIC(LongBranches, "Number of long branches."); static cl::opt<bool> SkipLongBranch( @@ -56,7 +54,7 @@ namespace { bool HasLongBranch; MachineInstr *Br; - MBBInfo() : Size(0), HasLongBranch(false), Br(0) {} + MBBInfo() : Size(0), HasLongBranch(false), Br(nullptr) {} }; class MipsLongBranch : public MachineFunctionPass { @@ -67,13 +65,14 @@ namespace { : MachineFunctionPass(ID), TM(tm), IsPIC(TM.getRelocationModel() == Reloc::PIC_), ABI(TM.getSubtarget<MipsSubtarget>().getTargetABI()), - LongBranchSeqSize(!IsPIC ? 2 : (ABI == MipsSubtarget::N64 ? 13 : 9)) {} + LongBranchSeqSize(!IsPIC ? 2 : (ABI == MipsSubtarget::N64 ? 10 : + (!TM.getSubtarget<MipsSubtarget>().isTargetNaCl() ? 9 : 10))) {} - virtual const char *getPassName() const { + const char *getPassName() const override { return "Mips Long Branch"; } - bool runOnMachineFunction(MachineFunction &F); + bool runOnMachineFunction(MachineFunction &F) override; private: void splitMBB(MachineBasicBlock *MBB); @@ -111,7 +110,7 @@ static MachineBasicBlock *getTargetMBB(const MachineInstr &Br) { } assert(false && "This instruction does not have an MBB operand."); - return 0; + return nullptr; } // Traverse the list of instructions backwards until a non-debug instruction is @@ -134,7 +133,7 @@ void MipsLongBranch::splitMBB(MachineBasicBlock *MBB) { (!LastBr->isConditionalBranch() && !LastBr->isUnconditionalBranch())) return; - ReverseIter FirstBr = getNonDebugInstr(llvm::next(LastBr), End); + ReverseIter FirstBr = getNonDebugInstr(std::next(LastBr), End); // MBB has only one branch instruction if FirstBr is not a branch // instruction. @@ -154,7 +153,7 @@ void MipsLongBranch::splitMBB(MachineBasicBlock *MBB) { NewMBB->removeSuccessor(Tgt); MBB->addSuccessor(NewMBB); MBB->addSuccessor(Tgt); - MF->insert(llvm::next(MachineFunction::iterator(MBB)), NewMBB); + MF->insert(std::next(MachineFunction::iterator(MBB)), NewMBB); NewMBB->splice(NewMBB->end(), MBB, (++LastBr).base(), MBB->end()); } @@ -267,20 +266,21 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) { 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); + // We must select between the MIPS32r6/MIPS64r6 BAL (which is a normal + // instruction) and the pre-MIPS32r6/MIPS64r6 definition (which is an + // pseudo-instruction wrapping BGEZAL). + + const MipsSubtarget &Subtarget = TM.getSubtarget<MipsSubtarget>(); + unsigned BalOp = Subtarget.hasMips32r6() ? Mips::BAL : Mips::BAL_BR; if (ABI != MipsSubtarget::N64) { // $longbr: // addiu $sp, $sp, -8 // sw $ra, 0($sp) - // bal $baltgt // lui $at, %hi($tgt - $baltgt) - // $baltgt: + // bal $baltgt // addiu $at, $at, %lo($tgt - $baltgt) + // $baltgt: // addu $at, $ra, $at // lw $ra, 0($sp) // jr $at @@ -295,35 +295,64 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) { BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::SW)).addReg(Mips::RA) .addReg(Mips::SP).addImm(0); + // LUi and ADDiu instructions create 32-bit offset of the target basic + // block from the target of BAL instruction. We cannot use immediate + // value for this offset because it cannot be determined accurately when + // the program has inline assembly statements. We therefore use the + // relocation expressions %hi($tgt-$baltgt) and %lo($tgt-$baltgt) which + // are resolved during the fixup, so the values will always be correct. + // + // Since we cannot create %hi($tgt-$baltgt) and %lo($tgt-$baltgt) + // expressions at this point (it is possible only at the MC layer), + // we replace LUi and ADDiu with pseudo instructions + // LONG_BRANCH_LUi and LONG_BRANCH_ADDiu, and add both basic + // blocks as operands to these instructions. When lowering these pseudo + // instructions to LUi and ADDiu in the MC layer, we will create + // %hi($tgt-$baltgt) and %lo($tgt-$baltgt) expressions and add them as + // operands to lowered instructions. + + BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_LUi), Mips::AT) + .addMBB(TgtMBB).addMBB(BalTgtMBB); 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)); + .append(BuildMI(*MF, DL, TII->get(BalOp)).addMBB(BalTgtMBB)) + .append(BuildMI(*MF, DL, TII->get(Mips::LONG_BRANCH_ADDiu), Mips::AT) + .addReg(Mips::AT) + .addMBB(TgtMBB) + .addMBB(BalTgtMBB)); 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)); + if (!TM.getSubtarget<MipsSubtarget>().isTargetNaCl()) { + 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 { + // In NaCl, modifying the sp is not allowed in branch delay slot. + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::SP) + .addReg(Mips::SP).addImm(8); + + MIBundleBuilder(*BalTgtMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(Mips::JR)).addReg(Mips::AT)) + .append(BuildMI(*MF, DL, TII->get(Mips::NOP))); + + // Bundle-align the target of indirect branch JR. + TgtMBB->setAlignment(MIPS_NACL_BUNDLE_ALIGN); + } } else { // $longbr: // daddiu $sp, $sp, -16 // sd $ra, 0($sp) - // lui64 $at, %highest($tgt - $baltgt) - // daddiu $at, $at, %higher($tgt - $baltgt) + // daddiu $at, $zero, %hi($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) + // $baltgt: // daddu $at, $ra, $at // ld $ra, 0($sp) // jr64 $at @@ -331,9 +360,20 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) { // $fallthrough: // - int64_t Higher = SignExtend64<16>(((Offset + 0x80008000) >> 32) & 0xffff); - int64_t Highest = - SignExtend64<16>(((Offset + 0x800080008000LL) >> 48) & 0xffff); + // We assume the branch is within-function, and that offset is within + // +/- 2GB. High 32 bits will therefore always be zero. + + // Note that this will work even if the offset is negative, because + // of the +1 modification that's added in that case. For example, if the + // offset is -1MB (0xFFFFFFFFFFF00000), the computation for %higher is + // + // 0xFFFFFFFFFFF00000 + 0x80008000 = 0x000000007FF08000 + // + // and the bits [47:32] are zero. For %highest + // + // 0xFFFFFFFFFFF00000 + 0x800080008000 = 0x000080007FF08000 + // + // and the bits [63:48] are zero. Pos = LongBrMBB->begin(); @@ -341,24 +381,22 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) { .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::LONG_BRANCH_DADDiu), + Mips::AT_64).addReg(Mips::ZERO_64) + .addMBB(TgtMBB, MipsII::MO_ABS_HI).addMBB(BalTgtMBB); 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)); + .append(BuildMI(*MF, DL, TII->get(BalOp)).addMBB(BalTgtMBB)) + .append( + BuildMI(*MF, DL, TII->get(Mips::LONG_BRANCH_DADDiu), Mips::AT_64) + .addReg(Mips::AT_64) + .addMBB(TgtMBB, MipsII::MO_ABS_LO) + .addMBB(BalTgtMBB)); 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) @@ -370,8 +408,7 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) { .addReg(Mips::SP_64).addImm(16)); } - assert(BalTgtMBBSize == BalTgtMBB->size()); - assert(LongBrMBB->size() + BalTgtMBBSize == LongBranchSeqSize); + assert(LongBrMBB->size() + BalTgtMBB->size() == LongBranchSeqSize); } else { // $longbr: // j $tgt @@ -412,7 +449,8 @@ bool MipsLongBranch::runOnMachineFunction(MachineFunction &F) { const MipsInstrInfo *TII = static_cast<const MipsInstrInfo*>(TM.getInstrInfo()); - if (TM.getSubtarget<MipsSubtarget>().inMips16Mode()) + const MipsSubtarget &STI = TM.getSubtarget<MipsSubtarget>(); + if (STI.inMips16Mode() || !STI.enableLongBranchPass()) return false; if ((TM.getRelocationModel() == Reloc::PIC_) && TM.getSubtarget<MipsSubtarget>().isABI_O32() && @@ -438,9 +476,18 @@ bool MipsLongBranch::runOnMachineFunction(MachineFunction &F) { continue; int ShVal = TM.getSubtarget<MipsSubtarget>().inMicroMipsMode() ? 2 : 4; + int64_t Offset = computeOffset(I->Br) / ShVal; + + if (TM.getSubtarget<MipsSubtarget>().isTargetNaCl()) { + // The offset calculation does not include sandboxing instructions + // that will be added later in the MC layer. Since at this point we + // don't know the exact amount of code that "sandboxing" will add, we + // conservatively estimate that code will not grow more than 100%. + Offset *= 2; + } // Check if offset fits into 16-bit immediate field of branches. - if (!ForceLongBranch && isInt<16>(computeOffset(I->Br) / ShVal)) + if (!ForceLongBranch && isInt<16>(Offset)) continue; I->HasLongBranch = true; diff --git a/lib/Target/Mips/MipsMCInstLower.cpp b/lib/Target/Mips/MipsMCInstLower.cpp index b6dfadce14e9..821392e1d45f 100644 --- a/lib/Target/Mips/MipsMCInstLower.cpp +++ b/lib/Target/Mips/MipsMCInstLower.cpp @@ -18,10 +18,10 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineOperand.h" +#include "llvm/IR/Mangler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" -#include "llvm/Target/Mangler.h" using namespace llvm; @@ -151,7 +151,75 @@ MCOperand MipsMCInstLower::LowerOperand(const MachineOperand &MO, return MCOperand(); } +MCOperand MipsMCInstLower::createSub(MachineBasicBlock *BB1, + MachineBasicBlock *BB2, + MCSymbolRefExpr::VariantKind Kind) const { + const MCSymbolRefExpr *Sym1 = MCSymbolRefExpr::Create(BB1->getSymbol(), *Ctx); + const MCSymbolRefExpr *Sym2 = MCSymbolRefExpr::Create(BB2->getSymbol(), *Ctx); + const MCBinaryExpr *Sub = MCBinaryExpr::CreateSub(Sym1, Sym2, *Ctx); + + return MCOperand::CreateExpr(MipsMCExpr::Create(Kind, Sub, *Ctx)); +} + +void MipsMCInstLower:: +lowerLongBranchLUi(const MachineInstr *MI, MCInst &OutMI) const { + OutMI.setOpcode(Mips::LUi); + + // Lower register operand. + OutMI.addOperand(LowerOperand(MI->getOperand(0))); + + // Create %hi($tgt-$baltgt). + OutMI.addOperand(createSub(MI->getOperand(1).getMBB(), + MI->getOperand(2).getMBB(), + MCSymbolRefExpr::VK_Mips_ABS_HI)); +} + +void MipsMCInstLower:: +lowerLongBranchADDiu(const MachineInstr *MI, MCInst &OutMI, int Opcode, + MCSymbolRefExpr::VariantKind Kind) const { + OutMI.setOpcode(Opcode); + + // Lower two register operands. + for (unsigned I = 0, E = 2; I != E; ++I) { + const MachineOperand &MO = MI->getOperand(I); + OutMI.addOperand(LowerOperand(MO)); + } + + // Create %lo($tgt-$baltgt) or %hi($tgt-$baltgt). + OutMI.addOperand(createSub(MI->getOperand(2).getMBB(), + MI->getOperand(3).getMBB(), Kind)); +} + +bool MipsMCInstLower::lowerLongBranch(const MachineInstr *MI, + MCInst &OutMI) const { + switch (MI->getOpcode()) { + default: + return false; + case Mips::LONG_BRANCH_LUi: + lowerLongBranchLUi(MI, OutMI); + return true; + case Mips::LONG_BRANCH_ADDiu: + lowerLongBranchADDiu(MI, OutMI, Mips::ADDiu, + MCSymbolRefExpr::VK_Mips_ABS_LO); + return true; + case Mips::LONG_BRANCH_DADDiu: + unsigned TargetFlags = MI->getOperand(2).getTargetFlags(); + if (TargetFlags == MipsII::MO_ABS_HI) + lowerLongBranchADDiu(MI, OutMI, Mips::DADDiu, + MCSymbolRefExpr::VK_Mips_ABS_HI); + else if (TargetFlags == MipsII::MO_ABS_LO) + lowerLongBranchADDiu(MI, OutMI, Mips::DADDiu, + MCSymbolRefExpr::VK_Mips_ABS_LO); + else + report_fatal_error("Unexpected flags for LONG_BRANCH_DADDiu"); + return true; + } +} + void MipsMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { + if (lowerLongBranch(MI, OutMI)) + return; + OutMI.setOpcode(MI->getOpcode()); for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { diff --git a/lib/Target/Mips/MipsMCInstLower.h b/lib/Target/Mips/MipsMCInstLower.h index 4570bd90997f..269190ffc065 100644 --- a/lib/Target/Mips/MipsMCInstLower.h +++ b/lib/Target/Mips/MipsMCInstLower.h @@ -9,6 +9,7 @@ #ifndef MIPSMCINSTLOWER_H #define MIPSMCINSTLOWER_H +#include "MCTargetDesc/MipsMCExpr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/Support/Compiler.h" @@ -36,6 +37,13 @@ public: private: MCOperand LowerSymbolOperand(const MachineOperand &MO, MachineOperandType MOTy, unsigned Offset) const; + MCOperand createSub(MachineBasicBlock *BB1, MachineBasicBlock *BB2, + MCSymbolRefExpr::VariantKind Kind) const; + void lowerLongBranchLUi(const MachineInstr *MI, MCInst &OutMI) const; + void lowerLongBranchADDiu(const MachineInstr *MI, MCInst &OutMI, + int Opcode, + MCSymbolRefExpr::VariantKind Kind) const; + bool lowerLongBranch(const MachineInstr *MI, MCInst &OutMI) const; }; } diff --git a/lib/Target/Mips/MipsMSAInstrFormats.td b/lib/Target/Mips/MipsMSAInstrFormats.td index 875dc0b4034d..bff2d0fab1ec 100644 --- a/lib/Target/Mips/MipsMSAInstrFormats.td +++ b/lib/Target/Mips/MipsMSAInstrFormats.td @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -def HasMSA : Predicate<"Subtarget.hasMSA()">, +def HasMSA : Predicate<"Subtarget->hasMSA()">, AssemblerPredicate<"FeatureMSA">; class MSAInst : MipsInst<(outs), (ins), "", [], NoItinerary, FrmOther> { @@ -15,6 +15,10 @@ class MSAInst : MipsInst<(outs), (ins), "", [], NoItinerary, FrmOther> { let Inst{31-26} = 0b011110; } +class MSA64Inst : MSAInst { + let Predicates = [HasMSA, HasMips64]; +} + class MSACBranch : MSAInst { let Inst{31-26} = 0b010001; } @@ -23,7 +27,11 @@ class MSASpecial : MSAInst { let Inst{31-26} = 0b000000; } -class PseudoMSA<dag outs, dag ins, list<dag> pattern, +class MSA64Special : MSA64Inst { + let Inst{31-26} = 0b000000; +} + +class MSAPseudo<dag outs, dag ins, list<dag> pattern, InstrItinClass itin = IIPseudo>: MipsPseudo<outs, ins, pattern, itin> { let Predicates = [HasMSA]; @@ -92,6 +100,17 @@ class MSA_2R_FILL_FMT<bits<8> major, bits<2> df, bits<6> minor>: MSAInst { let Inst{5-0} = minor; } +class MSA_2R_FILL_D_FMT<bits<8> major, bits<2> df, bits<6> minor>: MSA64Inst { + 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; @@ -274,6 +293,19 @@ class MSA_ELM_COPY_W_FMT<bits<4> major, bits<6> minor>: MSAInst { let Inst{5-0} = minor; } +class MSA_ELM_COPY_D_FMT<bits<4> major, bits<6> minor>: MSA64Inst { + bits<4> n; + bits<5> ws; + bits<5> rd; + + let Inst{25-22} = major; + let Inst{21-17} = 0b11100; + let Inst{16} = n{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; @@ -313,6 +345,19 @@ class MSA_ELM_INSERT_W_FMT<bits<4> major, bits<6> minor>: MSAInst { let Inst{5-0} = minor; } +class MSA_ELM_INSERT_D_FMT<bits<4> major, bits<6> minor>: MSA64Inst { + bits<6> n; + bits<5> rs; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-17} = 0b11100; + let Inst{16} = n{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; @@ -404,3 +449,17 @@ class SPECIAL_LSA_FMT<bits<6> minor>: MSASpecial { let Inst{7-6} = sa; let Inst{5-0} = minor; } + +class SPECIAL_DLSA_FMT<bits<6> minor>: MSA64Special { + 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/lib/Target/Mips/MipsMSAInstrInfo.td b/lib/Target/Mips/MipsMSAInstrInfo.td index 82c51a6473da..285bb146cdb6 100644 --- a/lib/Target/Mips/MipsMSAInstrInfo.td +++ b/lib/Target/Mips/MipsMSAInstrInfo.td @@ -27,6 +27,9 @@ 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 SDT_INSVE : SDTypeProfile<1, 4, [SDTCisVec<0>, SDTCisSameAs<0, 1>, + SDTCisVT<2, i32>, SDTCisSameAs<0, 3>, + SDTCisVT<4, i32>]>; def MipsVAllNonZero : SDNode<"MipsISD::VALL_NONZERO", SDT_MipsVecCond>; def MipsVAnyNonZero : SDNode<"MipsISD::VANY_NONZERO", SDT_MipsVecCond>; @@ -50,6 +53,7 @@ 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 MipsINSVE : SDNode<"MipsISD::INSVE", SDT_INSVE>; def vsetcc : SDNode<"ISD::SETCC", SDT_VSetCC>; def vfsetcc : SDNode<"ISD::SETCC", SDT_VFSetCC>; @@ -61,15 +65,11 @@ def MipsVExtractZExt : SDNode<"MipsISD::VEXTRACT_ZEXT_ELT", // 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 ParserMethod = "ParseLSAImm"; let RenderMethod = "addImmOperands"; } @@ -80,10 +80,6 @@ def LSAImm : Operand<i32> { let ParserMatchClass = uimm2LSAAsmOperand; } -def uimm3 : Operand<i32> { - let PrintMethod = "printUnsignedImm8"; -} - def uimm4 : Operand<i32> { let PrintMethod = "printUnsignedImm8"; } @@ -94,8 +90,6 @@ def uimm8 : Operand<i32> { def simm5 : Operand<i32>; -def simm10 : Operand<i32>; - def vsplat_uimm1 : Operand<vAny> { let PrintMethod = "printUnsignedImm8"; } @@ -137,6 +131,8 @@ 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_sext_i64 : PatFrag<(ops node:$vec, node:$idx), + (MipsVExtractSExt node:$vec, node:$idx, i64)>; def vextract_zext_i8 : PatFrag<(ops node:$vec, node:$idx), (MipsVExtractZExt node:$vec, node:$idx, i8)>; @@ -144,6 +140,8 @@ 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 vextract_zext_i64 : PatFrag<(ops node:$vec, node:$idx), + (MipsVExtractZExt node:$vec, node:$idx, i64)>; def vinsert_v16i8 : PatFrag<(ops node:$vec, node:$val, node:$idx), (v16i8 (vector_insert node:$vec, node:$val, node:$idx))>; @@ -151,6 +149,17 @@ 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))>; +def vinsert_v2i64 : PatFrag<(ops node:$vec, node:$val, node:$idx), + (v2i64 (vector_insert node:$vec, node:$val, node:$idx))>; + +def insve_v16i8 : PatFrag<(ops node:$v1, node:$i1, node:$v2, node:$i2), + (v16i8 (MipsINSVE node:$v1, node:$i1, node:$v2, node:$i2))>; +def insve_v8i16 : PatFrag<(ops node:$v1, node:$i1, node:$v2, node:$i2), + (v8i16 (MipsINSVE node:$v1, node:$i1, node:$v2, node:$i2))>; +def insve_v4i32 : PatFrag<(ops node:$v1, node:$i1, node:$v2, node:$i2), + (v4i32 (MipsINSVE node:$v1, node:$i1, node:$v2, node:$i2))>; +def insve_v2i64 : PatFrag<(ops node:$v1, node:$i1, node:$v2, node:$i2), + (v2i64 (MipsINSVE node:$v1, node:$i1, node:$v2, node:$i2))>; class vfsetcc_type<ValueType ResTy, ValueType OpTy, CondCode CC> : PatFrag<(ops node:$lhs, node:$rhs), @@ -232,7 +241,7 @@ 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))>; + (v2i64 (build_vector node:$e0, node:$e0))>; def vsplatf32 : PatFrag<(ops node:$e0), (v4f32 (build_vector node:$e0, node:$e0, node:$e0, node:$e0))>; @@ -614,10 +623,12 @@ 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_S_D_ENC : MSA_ELM_COPY_D_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 COPY_U_D_ENC : MSA_ELM_COPY_D_FMT<0b0011, 0b011001>; class CTCMSA_ENC : MSA_ELM_CTCMSA_FMT<0b0000111110, 0b011001>; @@ -724,6 +735,7 @@ 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 FILL_D_ENC : MSA_2R_FILL_D_FMT<0b11000000, 0b11, 0b011110>; class FLOG2_W_ENC : MSA_2RF_FMT<0b110010111, 0b0, 0b011110>; class FLOG2_D_ENC : MSA_2RF_FMT<0b110010111, 0b1, 0b011110>; @@ -851,6 +863,7 @@ 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 INSERT_D_ENC : MSA_ELM_INSERT_D_FMT<0b0100, 0b011001>; class INSVE_B_ENC : MSA_ELM_B_FMT<0b0101, 0b011001>; class INSVE_H_ENC : MSA_ELM_H_FMT<0b0101, 0b011001>; @@ -868,6 +881,7 @@ 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 DLSA_ENC : SPECIAL_DLSA_FMT<0b010101>; class MADD_Q_H_ENC : MSA_3RF_FMT<0b0101, 0b0, 0b011100>; class MADD_Q_W_ENC : MSA_3RF_FMT<0b0101, 0b1, 0b011100>; @@ -1221,8 +1235,12 @@ class MSA_BIT_BINSXI_DESC_BASE<string instr_asm, ValueType Ty, 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))]; + // Note that binsxi and vselect treat the condition operand the opposite + // way to each other. + // (vselect cond, if_set, if_clear) + // (BSEL_V cond, if_clear, if_set) + list<dag> Pattern = [(set ROWD:$wd, (vselect (Ty Mask:$m), (Ty ROWD:$ws), + ROWS:$wd_in))]; InstrItinClass Itinerary = itin; string Constraints = "$wd = $wd_in"; } @@ -1261,20 +1279,22 @@ class MSA_COPY_DESC_BASE<string instr_asm, SDPatternOperator OpNode, InstrItinClass Itinerary = itin; } -class MSA_ELM_DESC_BASE<string instr_asm, SDPatternOperator OpNode, - RegisterOperand ROWD, RegisterOperand ROWS = ROWD, - InstrItinClass itin = NoItinerary> { +class MSA_ELM_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, uimm4:$n); + dag InOperandList = (ins ROWD:$wd_in, ROWS:$ws, uimm4:$n); string AsmString = !strconcat(instr_asm, "\t$wd, $ws[$n]"); - list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, immZExt4:$n))]; + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWD:$wd_in, ROWS:$ws, + immZExt4:$n))]; + string Constraints = "$wd = $wd_in"; 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))]> { + MSAPseudo<(outs RCD:$wd), (ins RCWS:$ws, uimm4:$n), + [(set RCD:$wd, (OpNode (VecTy RCWS:$ws), immZExt4:$n))]> { bit usesCustomInserter = 1; } @@ -1300,17 +1320,6 @@ class MSA_I8_DESC_BASE<string instr_asm, SDPatternOperator OpNode, 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> { @@ -1355,8 +1364,8 @@ class MSA_2R_FILL_DESC_BASE<string instr_asm, ValueType VT, 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))]> { + MSAPseudo<(outs RCWD:$wd), (ins RCWS:$fs), + [(set RCWD:$wd, (OpNode RCWS:$fs))]> { let usesCustomInserter = 1; } @@ -1398,9 +1407,9 @@ 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); + dag InOperandList = (ins ROWS:$ws, GPR32Opnd:$rt); string AsmString = !strconcat(instr_asm, "\t$wd, $ws[$rt]"); - list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, GPR32:$rt))]; + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, GPR32Opnd:$rt))]; InstrItinClass Itinerary = itin; } @@ -1421,10 +1430,12 @@ 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); + dag InOperandList = (ins ROWD:$wd_in, ROWS:$ws, GPR32Opnd:$rt); string AsmString = !strconcat(instr_asm, "\t$wd, $ws[$rt]"); - list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, GPR32:$rt))]; + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWD:$wd_in, ROWS:$ws, + GPR32Opnd:$rt))]; InstrItinClass Itinerary = itin; + string Constraints = "$wd = $wd_in"; } class MSA_3R_4R_DESC_BASE<string instr_asm, SDPatternOperator OpNode, @@ -1434,8 +1445,8 @@ class MSA_3R_4R_DESC_BASE<string instr_asm, SDPatternOperator OpNode, 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))]; + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWD:$wd_in, ROWS:$ws, + ROWT:$wt))]; InstrItinClass Itinerary = itin; string Constraints = "$wd = $wd_in"; } @@ -1479,22 +1490,32 @@ class MSA_INSERT_DESC_BASE<string instr_asm, SDPatternOperator OpNode, 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, + MSAPseudo<(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_INSERT_VIDX_PSEUDO_BASE<SDPatternOperator OpNode, ValueType Ty, + RegisterOperand ROWD, RegisterOperand ROFS> : + MSAPseudo<(outs ROWD:$wd), (ins ROWD:$wd_in, GPR32Opnd:$n, ROFS:$fs), + [(set ROWD:$wd, (OpNode (Ty ROWD:$wd_in), ROFS:$fs, + GPR32Opnd:$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]"); + dag InOperandList = (ins ROWD:$wd_in, uimm6:$n, ROWS:$ws, uimmz:$n2); + string AsmString = !strconcat(instr_asm, "\t$wd[$n], $ws[$n2]"); list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWD:$wd_in, immZExt6:$n, - ROWS:$ws))]; + ROWS:$ws, + immz:$n2))]; InstrItinClass Itinerary = itin; string Constraints = "$wd = $wd_in"; } @@ -1525,8 +1546,8 @@ class MSA_ELM_SPLAT_DESC_BASE<string instr_asm, SplatComplexPattern SplatImm, 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))]>; + MSAPseudo<(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; @@ -1735,10 +1756,14 @@ 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 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>; @@ -1752,9 +1777,13 @@ class BSEL_V_DESC { dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws, MSA128BOpnd:$wt); string AsmString = "bsel.v\t$wd, $ws, $wt"; + // Note that vselect and BSEL_V treat the condition operand the opposite way + // from each other. + // (vselect cond, if_set, if_clear) + // (BSEL_V cond, if_clear, if_set) list<dag> Pattern = [(set MSA128BOpnd:$wd, - (vselect MSA128BOpnd:$wd_in, MSA128BOpnd:$ws, - MSA128BOpnd:$wt))]; + (vselect MSA128BOpnd:$wd_in, MSA128BOpnd:$wt, + MSA128BOpnd:$ws))]; InstrItinClass Itinerary = NoItinerary; string Constraints = "$wd = $wd_in"; } @@ -1764,9 +1793,13 @@ class BSELI_B_DESC { dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws, vsplat_uimm8:$u8); string AsmString = "bseli.b\t$wd, $ws, $u8"; + // Note that vselect and BSEL_V treat the condition operand the opposite way + // from each other. + // (vselect cond, if_set, if_clear) + // (BSEL_V cond, if_clear, if_set) list<dag> Pattern = [(set MSA128BOpnd:$wd, (vselect MSA128BOpnd:$wd_in, - MSA128BOpnd:$ws, - vsplati8_uimm8:$u8))]; + vsplati8_uimm8:$u8, + MSA128BOpnd:$ws))]; InstrItinClass Itinerary = NoItinerary; string Constraints = "$wd = $wd_in"; } @@ -1880,6 +1913,8 @@ 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_S_D_DESC : MSA_COPY_DESC_BASE<"copy_s.d", vextract_sext_i64, v2i64, + GPR64Opnd, MSA128DOpnd>; class COPY_U_B_DESC : MSA_COPY_DESC_BASE<"copy_u.b", vextract_zext_i8, v16i8, GPR32Opnd, MSA128BOpnd>; @@ -1887,6 +1922,8 @@ 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_U_D_DESC : MSA_COPY_DESC_BASE<"copy_u.d", vextract_zext_i64, v2i64, + GPR64Opnd, MSA128DOpnd>; class COPY_FW_PSEUDO_DESC : MSA_COPY_PSEUDO_BASE<vector_extract, v4f32, FGR32, MSA128W>; @@ -2047,11 +2084,11 @@ 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))]>; + MSAPseudo<(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))]>; + MSAPseudo<(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, @@ -2086,6 +2123,8 @@ 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_D_DESC : MSA_2R_FILL_DESC_BASE<"fill.d", v2i64, vsplati64, + MSA128DOpnd, GPR64Opnd>; class FILL_FW_PSEUDO_DESC : MSA_2R_FILL_PSEUDO_BASE<v4f32, vsplatf32, MSA128W, FGR32>; @@ -2259,24 +2298,40 @@ 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_D_DESC : MSA_INSERT_DESC_BASE<"insert.d", vinsert_v2i64, + MSA128DOpnd, GPR64Opnd>; + +class INSERT_B_VIDX_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v16i8, MSA128BOpnd, GPR32Opnd>; +class INSERT_H_VIDX_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v8i16, MSA128HOpnd, GPR32Opnd>; +class INSERT_W_VIDX_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v4i32, MSA128WOpnd, GPR32Opnd>; +class INSERT_D_VIDX_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v2i64, MSA128DOpnd, GPR64Opnd>; 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, +class INSERT_FW_VIDX_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v4f32, MSA128WOpnd, FGR32Opnd>; +class INSERT_FD_VIDX_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v2f64, MSA128DOpnd, FGR64Opnd>; + +class INSVE_B_DESC : MSA_INSVE_DESC_BASE<"insve.b", insve_v16i8, MSA128BOpnd>; -class INSVE_H_DESC : MSA_INSVE_DESC_BASE<"insve.h", int_mips_insve_h, +class INSVE_H_DESC : MSA_INSVE_DESC_BASE<"insve.h", insve_v8i16, MSA128HOpnd>; -class INSVE_W_DESC : MSA_INSVE_DESC_BASE<"insve.w", int_mips_insve_w, +class INSVE_W_DESC : MSA_INSVE_DESC_BASE<"insve.w", insve_v4i32, MSA128WOpnd>; -class INSVE_D_DESC : MSA_INSVE_DESC_BASE<"insve.d", int_mips_insve_d, +class INSVE_D_DESC : MSA_INSVE_DESC_BASE<"insve.d", insve_v2i64, MSA128DOpnd>; class LD_DESC_BASE<string instr_asm, SDPatternOperator OpNode, ValueType TyNode, RegisterOperand ROWD, - Operand MemOpnd = mem, ComplexPattern Addr = addrRegImm, + Operand MemOpnd = mem_msa, ComplexPattern Addr = addrimm10, InstrItinClass itin = NoItinerary> { dag OutOperandList = (outs ROWD:$wd); dag InOperandList = (ins MemOpnd:$addr); @@ -2296,16 +2351,21 @@ 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, +class LSA_DESC_BASE<string instr_asm, RegisterOperand RORD, + RegisterOperand RORS = RORD, RegisterOperand RORT = RORD, + InstrItinClass itin = NoItinerary > { + dag OutOperandList = (outs RORD:$rd); + dag InOperandList = (ins RORS:$rs, RORT:$rt, LSAImm:$sa); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt, $sa"); + list<dag> Pattern = [(set RORD:$rd, (add RORT:$rt, + (shl RORS:$rs, immZExt2Lsa:$sa)))]; - InstrItinClass Itinerary = NoItinerary; + InstrItinClass Itinerary = itin; } +class LSA_DESC : LSA_DESC_BASE<"lsa", GPR32Opnd>; +class DLSA_DESC : LSA_DESC_BASE<"dlsa", GPR64Opnd>; + 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, @@ -2502,10 +2562,14 @@ 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 SLDI_B_DESC : MSA_ELM_SLD_DESC_BASE<"sldi.b", int_mips_sldi_b, + MSA128BOpnd>; +class SLDI_H_DESC : MSA_ELM_SLD_DESC_BASE<"sldi.h", int_mips_sldi_h, + MSA128HOpnd>; +class SLDI_W_DESC : MSA_ELM_SLD_DESC_BASE<"sldi.w", int_mips_sldi_w, + MSA128WOpnd>; +class SLDI_D_DESC : MSA_ELM_SLD_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>; @@ -2597,7 +2661,7 @@ class SRLRI_D_DESC : MSA_BIT_D_X_DESC_BASE<"srlri.d", int_mips_srlri_d, class ST_DESC_BASE<string instr_asm, SDPatternOperator OpNode, ValueType TyNode, RegisterOperand ROWD, - Operand MemOpnd = mem, ComplexPattern Addr = addrRegImm, + Operand MemOpnd = mem_msa, ComplexPattern Addr = addrimm10, InstrItinClass itin = NoItinerary> { dag OutOperandList = (outs); dag InOperandList = (ins ROWD:$wd, MemOpnd:$addr); @@ -2810,8 +2874,12 @@ 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)))]>, + MSAPseudo<(outs RO:$wd), (ins RO:$wd_in, RO:$ws, RO:$wt), + [(set RO:$wd, (Ty (vselect RO:$wd_in, RO:$wt, RO:$ws)))]>, + // Note that vselect and BSEL_V treat the condition operand the opposite way + // from each other. + // (vselect cond, if_set, if_clear) + // (BSEL_V cond, if_clear, if_set) PseudoInstExpansion<(BSEL_V MSA128BOpnd:$wd, MSA128BOpnd:$wd_in, MSA128BOpnd:$ws, MSA128BOpnd:$wt)> { let Constraints = "$wd_in = $wd"; @@ -2897,10 +2965,12 @@ 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_S_D : COPY_S_D_ENC, COPY_S_D_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_U_D : COPY_U_D_ENC, COPY_U_D_DESC; def COPY_FW_PSEUDO : COPY_FW_PSEUDO_DESC; def COPY_FD_PSEUDO : COPY_FD_PSEUDO_DESC; @@ -3012,6 +3082,7 @@ 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_D : FILL_D_ENC, FILL_D_DESC; def FILL_FW_PSEUDO : FILL_FW_PSEUDO_DESC; def FILL_FD_PSEUDO : FILL_FD_PSEUDO_DESC; @@ -3141,18 +3212,30 @@ 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; +def INSERT_D : INSERT_D_ENC, INSERT_D_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; +// There is a fourth operand that is not present in the encoding. Use a +// custom decoder to get a chance to add it. +let DecoderMethod = "DecodeINSVE_DF" in { + 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 INSERT_B_VIDX_PSEUDO : INSERT_B_VIDX_PSEUDO_DESC; +def INSERT_H_VIDX_PSEUDO : INSERT_H_VIDX_PSEUDO_DESC; +def INSERT_W_VIDX_PSEUDO : INSERT_W_VIDX_PSEUDO_DESC; +def INSERT_D_VIDX_PSEUDO : INSERT_D_VIDX_PSEUDO_DESC; +def INSERT_FW_VIDX_PSEUDO : INSERT_FW_VIDX_PSEUDO_DESC; +def INSERT_FD_VIDX_PSEUDO : INSERT_FD_VIDX_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; @@ -3164,6 +3247,7 @@ 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 DLSA : DLSA_ENC, DLSA_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; @@ -3464,46 +3548,23 @@ class MSAPat<dag pattern, dag result, list<Predicate> pred = [HasMSA]> : 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 : MSAPat<(v8f16 (load addrimm10:$addr)), (LD_H addrimm10:$addr)>; +def : MSAPat<(v4f32 (load addrimm10:$addr)), (LD_W addrimm10:$addr)>; +def : MSAPat<(v2f64 (load addrimm10:$addr)), (LD_D addrimm10:$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)>; +def ST_FH : MSAPat<(store (v8f16 MSA128H:$ws), addrimm10:$addr), + (ST_H MSA128H:$ws, addrimm10:$addr)>; +def ST_FW : MSAPat<(store (v4f32 MSA128W:$ws), addrimm10:$addr), + (ST_W MSA128W:$ws, addrimm10:$addr)>; +def ST_FD : MSAPat<(store (v2f64 MSA128D:$ws), addrimm10:$addr), + (ST_D MSA128D:$ws, addrimm10:$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))]> { + MSAPseudo<(outs ROWD:$wd), + (ins ROWS:$ws), + [(set ROWD:$wd, (fabs ROWS:$ws))]> { InstrItinClass Itinerary = itin; } def FABS_W : MSA_FABS_PSEUDO_DESC_BASE<MSA128WOpnd>, @@ -3518,7 +3579,7 @@ class MSABitconvertPat<ValueType DstVT, ValueType SrcVT, MSAPat<(DstVT (bitconvert SrcVT:$src)), (COPY_TO_REGCLASS SrcVT:$src, DstRC), preds>; -// These are endian-independant because the element size doesnt change +// These are endian-independent because the element size doesnt change def : MSABitconvertPat<v8i16, v8f16, MSA128H>; def : MSABitconvertPat<v4i32, v4f32, MSA128W>; def : MSABitconvertPat<v2i64, v2f64, MSA128D>; @@ -3692,3 +3753,55 @@ 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>; + +// Vector extraction with variable index +def : MSAPat<(i32 (vextract_sext_i8 v16i8:$ws, i32:$idx)), + (SRA (COPY_TO_REGCLASS (i32 (EXTRACT_SUBREG (SPLAT_B v16i8:$ws, + i32:$idx), + sub_lo)), + GPR32), (i32 24))>; +def : MSAPat<(i32 (vextract_sext_i16 v8i16:$ws, i32:$idx)), + (SRA (COPY_TO_REGCLASS (i32 (EXTRACT_SUBREG (SPLAT_H v8i16:$ws, + i32:$idx), + sub_lo)), + GPR32), (i32 16))>; +def : MSAPat<(i32 (vextract_sext_i32 v4i32:$ws, i32:$idx)), + (COPY_TO_REGCLASS (i32 (EXTRACT_SUBREG (SPLAT_W v4i32:$ws, + i32:$idx), + sub_lo)), + GPR32)>; +def : MSAPat<(i64 (vextract_sext_i64 v2i64:$ws, i32:$idx)), + (COPY_TO_REGCLASS (i64 (EXTRACT_SUBREG (SPLAT_D v2i64:$ws, + i32:$idx), + sub_64)), + GPR64), [HasMSA, IsGP64bit]>; + +def : MSAPat<(i32 (vextract_zext_i8 v16i8:$ws, i32:$idx)), + (SRL (COPY_TO_REGCLASS (i32 (EXTRACT_SUBREG (SPLAT_B v16i8:$ws, + i32:$idx), + sub_lo)), + GPR32), (i32 24))>; +def : MSAPat<(i32 (vextract_zext_i16 v8i16:$ws, i32:$idx)), + (SRL (COPY_TO_REGCLASS (i32 (EXTRACT_SUBREG (SPLAT_H v8i16:$ws, + i32:$idx), + sub_lo)), + GPR32), (i32 16))>; +def : MSAPat<(i32 (vextract_zext_i32 v4i32:$ws, i32:$idx)), + (COPY_TO_REGCLASS (i32 (EXTRACT_SUBREG (SPLAT_W v4i32:$ws, + i32:$idx), + sub_lo)), + GPR32)>; +def : MSAPat<(i64 (vextract_zext_i64 v2i64:$ws, i32:$idx)), + (COPY_TO_REGCLASS (i64 (EXTRACT_SUBREG (SPLAT_D v2i64:$ws, + i32:$idx), + sub_64)), + GPR64), [HasMSA, IsGP64bit]>; + +def : MSAPat<(f32 (vector_extract v4f32:$ws, i32:$idx)), + (f32 (EXTRACT_SUBREG (SPLAT_W v4f32:$ws, + i32:$idx), + sub_lo))>; +def : MSAPat<(f64 (vector_extract v2f64:$ws, i32:$idx)), + (f64 (EXTRACT_SUBREG (SPLAT_D v2f64:$ws, + i32:$idx), + sub_64))>; diff --git a/lib/Target/Mips/MipsMachineFunction.cpp b/lib/Target/Mips/MipsMachineFunction.cpp index dedf802f80ac..bc896be4e1de 100644 --- a/lib/Target/Mips/MipsMachineFunction.cpp +++ b/lib/Target/Mips/MipsMachineFunction.cpp @@ -27,7 +27,7 @@ FixGlobalBaseReg("mips-fix-global-base-reg", cl::Hidden, cl::init(true), MipsCallEntry::MipsCallEntry(const StringRef &N) { #ifndef NDEBUG Name = N; - Val = 0; + Val = nullptr; #endif } @@ -65,9 +65,8 @@ MipsFunctionInfo::~MipsFunctionInfo() { ++I) delete I->getValue(); - for (ValueMap<const GlobalValue *, const MipsCallEntry *>::iterator - I = GlobalCallEntries.begin(), E = GlobalCallEntries.end(); I != E; ++I) - delete I->second; + for (const auto &Entry : GlobalCallEntries) + delete Entry.second; } bool MipsFunctionInfo::globalBaseRegSet() const { @@ -138,4 +137,12 @@ MachinePointerInfo MipsFunctionInfo::callPtrInfo(const GlobalValue *Val) { return MachinePointerInfo(E); } +int MipsFunctionInfo::getMoveF64ViaSpillFI(const TargetRegisterClass *RC) { + if (MoveF64ViaSpillFI == -1) { + MoveF64ViaSpillFI = MF.getFrameInfo()->CreateStackObject( + RC->getSize(), RC->getAlignment(), false); + } + return MoveF64ViaSpillFI; +} + void MipsFunctionInfo::anchor() { } diff --git a/lib/Target/Mips/MipsMachineFunction.h b/lib/Target/Mips/MipsMachineFunction.h index 43bf6827eefb..61260e578159 100644 --- a/lib/Target/Mips/MipsMachineFunction.h +++ b/lib/Target/Mips/MipsMachineFunction.h @@ -14,16 +14,18 @@ #ifndef MIPS_MACHINE_FUNCTION_INFO_H #define MIPS_MACHINE_FUNCTION_INFO_H -#include "MipsSubtarget.h" +#include "Mips16HardFloatInfo.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/IR/ValueMap.h" #include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetMachine.h" +#include <map> +#include <string> #include <utility> namespace llvm { @@ -34,12 +36,12 @@ 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; + bool isConstant(const MachineFrameInfo *) const override; + bool isAliased(const MachineFrameInfo *) const override; + bool mayAlias(const MachineFrameInfo *) const override; private: - virtual void printCustom(raw_ostream &O) const; + void printCustom(raw_ostream &O) const override; #ifndef NDEBUG std::string Name; const GlobalValue *Val; @@ -50,10 +52,10 @@ 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(MachineFunction &MF) + : MF(MF), SRetReturnReg(0), GlobalBaseReg(0), Mips16SPAliasReg(0), + VarArgsFrameIndex(0), CallsEhReturn(false), SaveS2(false), + MoveF64ViaSpillFI(-1) {} ~MipsFunctionInfo(); @@ -92,6 +94,14 @@ public: /// representing a GOT entry for a global function. MachinePointerInfo callPtrInfo(const GlobalValue *Val); + void setSaveS2() { SaveS2 = true; } + bool hasSaveS2() const { return SaveS2; } + + int getMoveF64ViaSpillFI(const TargetRegisterClass *RC); + + std::map<const char *, const llvm::Mips16HardFloatInfo::FuncSignature *> + StubsNeeded; + private: virtual void anchor(); @@ -126,6 +136,13 @@ private: /// Frame objects for spilling eh data registers. int EhDataRegFI[4]; + // saveS2 + bool SaveS2; + + /// FrameIndex for expanding BuildPairF64 nodes to spill and reload when the + /// O32 FPXX ABI is enabled. -1 is used to denote invalid index. + int MoveF64ViaSpillFI; + /// MipsCallEntry maps. StringMap<const MipsCallEntry *> ExternalCallEntries; ValueMap<const GlobalValue *, const MipsCallEntry *> GlobalCallEntries; diff --git a/lib/Target/Mips/MipsModuleISelDAGToDAG.cpp b/lib/Target/Mips/MipsModuleISelDAGToDAG.cpp index c6abf17df353..b011e8fcd8b7 100644 --- a/lib/Target/Mips/MipsModuleISelDAGToDAG.cpp +++ b/lib/Target/Mips/MipsModuleISelDAGToDAG.cpp @@ -14,11 +14,13 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#define DEBUG_TYPE "mips-isel" + namespace llvm { bool MipsModuleDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { DEBUG(errs() << "In MipsModuleDAGToDAGISel::runMachineFunction\n"); - const_cast<MipsSubtarget&>(Subtarget).resetSubtarget(&MF); + TM.resetSubtarget(&MF); return false; } diff --git a/lib/Target/Mips/MipsModuleISelDAGToDAG.h b/lib/Target/Mips/MipsModuleISelDAGToDAG.h index fda35ae288bb..f7a03104880b 100644 --- a/lib/Target/Mips/MipsModuleISelDAGToDAG.h +++ b/lib/Target/Mips/MipsModuleISelDAGToDAG.h @@ -37,25 +37,17 @@ public: static char ID; explicit MipsModuleDAGToDAGISel(MipsTargetMachine &TM_) - : MachineFunctionPass(ID), - TM(TM_), Subtarget(TM.getSubtarget<MipsSubtarget>()) {} + : MachineFunctionPass(ID), TM(TM_) {} // Pass Name - virtual const char *getPassName() const { + const char *getPassName() const override { return "MIPS DAG->DAG Pattern Instruction Selection"; } - virtual bool runOnMachineFunction(MachineFunction &MF); - - virtual SDNode *Select(SDNode *N) { - llvm_unreachable("unexpected"); - } + bool runOnMachineFunction(MachineFunction &MF) override; 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; + MipsTargetMachine &TM; }; /// createMipsISelDag - This pass converts a legalized DAG into a diff --git a/lib/Target/Mips/MipsOptimizePICCall.cpp b/lib/Target/Mips/MipsOptimizePICCall.cpp new file mode 100644 index 000000000000..c234049ed125 --- /dev/null +++ b/lib/Target/Mips/MipsOptimizePICCall.cpp @@ -0,0 +1,301 @@ +//===--------- MipsOptimizePICCall.cpp - Optimize PIC Calls ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass eliminates unnecessary instructions that set up $gp and replace +// instructions that load target function addresses with copy instructions. +// +//===----------------------------------------------------------------------===// + +#include "Mips.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsMachineFunction.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/ScopedHashTable.h" +#include "llvm/CodeGen/MachineDominators.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/CommandLine.h" + +using namespace llvm; + +#define DEBUG_TYPE "optimize-mips-pic-call" + +static cl::opt<bool> LoadTargetFromGOT("mips-load-target-from-got", + cl::init(true), + cl::desc("Load target address from GOT"), + cl::Hidden); + +static cl::opt<bool> EraseGPOpnd("mips-erase-gp-opnd", + cl::init(true), cl::desc("Erase GP Operand"), + cl::Hidden); + +namespace { +typedef PointerUnion<const Value *, const PseudoSourceValue *> ValueType; + +typedef std::pair<unsigned, unsigned> CntRegP; +typedef RecyclingAllocator<BumpPtrAllocator, + ScopedHashTableVal<ValueType, CntRegP> > +AllocatorTy; +typedef ScopedHashTable<ValueType, CntRegP, DenseMapInfo<ValueType>, + AllocatorTy> ScopedHTType; + +class MBBInfo { +public: + MBBInfo(MachineDomTreeNode *N); + const MachineDomTreeNode *getNode() const; + bool isVisited() const; + void preVisit(ScopedHTType &ScopedHT); + void postVisit(); + +private: + MachineDomTreeNode *Node; + ScopedHTType::ScopeTy *HTScope; +}; + +class OptimizePICCall : public MachineFunctionPass { +public: + OptimizePICCall(TargetMachine &tm) : MachineFunctionPass(ID) {} + + const char *getPassName() const override { return "Mips OptimizePICCall"; } + + bool runOnMachineFunction(MachineFunction &F) override; + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired<MachineDominatorTree>(); + MachineFunctionPass::getAnalysisUsage(AU); + } + +private: + /// \brief Visit MBB. + bool visitNode(MBBInfo &MBBI); + + /// \brief Test if MI jumps to a function via a register. + /// + /// Also, return the virtual register containing the target function's address + /// and the underlying object in Reg and Val respectively, if the function's + /// address can be resolved lazily. + bool isCallViaRegister(MachineInstr &MI, unsigned &Reg, + ValueType &Val) const; + + /// \brief Return the number of instructions that dominate the current + /// instruction and load the function address from object Entry. + unsigned getCount(ValueType Entry); + + /// \brief Return the destination virtual register of the last instruction + /// that loads from object Entry. + unsigned getReg(ValueType Entry); + + /// \brief Update ScopedHT. + void incCntAndSetReg(ValueType Entry, unsigned Reg); + + ScopedHTType ScopedHT; + static char ID; +}; + +char OptimizePICCall::ID = 0; +} // end of anonymous namespace + +/// Return the first MachineOperand of MI if it is a used virtual register. +static MachineOperand *getCallTargetRegOpnd(MachineInstr &MI) { + if (MI.getNumOperands() == 0) + return nullptr; + + MachineOperand &MO = MI.getOperand(0); + + if (!MO.isReg() || !MO.isUse() || + !TargetRegisterInfo::isVirtualRegister(MO.getReg())) + return nullptr; + + return &MO; +} + +/// Return type of register Reg. +static MVT::SimpleValueType getRegTy(unsigned Reg, MachineFunction &MF) { + const TargetRegisterClass *RC = MF.getRegInfo().getRegClass(Reg); + assert(RC->vt_end() - RC->vt_begin() == 1); + return *RC->vt_begin(); +} + +/// Do the following transformation: +/// +/// jalr $vreg +/// => +/// copy $t9, $vreg +/// jalr $t9 +static void setCallTargetReg(MachineBasicBlock *MBB, + MachineBasicBlock::iterator I) { + MachineFunction &MF = *MBB->getParent(); + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + unsigned SrcReg = I->getOperand(0).getReg(); + unsigned DstReg = getRegTy(SrcReg, MF) == MVT::i32 ? Mips::T9 : Mips::T9_64; + BuildMI(*MBB, I, I->getDebugLoc(), TII.get(TargetOpcode::COPY), DstReg) + .addReg(SrcReg); + I->getOperand(0).setReg(DstReg); +} + +/// Search MI's operands for register GP and erase it. +static void eraseGPOpnd(MachineInstr &MI) { + if (!EraseGPOpnd) + return; + + MachineFunction &MF = *MI.getParent()->getParent(); + MVT::SimpleValueType Ty = getRegTy(MI.getOperand(0).getReg(), MF); + unsigned Reg = Ty == MVT::i32 ? Mips::GP : Mips::GP_64; + + for (unsigned I = 0; I < MI.getNumOperands(); ++I) { + MachineOperand &MO = MI.getOperand(I); + if (MO.isReg() && MO.getReg() == Reg) { + MI.RemoveOperand(I); + return; + } + } + + llvm_unreachable(nullptr); +} + +MBBInfo::MBBInfo(MachineDomTreeNode *N) : Node(N), HTScope(nullptr) {} + +const MachineDomTreeNode *MBBInfo::getNode() const { return Node; } + +bool MBBInfo::isVisited() const { return HTScope; } + +void MBBInfo::preVisit(ScopedHTType &ScopedHT) { + HTScope = new ScopedHTType::ScopeTy(ScopedHT); +} + +void MBBInfo::postVisit() { + delete HTScope; +} + +// OptimizePICCall methods. +bool OptimizePICCall::runOnMachineFunction(MachineFunction &F) { + if (F.getTarget().getSubtarget<MipsSubtarget>().inMips16Mode()) + return false; + + // Do a pre-order traversal of the dominator tree. + MachineDominatorTree *MDT = &getAnalysis<MachineDominatorTree>(); + bool Changed = false; + + SmallVector<MBBInfo, 8> WorkList(1, MBBInfo(MDT->getRootNode())); + + while (!WorkList.empty()) { + MBBInfo &MBBI = WorkList.back(); + + // If this MBB has already been visited, destroy the scope for the MBB and + // pop it from the work list. + if (MBBI.isVisited()) { + MBBI.postVisit(); + WorkList.pop_back(); + continue; + } + + // Visit the MBB and add its children to the work list. + MBBI.preVisit(ScopedHT); + Changed |= visitNode(MBBI); + const MachineDomTreeNode *Node = MBBI.getNode(); + const std::vector<MachineDomTreeNode *> &Children = Node->getChildren(); + WorkList.append(Children.begin(), Children.end()); + } + + return Changed; +} + +bool OptimizePICCall::visitNode(MBBInfo &MBBI) { + bool Changed = false; + MachineBasicBlock *MBB = MBBI.getNode()->getBlock(); + + for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E; + ++I) { + unsigned Reg; + ValueType Entry; + + // Skip instructions that are not call instructions via registers. + if (!isCallViaRegister(*I, Reg, Entry)) + continue; + + Changed = true; + unsigned N = getCount(Entry); + + if (N != 0) { + // If a function has been called more than twice, we do not have to emit a + // load instruction to get the function address from the GOT, but can + // instead reuse the address that has been loaded before. + if (N >= 2 && !LoadTargetFromGOT) + getCallTargetRegOpnd(*I)->setReg(getReg(Entry)); + + // Erase the $gp operand if this isn't the first time a function has + // been called. $gp needs to be set up only if the function call can go + // through a lazy binding stub. + eraseGPOpnd(*I); + } + + if (Entry) + incCntAndSetReg(Entry, Reg); + + setCallTargetReg(MBB, I); + } + + return Changed; +} + +bool OptimizePICCall::isCallViaRegister(MachineInstr &MI, unsigned &Reg, + ValueType &Val) const { + if (!MI.isCall()) + return false; + + MachineOperand *MO = getCallTargetRegOpnd(MI); + + // Return if MI is not a function call via a register. + if (!MO) + return false; + + // Get the instruction that loads the function address from the GOT. + Reg = MO->getReg(); + Val = (Value*)nullptr; + MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo(); + MachineInstr *DefMI = MRI.getVRegDef(Reg); + + assert(DefMI); + + // See if DefMI is an instruction that loads from a GOT entry that holds the + // address of a lazy binding stub. + if (!DefMI->mayLoad() || DefMI->getNumOperands() < 3) + return true; + + unsigned Flags = DefMI->getOperand(2).getTargetFlags(); + + if (Flags != MipsII::MO_GOT_CALL && Flags != MipsII::MO_CALL_LO16) + return true; + + // Return the underlying object for the GOT entry in Val. + assert(DefMI->hasOneMemOperand()); + Val = (*DefMI->memoperands_begin())->getValue(); + if (!Val) + Val = (*DefMI->memoperands_begin())->getPseudoValue(); + return true; +} + +unsigned OptimizePICCall::getCount(ValueType Entry) { + return ScopedHT.lookup(Entry).first; +} + +unsigned OptimizePICCall::getReg(ValueType Entry) { + unsigned Reg = ScopedHT.lookup(Entry).second; + assert(Reg); + return Reg; +} + +void OptimizePICCall::incCntAndSetReg(ValueType Entry, unsigned Reg) { + CntRegP P = ScopedHT.lookup(Entry); + ScopedHT.insert(Entry, std::make_pair(P.first + 1, Reg)); +} + +/// Return an OptimizeCall object. +FunctionPass *llvm::createMipsOptimizePICCallPass(MipsTargetMachine &TM) { + return new OptimizePICCall(TM); +} diff --git a/lib/Target/Mips/MipsOptionRecord.h b/lib/Target/Mips/MipsOptionRecord.h new file mode 100644 index 000000000000..c0abce3eaddb --- /dev/null +++ b/lib/Target/Mips/MipsOptionRecord.h @@ -0,0 +1,80 @@ +//===-- MipsOptionRecord.h - Abstraction for storing information ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// MipsOptionRecord - Abstraction for storing arbitrary information in +// ELF files. Arbitrary information (e.g. register usage) can be stored in Mips +// specific ELF sections like .Mips.options. Specific records should subclass +// MipsOptionRecord and provide an implementation to EmitMipsOptionRecord which +// basically just dumps the information into an ELF section. More information +// about .Mips.option can be found in the SysV ABI and the 64-bit ELF Object +// specification. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSOPTIONRECORD_H +#define MIPSOPTIONRECORD_H + +#include "MipsMCTargetDesc.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCRegisterInfo.h" + +using namespace llvm; + +namespace llvm { +class MipsELFStreamer; +class MCSubtargetInfo; +} + +class MipsOptionRecord { +public: + virtual ~MipsOptionRecord(){}; + virtual void EmitMipsOptionRecord() = 0; +}; + +class MipsRegInfoRecord : public MipsOptionRecord { +public: + MipsRegInfoRecord(MipsELFStreamer *S, MCContext &Context, + const MCSubtargetInfo &STI) + : Streamer(S), Context(Context), STI(STI) { + ri_gprmask = 0; + ri_cprmask[0] = ri_cprmask[1] = ri_cprmask[2] = ri_cprmask[3] = 0; + ri_gp_value = 0; + + const MCRegisterInfo *TRI = Context.getRegisterInfo(); + GPR32RegClass = &(TRI->getRegClass(Mips::GPR32RegClassID)); + GPR64RegClass = &(TRI->getRegClass(Mips::GPR64RegClassID)); + FGR32RegClass = &(TRI->getRegClass(Mips::FGR32RegClassID)); + FGR64RegClass = &(TRI->getRegClass(Mips::FGR64RegClassID)); + AFGR64RegClass = &(TRI->getRegClass(Mips::AFGR64RegClassID)); + MSA128BRegClass = &(TRI->getRegClass(Mips::MSA128BRegClassID)); + COP2RegClass = &(TRI->getRegClass(Mips::COP2RegClassID)); + COP3RegClass = &(TRI->getRegClass(Mips::COP3RegClassID)); + } + ~MipsRegInfoRecord() {} + + void EmitMipsOptionRecord(); + void SetPhysRegUsed(unsigned Reg, const MCRegisterInfo *MCRegInfo); + +private: + MipsELFStreamer *Streamer; + MCContext &Context; + const MCSubtargetInfo &STI; + const MCRegisterClass *GPR32RegClass; + const MCRegisterClass *GPR64RegClass; + const MCRegisterClass *FGR32RegClass; + const MCRegisterClass *FGR64RegClass; + const MCRegisterClass *AFGR64RegClass; + const MCRegisterClass *MSA128BRegClass; + const MCRegisterClass *COP2RegClass; + const MCRegisterClass *COP3RegClass; + uint32_t ri_gprmask; + uint32_t ri_cprmask[4]; + int64_t ri_gp_value; +}; +#endif diff --git a/lib/Target/Mips/MipsOs16.cpp b/lib/Target/Mips/MipsOs16.cpp index fe60841212e0..7aae964df538 100644 --- a/lib/Target/Mips/MipsOs16.cpp +++ b/lib/Target/Mips/MipsOs16.cpp @@ -11,13 +11,14 @@ // //===----------------------------------------------------------------------===// -#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" +#define DEBUG_TYPE "mips-os16" + static cl::opt<std::string> Mips32FunctionMask( "mips32-function-mask", diff --git a/lib/Target/Mips/MipsOs16.h b/lib/Target/Mips/MipsOs16.h index 21beef8549cd..55e5a81daf99 100644 --- a/lib/Target/Mips/MipsOs16.h +++ b/lib/Target/Mips/MipsOs16.h @@ -34,11 +34,11 @@ public: } - virtual const char *getPassName() const { + const char *getPassName() const override { return "MIPS Os16 Optimization"; } - virtual bool runOnModule(Module &M); + bool runOnModule(Module &M) override; }; diff --git a/lib/Target/Mips/MipsRegisterInfo.cpp b/lib/Target/Mips/MipsRegisterInfo.cpp index 3105b0208451..084449bba59c 100644 --- a/lib/Target/Mips/MipsRegisterInfo.cpp +++ b/lib/Target/Mips/MipsRegisterInfo.cpp @@ -11,8 +11,6 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "mips-reg-info" - #include "MipsRegisterInfo.h" #include "Mips.h" #include "MipsAnalyzeImmediate.h" @@ -24,9 +22,9 @@ #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/DebugInfo.h" +#include "llvm/IR/Function.h" #include "llvm/IR/Type.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -37,11 +35,13 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" +using namespace llvm; + +#define DEBUG_TYPE "mips-reg-info" + #define GET_REGINFO_TARGET_DESC #include "MipsGenRegisterInfo.inc" -using namespace llvm; - MipsRegisterInfo::MipsRegisterInfo(const MipsSubtarget &ST) : MipsGenRegisterInfo(Mips::RA), Subtarget(ST) {} @@ -79,8 +79,8 @@ MipsRegisterInfo::getRegPressureLimit(const TargetRegisterClass *RC, //===----------------------------------------------------------------------===// /// Mips Callee Saved Registers -const uint16_t* MipsRegisterInfo:: -getCalleeSavedRegs(const MachineFunction *MF) const { +const MCPhysReg * +MipsRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { if (Subtarget.isSingleFloat()) return CSR_SingleFloatOnly_SaveList; @@ -93,6 +93,9 @@ getCalleeSavedRegs(const MachineFunction *MF) const { if (Subtarget.isFP64bit()) return CSR_O32_FP64_SaveList; + if (Subtarget.isFPXX()) + return CSR_O32_FPXX_SaveList; + return CSR_O32_SaveList; } @@ -110,6 +113,9 @@ MipsRegisterInfo::getCallPreservedMask(CallingConv::ID) const { if (Subtarget.isFP64bit()) return CSR_O32_FP64_RegMask; + if (Subtarget.isFPXX()) + return CSR_O32_FPXX_RegMask; + return CSR_O32_RegMask; } @@ -119,11 +125,11 @@ const uint32_t *MipsRegisterInfo::getMips16RetHelperMask() { BitVector MipsRegisterInfo:: getReservedRegs(const MachineFunction &MF) const { - static const uint16_t ReservedGPR32[] = { + static const MCPhysReg ReservedGPR32[] = { Mips::ZERO, Mips::K0, Mips::K1, Mips::SP }; - static const uint16_t ReservedGPR64[] = { + static const MCPhysReg ReservedGPR64[] = { Mips::ZERO_64, Mips::K0_64, Mips::K1_64, Mips::SP_64 }; @@ -133,6 +139,13 @@ getReservedRegs(const MachineFunction &MF) const { for (unsigned I = 0; I < array_lengthof(ReservedGPR32); ++I) Reserved.set(ReservedGPR32[I]); + // Reserve registers for the NaCl sandbox. + if (Subtarget.isTargetNaCl()) { + Reserved.set(Mips::T6); // Reserved for control flow mask. + Reserved.set(Mips::T7); // Reserved for memory access mask. + Reserved.set(Mips::T8); // Reserved for thread pointer. + } + for (unsigned I = 0; I < array_lengthof(ReservedGPR64); ++I) Reserved.set(ReservedGPR64[I]); @@ -179,10 +192,13 @@ getReservedRegs(const MachineFunction &MF) const { // Reserve RA if in mips16 mode. if (Subtarget.inMips16Mode()) { + const MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); Reserved.set(Mips::RA); Reserved.set(Mips::RA_64); Reserved.set(Mips::T0); Reserved.set(Mips::T1); + if (MF.getFunction()->hasFnAttribute("saveS2") || MipsFI->hasSaveS2()) + Reserved.set(Mips::S2); } // Reserve GP if small section is used. @@ -191,6 +207,11 @@ getReservedRegs(const MachineFunction &MF) const { Reserved.set(Mips::GP_64); } + if (Subtarget.isABI_O32() && !Subtarget.useOddSPReg()) { + for (const auto &Reg : Mips::OddSPRegClass) + Reserved.set(Reg); + } + return Reserved; } diff --git a/lib/Target/Mips/MipsRegisterInfo.h b/lib/Target/Mips/MipsRegisterInfo.h index 0450c6fbe47e..b34496fd8e12 100644 --- a/lib/Target/Mips/MipsRegisterInfo.h +++ b/lib/Target/Mips/MipsRegisterInfo.h @@ -43,30 +43,31 @@ public: /// Code Generation virtual methods... const TargetRegisterClass *getPointerRegClass(const MachineFunction &MF, - unsigned Kind) const; + unsigned Kind) const override; unsigned getRegPressureLimit(const TargetRegisterClass *RC, - MachineFunction &MF) const; - const uint16_t *getCalleeSavedRegs(const MachineFunction *MF = 0) const; - const uint32_t *getCallPreservedMask(CallingConv::ID) const; + MachineFunction &MF) const override; + const MCPhysReg * + getCalleeSavedRegs(const MachineFunction *MF = nullptr) const override; + const uint32_t *getCallPreservedMask(CallingConv::ID) const override; static const uint32_t *getMips16RetHelperMask(); - BitVector getReservedRegs(const MachineFunction &MF) const; + BitVector getReservedRegs(const MachineFunction &MF) const override; - virtual bool requiresRegisterScavenging(const MachineFunction &MF) const; + bool requiresRegisterScavenging(const MachineFunction &MF) const override; - virtual bool trackLivenessAfterRegAlloc(const MachineFunction &MF) const; + bool trackLivenessAfterRegAlloc(const MachineFunction &MF) const override; /// Stack Frame Processing Methods void eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum, - RegScavenger *RS = NULL) const; + RegScavenger *RS = nullptr) const override; void processFunctionBeforeFrameFinalized(MachineFunction &MF, - RegScavenger *RS = NULL) const; + RegScavenger *RS = nullptr) const; /// Debug information queries. - unsigned getFrameRegister(const MachineFunction &MF) const; + unsigned getFrameRegister(const MachineFunction &MF) const override; /// \brief Return GPR register class. virtual const TargetRegisterClass *intRegClass(unsigned Size) const = 0; diff --git a/lib/Target/Mips/MipsRegisterInfo.td b/lib/Target/Mips/MipsRegisterInfo.td index 3173d0927af1..74dfa4fe7d9c 100644 --- a/lib/Target/Mips/MipsRegisterInfo.td +++ b/lib/Target/Mips/MipsRegisterInfo.td @@ -205,11 +205,16 @@ let Namespace = "Mips" in { foreach I = 0-31 in def COP2#I : MipsReg<#I, ""#I>; + // COP3 registers. + foreach I = 0-31 in + def COP3#I : MipsReg<#I, ""#I>; + // PC register def PC : Register<"pc">; // Hardware register $29 - def HWR29 : MipsReg<29, "29">; + foreach I = 0-31 in + def HWR#I : MipsReg<#I, ""#I>; // Accum registers foreach I = 0-3 in @@ -245,6 +250,15 @@ let Namespace = "Mips" in { def MSARequest : MipsReg<5, "5">; def MSAMap : MipsReg<6, "6">; def MSAUnmap : MipsReg<7, "7">; + + // Octeon multiplier and product registers + def MPL0 : MipsReg<0, "mpl0">; + def MPL1 : MipsReg<1, "mpl1">; + def MPL2 : MipsReg<2, "mpl2">; + def P0 : MipsReg<0, "p0">; + def P1 : MipsReg<1, "p1">; + def P2 : MipsReg<2, "p2">; + } //===----------------------------------------------------------------------===// @@ -326,6 +340,15 @@ def AFGR64 : RegisterClass<"Mips", [f64], 64, (add def FGR64 : RegisterClass<"Mips", [f64], 64, (sequence "D%u_64", 0, 31)>; +// Used to reserve odd registers when given -mattr=+nooddspreg +// FIXME: Remove double precision registers from this set. +def OddSP : RegisterClass<"Mips", [f32], 32, + (add (decimate (sequence "F%u", 1, 31), 2), + (decimate (sequence "F_HI%u", 1, 31), 2), + (decimate (sequence "D%u", 1, 15), 2), + (decimate (sequence "D%u_64", 1, 31), 2))>, + Unallocatable; + // FP control registers. def CCR : RegisterClass<"Mips", [i32], 32, (sequence "FCR%u", 0, 31)>, Unallocatable; @@ -334,6 +357,10 @@ def CCR : RegisterClass<"Mips", [i32], 32, (sequence "FCR%u", 0, 31)>, def FCC : RegisterClass<"Mips", [i32], 32, (sequence "FCC%u", 0, 7)>, Unallocatable; +// MIPS32r6/MIPS64r6 store FPU condition codes in normal FGR registers. +// This class allows us to represent this in codegen patterns. +def FGRCC : RegisterClass<"Mips", [i32], 32, (sequence "F%u", 0, 31)>; + def MSA128B: RegisterClass<"Mips", [v16i8], 128, (sequence "W%u", 0, 31)>; def MSA128H: RegisterClass<"Mips", [v8i16, v8f16], 128, @@ -355,7 +382,8 @@ 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; +def HWRegs : RegisterClass<"Mips", [i32], 32, (sequence "HWR%u", 0, 31)>, + Unallocatable; // Accumulator Registers def ACC64 : RegisterClass<"Mips", [untyped], 64, (add AC0)> { @@ -376,89 +404,81 @@ def DSPCC : RegisterClass<"Mips", [v4i8, v2i16], 32, (add DSPCCond)>; def COP2 : RegisterClass<"Mips", [i32], 32, (sequence "COP2%u", 0, 31)>, Unallocatable; +// Coprocessor 3 registers. +def COP3 : RegisterClass<"Mips", [i32], 32, (sequence "COP3%u", 0, 31)>, + Unallocatable; + +// Octeon multiplier and product registers +def OCTEON_MPL : RegisterClass<"Mips", [i64], 64, (add MPL0, MPL1, MPL2)>, + Unallocatable; +def OCTEON_P : RegisterClass<"Mips", [i64], 64, (add P0, P1, P2)>, + Unallocatable; + // Register Operands. class MipsAsmRegOperand : AsmOperandClass { - let RenderMethod = "addRegAsmOperands"; -} -def GPR32AsmOperand : MipsAsmRegOperand { - let Name = "GPR32Asm"; - let ParserMethod = "parseGPR32"; + let ParserMethod = "ParseAnyRegister"; } def GPR64AsmOperand : MipsAsmRegOperand { - let Name = "GPR64Asm"; - let ParserMethod = "parseGPR64"; + let Name = "GPR64AsmReg"; + let PredicateMethod = "isGPRAsmReg"; } -def ACC64DSPAsmOperand : MipsAsmRegOperand { - let Name = "ACC64DSPAsm"; - let ParserMethod = "parseACC64DSP"; +def GPR32AsmOperand : MipsAsmRegOperand { + let Name = "GPR32AsmReg"; + let PredicateMethod = "isGPRAsmReg"; } -def LO32DSPAsmOperand : MipsAsmRegOperand { - let Name = "LO32DSPAsm"; - let ParserMethod = "parseLO32DSP"; +def ACC64DSPAsmOperand : MipsAsmRegOperand { + let Name = "ACC64DSPAsmReg"; + let PredicateMethod = "isACCAsmReg"; } def HI32DSPAsmOperand : MipsAsmRegOperand { - let Name = "HI32DSPAsm"; - let ParserMethod = "parseHI32DSP"; + let Name = "HI32DSPAsmReg"; + let PredicateMethod = "isACCAsmReg"; +} + +def LO32DSPAsmOperand : MipsAsmRegOperand { + let Name = "LO32DSPAsmReg"; + let PredicateMethod = "isACCAsmReg"; } def CCRAsmOperand : MipsAsmRegOperand { - let Name = "CCRAsm"; - let ParserMethod = "parseCCRRegs"; + let Name = "CCRAsmReg"; } def AFGR64AsmOperand : MipsAsmRegOperand { - let Name = "AFGR64Asm"; - let ParserMethod = "parseAFGR64Regs"; + let Name = "AFGR64AsmReg"; + let PredicateMethod = "isFGRAsmReg"; } def FGR64AsmOperand : MipsAsmRegOperand { - let Name = "FGR64Asm"; - let ParserMethod = "parseFGR64Regs"; + let Name = "FGR64AsmReg"; + let PredicateMethod = "isFGRAsmReg"; } def FGR32AsmOperand : MipsAsmRegOperand { - let Name = "FGR32Asm"; - let ParserMethod = "parseFGR32Regs"; + let Name = "FGR32AsmReg"; + let PredicateMethod = "isFGRAsmReg"; } def FGRH32AsmOperand : MipsAsmRegOperand { - let Name = "FGRH32Asm"; - let ParserMethod = "parseFGRH32Regs"; + let Name = "FGRH32AsmReg"; + let PredicateMethod = "isFGRAsmReg"; } 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"; + let Name = "FCCAsmReg"; } -def MSA128DAsmOperand : MipsAsmRegOperand { - let Name = "MSA128DAsm"; - let ParserMethod = "parseMSA128DRegs"; +def MSA128AsmOperand : MipsAsmRegOperand { + let Name = "MSA128AsmReg"; } -def MSA128CRAsmOperand : MipsAsmRegOperand { - let Name = "MSA128CRAsm"; - let ParserMethod = "parseMSA128CtrlRegs"; +def MSACtrlAsmOperand : MipsAsmRegOperand { + let Name = "MSACtrlAsmReg"; } def GPR32Opnd : RegisterOperand<GPR32> { @@ -478,13 +498,15 @@ def CCROpnd : RegisterOperand<CCR> { } def HWRegsAsmOperand : MipsAsmRegOperand { - let Name = "HWRegsAsm"; - let ParserMethod = "parseHWRegs"; + let Name = "HWRegsAsmReg"; } def COP2AsmOperand : MipsAsmRegOperand { - let Name = "COP2Asm"; - let ParserMethod = "parseCOP2"; + let Name = "COP2AsmReg"; +} + +def COP3AsmOperand : MipsAsmRegOperand { + let Name = "COP3AsmReg"; } def HWRegsOpnd : RegisterOperand<HWRegs> { @@ -503,6 +525,12 @@ def FGR32Opnd : RegisterOperand<FGR32> { let ParserMatchClass = FGR32AsmOperand; } +def FGRCCOpnd : RegisterOperand<FGRCC> { + // The assembler doesn't use register classes so we can re-use + // FGR32AsmOperand. + let ParserMatchClass = FGR32AsmOperand; +} + def FGRH32Opnd : RegisterOperand<FGRH32> { let ParserMatchClass = FGRH32AsmOperand; } @@ -527,23 +555,27 @@ def COP2Opnd : RegisterOperand<COP2> { let ParserMatchClass = COP2AsmOperand; } +def COP3Opnd : RegisterOperand<COP3> { + let ParserMatchClass = COP3AsmOperand; +} + def MSA128BOpnd : RegisterOperand<MSA128B> { - let ParserMatchClass = MSA128BAsmOperand; + let ParserMatchClass = MSA128AsmOperand; } def MSA128HOpnd : RegisterOperand<MSA128H> { - let ParserMatchClass = MSA128HAsmOperand; + let ParserMatchClass = MSA128AsmOperand; } def MSA128WOpnd : RegisterOperand<MSA128W> { - let ParserMatchClass = MSA128WAsmOperand; + let ParserMatchClass = MSA128AsmOperand; } def MSA128DOpnd : RegisterOperand<MSA128D> { - let ParserMatchClass = MSA128DAsmOperand; + let ParserMatchClass = MSA128AsmOperand; } def MSA128CROpnd : RegisterOperand<MSACtrl> { - let ParserMatchClass = MSA128CRAsmOperand; + let ParserMatchClass = MSACtrlAsmOperand; } diff --git a/lib/Target/Mips/MipsSEFrameLowering.cpp b/lib/Target/Mips/MipsSEFrameLowering.cpp index 33ed4b3e3a67..d0a17cd834a0 100644 --- a/lib/Target/Mips/MipsSEFrameLowering.cpp +++ b/lib/Target/Mips/MipsSEFrameLowering.cpp @@ -16,6 +16,7 @@ #include "MipsAnalyzeImmediate.h" #include "MipsMachineFunction.h" #include "MipsSEInstrInfo.h" +#include "MipsSubtarget.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" @@ -63,6 +64,10 @@ private: bool expandCopy(MachineBasicBlock &MBB, Iter I); bool expandCopyACC(MachineBasicBlock &MBB, Iter I, unsigned MFHiOpc, unsigned MFLoOpc); + bool expandBuildPairF64(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, bool FP64) const; + bool expandExtractElementF64(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, bool FP64) const; MachineFunction &MF; MachineRegisterInfo &MRI; @@ -107,6 +112,22 @@ bool ExpandPseudo::expandInstr(MachineBasicBlock &MBB, Iter I) { case Mips::STORE_ACC128: expandStoreACC(MBB, I, Mips::PseudoMFHI64, Mips::PseudoMFLO64, 8); break; + case Mips::BuildPairF64: + if (expandBuildPairF64(MBB, I, false)) + MBB.erase(I); + return false; + case Mips::BuildPairF64_64: + if (expandBuildPairF64(MBB, I, true)) + MBB.erase(I); + return false; + case Mips::ExtractElementF64: + if (expandExtractElementF64(MBB, I, false)) + MBB.erase(I); + return false; + case Mips::ExtractElementF64_64: + if (expandExtractElementF64(MBB, I, true)) + MBB.erase(I); + return false; case TargetOpcode::COPY: if (!expandCopy(MBB, I)) return false; @@ -257,6 +278,123 @@ bool ExpandPseudo::expandCopyACC(MachineBasicBlock &MBB, Iter I, return true; } +/// This method expands the same instruction that MipsSEInstrInfo:: +/// expandBuildPairF64 does, for the case when ABI is fpxx and mthc1 is not +/// available and the case where the ABI is FP64A. It is implemented here +/// because frame indexes are eliminated before MipsSEInstrInfo:: +/// expandBuildPairF64 is called. +bool ExpandPseudo::expandBuildPairF64(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + bool FP64) const { + // For fpxx and when mthc1 is not available, use: + // spill + reload via ldc1 + // + // The case where dmtc1 is available doesn't need to be handled here + // because it never creates a BuildPairF64 node. + // + // The FP64A ABI (fp64 with nooddspreg) must also use a spill/reload sequence + // for odd-numbered double precision values (because the lower 32-bits is + // transferred with mtc1 which is redirected to the upper half of the even + // register). Unfortunately, we have to make this decision before register + // allocation so for now we use a spill/reload sequence for all + // double-precision values in regardless of being an odd/even register. + + const TargetMachine &TM = MF.getTarget(); + const MipsSubtarget &Subtarget = TM.getSubtarget<MipsSubtarget>(); + if ((Subtarget.isABI_FPXX() && !Subtarget.hasMTHC1()) || + (FP64 && !Subtarget.useOddSPReg())) { + const MipsSEInstrInfo &TII = + *static_cast<const MipsSEInstrInfo*>(TM.getInstrInfo()); + const MipsRegisterInfo &TRI = + *static_cast<const MipsRegisterInfo*>(TM.getRegisterInfo()); + + unsigned DstReg = I->getOperand(0).getReg(); + unsigned LoReg = I->getOperand(1).getReg(); + unsigned HiReg = I->getOperand(2).getReg(); + + // It should be impossible to have FGR64 on MIPS-II or MIPS32r1 (which are + // the cases where mthc1 is not available). 64-bit architectures and + // MIPS32r2 or later can use FGR64 though. + assert(Subtarget.isGP64bit() || Subtarget.hasMTHC1() || + !Subtarget.isFP64bit()); + + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + const TargetRegisterClass *RC2 = + FP64 ? &Mips::FGR64RegClass : &Mips::AFGR64RegClass; + + // We re-use the same spill slot each time so that the stack frame doesn't + // grow too much in functions with a large number of moves. + int FI = MF.getInfo<MipsFunctionInfo>()->getMoveF64ViaSpillFI(RC2); + TII.storeRegToStack(MBB, I, LoReg, I->getOperand(1).isKill(), FI, RC, &TRI, + 0); + TII.storeRegToStack(MBB, I, HiReg, I->getOperand(2).isKill(), FI, RC, &TRI, + 4); + TII.loadRegFromStack(MBB, I, DstReg, FI, RC2, &TRI, 0); + return true; + } + + return false; +} + +/// This method expands the same instruction that MipsSEInstrInfo:: +/// expandExtractElementF64 does, for the case when ABI is fpxx and mfhc1 is not +/// available and the case where the ABI is FP64A. It is implemented here +/// because frame indexes are eliminated before MipsSEInstrInfo:: +/// expandExtractElementF64 is called. +bool ExpandPseudo::expandExtractElementF64(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + bool FP64) const { + // For fpxx and when mfhc1 is not available, use: + // spill + reload via ldc1 + // + // The case where dmfc1 is available doesn't need to be handled here + // because it never creates a ExtractElementF64 node. + // + // The FP64A ABI (fp64 with nooddspreg) must also use a spill/reload sequence + // for odd-numbered double precision values (because the lower 32-bits is + // transferred with mfc1 which is redirected to the upper half of the even + // register). Unfortunately, we have to make this decision before register + // allocation so for now we use a spill/reload sequence for all + // double-precision values in regardless of being an odd/even register. + + const TargetMachine &TM = MF.getTarget(); + const MipsSubtarget &Subtarget = TM.getSubtarget<MipsSubtarget>(); + if ((Subtarget.isABI_FPXX() && !Subtarget.hasMTHC1()) || + (FP64 && !Subtarget.useOddSPReg())) { + const MipsSEInstrInfo &TII = + *static_cast<const MipsSEInstrInfo *>(TM.getInstrInfo()); + const MipsRegisterInfo &TRI = + *static_cast<const MipsRegisterInfo *>(TM.getRegisterInfo()); + + unsigned DstReg = I->getOperand(0).getReg(); + unsigned SrcReg = I->getOperand(1).getReg(); + unsigned N = I->getOperand(2).getImm(); + + // It should be impossible to have FGR64 on MIPS-II or MIPS32r1 (which are + // the cases where mfhc1 is not available). 64-bit architectures and + // MIPS32r2 or later can use FGR64 though. + assert(Subtarget.isGP64bit() || Subtarget.hasMTHC1() || + !Subtarget.isFP64bit()); + + const TargetRegisterClass *RC = + FP64 ? &Mips::FGR64RegClass : &Mips::AFGR64RegClass; + const TargetRegisterClass *RC2 = &Mips::GPR32RegClass; + + // We re-use the same spill slot each time so that the stack frame doesn't + // grow too much in functions with a large number of moves. + int FI = MF.getInfo<MipsFunctionInfo>()->getMoveF64ViaSpillFI(RC); + TII.storeRegToStack(MBB, I, SrcReg, I->getOperand(1).isKill(), FI, RC, &TRI, + 0); + TII.loadRegFromStack(MBB, I, DstReg, FI, RC2, &TRI, N * 4); + return true; + } + + return false; +} + +MipsSEFrameLowering::MipsSEFrameLowering(const MipsSubtarget &STI) + : MipsFrameLowering(STI, STI.stackAlignment()) {} + unsigned MipsSEFrameLowering::ehDataReg(unsigned I) const { static const unsigned EhDataReg[] = { Mips::A0, Mips::A1, Mips::A2, Mips::A3 @@ -299,11 +437,10 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF) const { 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)); + unsigned CFIIndex = MMI.addFrameInst( + MCCFIInstruction::createDefCfaOffset(nullptr, -StackSize)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); @@ -315,10 +452,6 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF) const { // 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()); @@ -335,14 +468,37 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF) const { if (!STI.isLittle()) std::swap(Reg0, Reg1); - MMI.addFrameInst( - MCCFIInstruction::createOffset(CSLabel, Reg0, Offset)); - MMI.addFrameInst( - MCCFIInstruction::createOffset(CSLabel, Reg1, Offset + 4)); + unsigned CFIIndex = MMI.addFrameInst( + MCCFIInstruction::createOffset(nullptr, Reg0, Offset)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + + CFIIndex = MMI.addFrameInst( + MCCFIInstruction::createOffset(nullptr, Reg1, Offset + 4)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } else if (Mips::FGR64RegClass.contains(Reg)) { + unsigned Reg0 = MRI->getDwarfRegNum(Reg, true); + unsigned Reg1 = MRI->getDwarfRegNum(Reg, true) + 1; + + if (!STI.isLittle()) + std::swap(Reg0, Reg1); + + unsigned CFIIndex = MMI.addFrameInst( + MCCFIInstruction::createOffset(nullptr, Reg0, Offset)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + + CFIIndex = MMI.addFrameInst( + MCCFIInstruction::createOffset(nullptr, Reg1, Offset + 4)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); } else { // Reg is either in GPR32 or FGR32. - MMI.addFrameInst(MCCFIInstruction::createOffset( - CSLabel, MRI->getDwarfRegNum(Reg, 1), Offset)); + unsigned CFIIndex = MMI.addFrameInst(MCCFIInstruction::createOffset( + nullptr, MRI->getDwarfRegNum(Reg, 1), Offset)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); } } } @@ -360,27 +516,27 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF) const { } // 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)); + unsigned CFIIndex = MMI.addFrameInst( + MCCFIInstruction::createOffset(nullptr, Reg, Offset)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); } } // 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); + BuildMI(MBB, MBBI, dl, TII.get(ADDu), FP).addReg(SP).addReg(ZERO) + .setMIFlag(MachineInstr::FrameSetup); // 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))); + unsigned CFIIndex = MMI.addFrameInst(MCCFIInstruction::createDefCfaRegister( + nullptr, MRI->getDwarfRegNum(FP, true))); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); } } diff --git a/lib/Target/Mips/MipsSEFrameLowering.h b/lib/Target/Mips/MipsSEFrameLowering.h index 8fa9e469887d..e832848754dc 100644 --- a/lib/Target/Mips/MipsSEFrameLowering.h +++ b/lib/Target/Mips/MipsSEFrameLowering.h @@ -20,27 +20,26 @@ namespace llvm { class MipsSEFrameLowering : public MipsFrameLowering { public: - explicit MipsSEFrameLowering(const MipsSubtarget &STI) - : MipsFrameLowering(STI, STI.stackAlignment()) {} + explicit MipsSEFrameLowering(const MipsSubtarget &STI); /// 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 emitPrologue(MachineFunction &MF) const override; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override; void eliminateCallFramePseudoInstr(MachineFunction &MF, - MachineBasicBlock &MBB, - MachineBasicBlock::iterator I) const; + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const override; bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, const std::vector<CalleeSavedInfo> &CSI, - const TargetRegisterInfo *TRI) const; + const TargetRegisterInfo *TRI) const override; - bool hasReservedCallFrame(const MachineFunction &MF) const; + bool hasReservedCallFrame(const MachineFunction &MF) const override; void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, - RegScavenger *RS) const; + RegScavenger *RS) const override; unsigned ehDataReg(unsigned I) const; }; diff --git a/lib/Target/Mips/MipsSEISelDAGToDAG.cpp b/lib/Target/Mips/MipsSEISelDAGToDAG.cpp index 737660ec876c..47e193191c3e 100644 --- a/lib/Target/Mips/MipsSEISelDAGToDAG.cpp +++ b/lib/Target/Mips/MipsSEISelDAGToDAG.cpp @@ -11,10 +11,9 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "mips-isel" #include "MipsSEISelDAGToDAG.h" -#include "Mips.h" #include "MCTargetDesc/MipsBaseInfo.h" +#include "Mips.h" #include "MipsAnalyzeImmediate.h" #include "MipsMachineFunction.h" #include "MipsRegisterInfo.h" @@ -24,19 +23,22 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/IR/CFG.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; +#define DEBUG_TYPE "mips-isel" + bool MipsSEDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { - if (Subtarget.inMips16Mode()) + Subtarget = &TM.getSubtarget<MipsSubtarget>(); + if (Subtarget->inMips16Mode()) return false; return MipsDAGToDAGISel::runOnMachineFunction(MF); } @@ -104,7 +106,7 @@ bool MipsSEDAGToDAGISel::replaceUsesWithZeroReg(MachineRegisterInfo *MRI, // Replace uses with ZeroReg. for (MachineRegisterInfo::use_iterator U = MRI->use_begin(DstReg), E = MRI->use_end(); U != E;) { - MachineOperand &MO = U.getOperand(); + MachineOperand &MO = *U; unsigned OpNo = U.getOperandNo(); MachineInstr *MI = MO.getParent(); ++U; @@ -133,7 +135,7 @@ void MipsSEDAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) { unsigned V0, V1, GlobalBaseReg = MipsFI->getGlobalBaseReg(); const TargetRegisterClass *RC; - if (Subtarget.isABI_N64()) + if (Subtarget->isABI_N64()) RC = (const TargetRegisterClass*)&Mips::GPR64RegClass; else RC = (const TargetRegisterClass*)&Mips::GPR32RegClass; @@ -141,7 +143,7 @@ void MipsSEDAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) { V0 = RegInfo.createVirtualRegister(RC); V1 = RegInfo.createVirtualRegister(RC); - if (Subtarget.isABI_N64()) { + if (Subtarget->isABI_N64()) { MF.getRegInfo().addLiveIn(Mips::T9_64); MBB.addLiveIn(Mips::T9_64); @@ -173,7 +175,7 @@ void MipsSEDAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) { MF.getRegInfo().addLiveIn(Mips::T9); MBB.addLiveIn(Mips::T9); - if (Subtarget.isABI_N32()) { + if (Subtarget->isABI_N32()) { // lui $v0, %hi(%neg(%gp_rel(fname))) // addu $v1, $v0, $t9 // addiu $globalbasereg, $v1, %lo(%neg(%gp_rel(fname))) @@ -186,7 +188,7 @@ void MipsSEDAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) { return; } - assert(Subtarget.isABI_O32()); + assert(Subtarget->isABI_O32()); // For O32 ABI, the following instruction sequence is emitted to initialize // the global base register: @@ -248,18 +250,49 @@ SDNode *MipsSEDAGToDAGISel::selectAddESubE(unsigned MOp, SDValue InFlag, SDValue(AddCarry, 0)); } +/// Match frameindex +bool MipsSEDAGToDAGISel::selectAddrFrameIndex(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { + EVT ValTy = Addr.getValueType(); + + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); + Offset = CurDAG->getTargetConstant(0, ValTy); + return true; + } + return false; +} + +/// Match frameindex+offset and frameindex|offset +bool MipsSEDAGToDAGISel::selectAddrFrameIndexOffset(SDValue Addr, SDValue &Base, + SDValue &Offset, + unsigned OffsetBits) const { + if (CurDAG->isBaseWithConstantOffset(Addr)) { + ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)); + if (isIntN(OffsetBits, CN->getSExtValue())) { + EVT ValTy = Addr.getValueType(); + + // 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; + } + } + return false; +} + /// 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); + if (selectAddrFrameIndex(Addr, Base, Offset)) return true; - } // on PIC code Load GA if (Addr.getOpcode() == MipsISD::Wrapper) { @@ -275,21 +308,8 @@ bool MipsSEDAGToDAGISel::selectAddrRegImm(SDValue Addr, SDValue &Base, } // 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; - } - } + if (selectAddrFrameIndexOffset(Addr, Base, Offset, 16)) + return true; // Operand is a result from an ADD. if (Addr.getOpcode() == ISD::ADD) { @@ -343,27 +363,25 @@ bool MipsSEDAGToDAGISel::selectIntAddr(SDValue Addr, SDValue &Base, selectAddrDefault(Addr, Base, Offset); } -/// Used on microMIPS Load/Store unaligned instructions (12-bit offset) -bool MipsSEDAGToDAGISel::selectAddrRegImm12(SDValue Addr, SDValue &Base, +bool MipsSEDAGToDAGISel::selectAddrRegImm10(SDValue Addr, SDValue &Base, SDValue &Offset) const { - EVT ValTy = Addr.getValueType(); + if (selectAddrFrameIndex(Addr, Base, Offset)) + return true; - // 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 (selectAddrFrameIndexOffset(Addr, Base, Offset, 10)) + return true; - // 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); + return false; +} - Offset = CurDAG->getTargetConstant(CN->getZExtValue(), ValTy); - return true; - } - } +/// Used on microMIPS Load/Store unaligned instructions (12-bit offset) +bool MipsSEDAGToDAGISel::selectAddrRegImm12(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if (selectAddrFrameIndex(Addr, Base, Offset)) + return true; + + if (selectAddrFrameIndexOffset(Addr, Base, Offset, 12)) + return true; return false; } @@ -374,18 +392,29 @@ bool MipsSEDAGToDAGISel::selectIntAddrMM(SDValue Addr, SDValue &Base, selectAddrDefault(Addr, Base, Offset); } +bool MipsSEDAGToDAGISel::selectIntAddrMSA(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if (selectAddrRegImm10(Addr, Base, Offset)) + return true; + + if (selectAddrDefault(Addr, Base, Offset)) + return true; + + return false; +} + // 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()) + if (!Subtarget->hasMSA()) return false; BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N); - if (Node == NULL) + if (!Node) return false; APInt SplatValue, SplatUndef; @@ -394,7 +423,7 @@ bool MipsSEDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm) const { if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs, 8, - !Subtarget.isLittle())) + !Subtarget->isLittle())) return false; Imm = SplatValue; @@ -620,7 +649,7 @@ std::pair<bool, SDNode*> MipsSEDAGToDAGISel::selectNode(SDNode *Node) { } case ISD::ADDE: { - if (Subtarget.hasDSP()) // Select DSP instructions, ADDSC and ADDWC. + 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); @@ -630,11 +659,11 @@ std::pair<bool, SDNode*> MipsSEDAGToDAGISel::selectNode(SDNode *Node) { case ISD::ConstantFP: { ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(Node); if (Node->getValueType(0) == MVT::f64 && CN->isExactlyValue(+0.0)) { - if (Subtarget.hasMips64()) { + if (Subtarget->isGP64bit()) { 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()) { + } else if (Subtarget->isFP64bit()) { SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, Mips::ZERO, MVT::i32); Result = CurDAG->getMachineNode(Mips::BuildPairF64_64, DL, MVT::f64, @@ -785,17 +814,17 @@ std::pair<bool, SDNode*> MipsSEDAGToDAGISel::selectNode(SDNode *Node) { EVT ResVecTy = BVN->getValueType(0); EVT ViaVecTy; - if (!Subtarget.hasMSA() || !BVN->getValueType(0).is128BitVector()) - return std::make_pair(false, (SDNode*)NULL); + if (!Subtarget->hasMSA() || !BVN->getValueType(0).is128BitVector()) + return std::make_pair(false, nullptr); if (!BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs, 8, - !Subtarget.isLittle())) - return std::make_pair(false, (SDNode*)NULL); + !Subtarget->isLittle())) + return std::make_pair(false, nullptr); switch (SplatBitSize) { default: - return std::make_pair(false, (SDNode*)NULL); + return std::make_pair(false, nullptr); case 8: LdiOp = Mips::LDI_B; ViaVecTy = MVT::v16i8; @@ -815,7 +844,7 @@ std::pair<bool, SDNode*> MipsSEDAGToDAGISel::selectNode(SDNode *Node) { } if (!SplatValue.isSignedIntN(10)) - return std::make_pair(false, (SDNode*)NULL); + return std::make_pair(false, nullptr); SDValue Imm = CurDAG->getTargetConstant(SplatValue, ViaVecTy.getVectorElementType()); @@ -841,7 +870,7 @@ std::pair<bool, SDNode*> MipsSEDAGToDAGISel::selectNode(SDNode *Node) { } - return std::make_pair(false, (SDNode*)NULL); + return std::make_pair(false, nullptr); } FunctionPass *llvm::createMipsSEISelDag(MipsTargetMachine &TM) { diff --git a/lib/Target/Mips/MipsSEISelDAGToDAG.h b/lib/Target/Mips/MipsSEISelDAGToDAG.h index dc52064c9830..57328d2f9270 100644 --- a/lib/Target/Mips/MipsSEISelDAGToDAG.h +++ b/lib/Target/Mips/MipsSEISelDAGToDAG.h @@ -25,7 +25,7 @@ public: private: - virtual bool runOnMachineFunction(MachineFunction &MF); + bool runOnMachineFunction(MachineFunction &MF) override; void addDSPCtrlRegOperands(bool IsDef, MachineInstr &MI, MachineFunction &MF); @@ -40,60 +40,70 @@ private: SDNode *selectAddESubE(unsigned MOp, SDValue InFlag, SDValue CmpLHS, SDLoc DL, SDNode *Node) const; - virtual bool selectAddrRegImm(SDValue Addr, SDValue &Base, - SDValue &Offset) const; + bool selectAddrFrameIndex(SDValue Addr, SDValue &Base, SDValue &Offset) const; + bool selectAddrFrameIndexOffset(SDValue Addr, SDValue &Base, SDValue &Offset, + unsigned OffsetBits) const; - virtual bool selectAddrRegReg(SDValue Addr, SDValue &Base, - SDValue &Offset) const; + bool selectAddrRegImm(SDValue Addr, SDValue &Base, + SDValue &Offset) const override; - virtual bool selectAddrDefault(SDValue Addr, SDValue &Base, - SDValue &Offset) const; + bool selectAddrRegReg(SDValue Addr, SDValue &Base, + SDValue &Offset) const override; - virtual bool selectIntAddr(SDValue Addr, SDValue &Base, - SDValue &Offset) const; + bool selectAddrDefault(SDValue Addr, SDValue &Base, + SDValue &Offset) const override; - virtual bool selectAddrRegImm12(SDValue Addr, SDValue &Base, - SDValue &Offset) const; + bool selectIntAddr(SDValue Addr, SDValue &Base, + SDValue &Offset) const override; - virtual bool selectIntAddrMM(SDValue Addr, SDValue &Base, - SDValue &Offset) const; + bool selectAddrRegImm10(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + bool selectAddrRegImm12(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + bool selectIntAddrMM(SDValue Addr, SDValue &Base, + SDValue &Offset) const override; + + bool selectIntAddrMSA(SDValue Addr, SDValue &Base, + SDValue &Offset) const override; /// \brief Select constant vector splats. - virtual bool selectVSplat(SDNode *N, APInt &Imm) const; + bool selectVSplat(SDNode *N, APInt &Imm) const override; /// \brief Select constant vector splats whose value fits in a given integer. - virtual bool selectVSplatCommon(SDValue N, SDValue &Imm, bool Signed, + 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; + bool selectVSplatUimm1(SDValue N, SDValue &Imm) const override; /// \brief Select constant vector splats whose value fits in a uimm2. - virtual bool selectVSplatUimm2(SDValue N, SDValue &Imm) const; + bool selectVSplatUimm2(SDValue N, SDValue &Imm) const override; /// \brief Select constant vector splats whose value fits in a uimm3. - virtual bool selectVSplatUimm3(SDValue N, SDValue &Imm) const; + bool selectVSplatUimm3(SDValue N, SDValue &Imm) const override; /// \brief Select constant vector splats whose value fits in a uimm4. - virtual bool selectVSplatUimm4(SDValue N, SDValue &Imm) const; + bool selectVSplatUimm4(SDValue N, SDValue &Imm) const override; /// \brief Select constant vector splats whose value fits in a uimm5. - virtual bool selectVSplatUimm5(SDValue N, SDValue &Imm) const; + bool selectVSplatUimm5(SDValue N, SDValue &Imm) const override; /// \brief Select constant vector splats whose value fits in a uimm6. - virtual bool selectVSplatUimm6(SDValue N, SDValue &Imm) const; + bool selectVSplatUimm6(SDValue N, SDValue &Imm) const override; /// \brief Select constant vector splats whose value fits in a uimm8. - virtual bool selectVSplatUimm8(SDValue N, SDValue &Imm) const; + bool selectVSplatUimm8(SDValue N, SDValue &Imm) const override; /// \brief Select constant vector splats whose value fits in a simm5. - virtual bool selectVSplatSimm5(SDValue N, SDValue &Imm) const; + bool selectVSplatSimm5(SDValue N, SDValue &Imm) const override; /// \brief Select constant vector splats whose value is a power of 2. - virtual bool selectVSplatUimmPow2(SDValue N, SDValue &Imm) const; + bool selectVSplatUimmPow2(SDValue N, SDValue &Imm) const override; /// \brief Select constant vector splats whose value is the inverse of a /// power of 2. - virtual bool selectVSplatUimmInvPow2(SDValue N, SDValue &Imm) const; + bool selectVSplatUimmInvPow2(SDValue N, SDValue &Imm) const override; /// \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; + bool selectVSplatMaskL(SDValue N, SDValue &Imm) const override; /// \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; + bool selectVSplatMaskR(SDValue N, SDValue &Imm) const override; - virtual std::pair<bool, SDNode*> selectNode(SDNode *Node); + std::pair<bool, SDNode*> selectNode(SDNode *Node) override; - virtual void processFunctionAfterISel(MachineFunction &MF); + void processFunctionAfterISel(MachineFunction &MF) override; // Insert instructions to initialize the global base register in the // first MBB of the function. diff --git a/lib/Target/Mips/MipsSEISelLowering.cpp b/lib/Target/Mips/MipsSEISelLowering.cpp index 809adc03b151..8173615cdcb5 100644 --- a/lib/Target/Mips/MipsSEISelLowering.cpp +++ b/lib/Target/Mips/MipsSEISelLowering.cpp @@ -10,7 +10,6 @@ // Subclass of MipsTargetLowering specialized for mips32/64. // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "mips-isel" #include "MipsSEISelLowering.h" #include "MipsRegisterInfo.h" #include "MipsTargetMachine.h" @@ -24,6 +23,8 @@ using namespace llvm; +#define DEBUG_TYPE "mips-isel" + static cl::opt<bool> EnableMipsTailCalls("enable-mips-tail-calls", cl::Hidden, cl::desc("MIPS: Enable tail calls."), cl::init(false)); @@ -33,15 +34,16 @@ static cl::opt<bool> NoDPLoadStore("mno-ldc1-sdc1", cl::init(false), "stores to their single precision " "counterparts")); -MipsSETargetLowering::MipsSETargetLowering(MipsTargetMachine &TM) - : MipsTargetLowering(TM) { +MipsSETargetLowering::MipsSETargetLowering(MipsTargetMachine &TM, + const MipsSubtarget &STI) + : MipsTargetLowering(TM, STI) { // Set up the register classes addRegisterClass(MVT::i32, &Mips::GPR32RegClass); - if (HasMips64) + if (Subtarget.isGP64bit()) addRegisterClass(MVT::i64, &Mips::GPR64RegClass); - if (Subtarget->hasDSP() || Subtarget->hasMSA()) { + 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; @@ -57,7 +59,7 @@ MipsSETargetLowering::MipsSETargetLowering(MipsTargetMachine &TM) } } - if (Subtarget->hasDSP()) { + if (Subtarget.hasDSP()) { MVT::SimpleValueType VecTys[2] = {MVT::v2i16, MVT::v4i8}; for (unsigned i = 0; i < array_lengthof(VecTys); ++i) { @@ -81,10 +83,10 @@ MipsSETargetLowering::MipsSETargetLowering(MipsTargetMachine &TM) setTargetDAGCombine(ISD::VSELECT); } - if (Subtarget->hasDSPR2()) + if (Subtarget.hasDSPR2()) setOperationAction(ISD::MUL, MVT::v2i16, Legal); - if (Subtarget->hasMSA()) { + if (Subtarget.hasMSA()) { addMSAIntType(MVT::v16i8, &Mips::MSA128BRegClass); addMSAIntType(MVT::v8i16, &Mips::MSA128HRegClass); addMSAIntType(MVT::v4i32, &Mips::MSA128WRegClass); @@ -100,12 +102,12 @@ MipsSETargetLowering::MipsSETargetLowering(MipsTargetMachine &TM) setTargetDAGCombine(ISD::XOR); } - if (!Subtarget->mipsSEUsesSoftFloat()) { + if (!Subtarget.abiUsesSoftFloat()) { addRegisterClass(MVT::f32, &Mips::FGR32RegClass); // When dealing with single precision only, use libcalls - if (!Subtarget->isSingleFloat()) { - if (Subtarget->isFP64bit()) + if (!Subtarget.isSingleFloat()) { + if (Subtarget.isFP64bit()) addRegisterClass(MVT::f64, &Mips::FGR64RegClass); else addRegisterClass(MVT::f64, &Mips::AFGR64RegClass); @@ -117,10 +119,14 @@ MipsSETargetLowering::MipsSETargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::MULHS, MVT::i32, Custom); setOperationAction(ISD::MULHU, MVT::i32, Custom); - if (HasMips64) { + if (Subtarget.hasCnMips()) + setOperationAction(ISD::MUL, MVT::i64, Legal); + else if (Subtarget.isGP64bit()) + setOperationAction(ISD::MUL, MVT::i64, Custom); + + if (Subtarget.isGP64bit()) { 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); @@ -147,12 +153,91 @@ MipsSETargetLowering::MipsSETargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::STORE, MVT::f64, Custom); } + if (Subtarget.hasMips32r6()) { + // MIPS32r6 replaces the accumulator-based multiplies with a three register + // instruction + setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::MUL, MVT::i32, Legal); + setOperationAction(ISD::MULHS, MVT::i32, Legal); + setOperationAction(ISD::MULHU, MVT::i32, Legal); + + // MIPS32r6 replaces the accumulator-based division/remainder with separate + // three register division and remainder instructions. + setOperationAction(ISD::SDIVREM, MVT::i32, Expand); + setOperationAction(ISD::UDIVREM, MVT::i32, Expand); + setOperationAction(ISD::SDIV, MVT::i32, Legal); + setOperationAction(ISD::UDIV, MVT::i32, Legal); + setOperationAction(ISD::SREM, MVT::i32, Legal); + setOperationAction(ISD::UREM, MVT::i32, Legal); + + // MIPS32r6 replaces conditional moves with an equivalent that removes the + // need for three GPR read ports. + setOperationAction(ISD::SETCC, MVT::i32, Legal); + setOperationAction(ISD::SELECT, MVT::i32, Legal); + setOperationAction(ISD::SELECT_CC, MVT::i32, Expand); + + setOperationAction(ISD::SETCC, MVT::f32, Legal); + setOperationAction(ISD::SELECT, MVT::f32, Legal); + setOperationAction(ISD::SELECT_CC, MVT::f32, Expand); + + assert(Subtarget.isFP64bit() && "FR=1 is required for MIPS32r6"); + setOperationAction(ISD::SETCC, MVT::f64, Legal); + setOperationAction(ISD::SELECT, MVT::f64, Legal); + setOperationAction(ISD::SELECT_CC, MVT::f64, Expand); + + setOperationAction(ISD::BRCOND, MVT::Other, Legal); + + // Floating point > and >= are supported via < and <= + setCondCodeAction(ISD::SETOGE, MVT::f32, Expand); + setCondCodeAction(ISD::SETOGT, MVT::f32, Expand); + setCondCodeAction(ISD::SETUGE, MVT::f32, Expand); + setCondCodeAction(ISD::SETUGT, MVT::f32, Expand); + + setCondCodeAction(ISD::SETOGE, MVT::f64, Expand); + setCondCodeAction(ISD::SETOGT, MVT::f64, Expand); + setCondCodeAction(ISD::SETUGE, MVT::f64, Expand); + setCondCodeAction(ISD::SETUGT, MVT::f64, Expand); + } + + if (Subtarget.hasMips64r6()) { + // MIPS64r6 replaces the accumulator-based multiplies with a three register + // instruction + setOperationAction(ISD::MUL, MVT::i64, Legal); + setOperationAction(ISD::MULHS, MVT::i64, Legal); + setOperationAction(ISD::MULHU, MVT::i64, Legal); + + // MIPS32r6 replaces the accumulator-based division/remainder with separate + // three register division and remainder instructions. + setOperationAction(ISD::SDIVREM, MVT::i64, Expand); + setOperationAction(ISD::UDIVREM, MVT::i64, Expand); + setOperationAction(ISD::SDIV, MVT::i64, Legal); + setOperationAction(ISD::UDIV, MVT::i64, Legal); + setOperationAction(ISD::SREM, MVT::i64, Legal); + setOperationAction(ISD::UREM, MVT::i64, Legal); + + // MIPS64r6 replaces conditional moves with an equivalent that removes the + // need for three GPR read ports. + setOperationAction(ISD::SETCC, MVT::i64, Legal); + setOperationAction(ISD::SELECT, MVT::i64, Legal); + setOperationAction(ISD::SELECT_CC, MVT::i64, Expand); + } + computeRegisterProperties(); } const MipsTargetLowering * -llvm::createMipsSETargetLowering(MipsTargetMachine &TM) { - return new MipsSETargetLowering(TM); +llvm::createMipsSETargetLowering(MipsTargetMachine &TM, + const MipsSubtarget &STI) { + return new MipsSETargetLowering(TM, STI); +} + +const TargetRegisterClass * +MipsSETargetLowering::getRepRegClassFor(MVT VT) const { + if (VT == MVT::Untyped) + return Subtarget.hasDSP() ? &Mips::ACC64DSPRegClass : &Mips::ACC64RegClass; + + return TargetLowering::getRepRegClassFor(VT); } // Enable MSA support for the given integer type and Register class. @@ -244,9 +329,21 @@ addMSAFloatType(MVT::SimpleValueType Ty, const TargetRegisterClass *RC) { } bool -MipsSETargetLowering::allowsUnalignedMemoryAccesses(EVT VT, bool *Fast) const { +MipsSETargetLowering::allowsUnalignedMemoryAccesses(EVT VT, + unsigned, + bool *Fast) const { MVT::SimpleValueType SVT = VT.getSimpleVT().SimpleTy; + if (Subtarget.systemSupportsUnalignedAccess()) { + // MIPS32r6/MIPS64r6 is required to support unaligned access. It's + // implementation defined whether this is handled by hardware, software, or + // a hybrid of the two but it's expected that most implementations will + // handle the majority of cases in hardware. + if (Fast) + *Fast = true; + return true; + } + switch (SVT) { case MVT::i64: case MVT::i32: @@ -428,12 +525,12 @@ static bool selectMSUB(SDNode *SUBENode, SelectionDAG *CurDAG) { static SDValue performADDECombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, - const MipsSubtarget *Subtarget) { + const MipsSubtarget &Subtarget) { if (DCI.isBeforeLegalize()) return SDValue(); - if (Subtarget->hasMips32() && N->getValueType(0) == MVT::i32 && - selectMADD(N, &DAG)) + if (Subtarget.hasMips32() && !Subtarget.hasMips32r6() && + N->getValueType(0) == MVT::i32 && selectMADD(N, &DAG)) return SDValue(N, 0); return SDValue(); @@ -448,8 +545,8 @@ static SDValue performADDECombine(SDNode *N, SelectionDAG &DAG, // - 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()) + const MipsSubtarget &Subtarget) { + if (!Subtarget.hasMSA()) return SDValue(); SDValue Op0 = N->getOperand(0); @@ -481,7 +578,8 @@ static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG, Log2 == ExtendTySize) { SDValue Ops[] = { Op0->getOperand(0), Op0->getOperand(1), Op0Op2 }; DAG.MorphNodeTo(Op0.getNode(), MipsISD::VEXTRACT_ZEXT_ELT, - Op0->getVTList(), Ops, Op0->getNumOperands()); + Op0->getVTList(), + makeArrayRef(Ops, Op0->getNumOperands())); return Op0; } } @@ -501,7 +599,7 @@ static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG, static bool isVSplat(SDValue N, APInt &Imm, bool IsLittleEndian) { BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N.getNode()); - if (Node == NULL) + if (!Node) return false; APInt SplatValue, SplatUndef; @@ -563,8 +661,8 @@ static bool isBitwiseInverse(SDValue N, SDValue OfNode) { // vector type. static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, - const MipsSubtarget *Subtarget) { - if (!Subtarget->hasMSA()) + const MipsSubtarget &Subtarget) { + if (!Subtarget.hasMSA()) return SDValue(); EVT Ty = N->getValueType(0); @@ -580,7 +678,7 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, SDValue Op0Op1 = Op0->getOperand(1); SDValue Op1Op0 = Op1->getOperand(0); SDValue Op1Op1 = Op1->getOperand(1); - bool IsLittleEndian = !Subtarget->isLittle(); + bool IsLittleEndian = !Subtarget.isLittle(); SDValue IfSet, IfClr, Cond; bool IsConstantMask = false; @@ -675,7 +773,7 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, } // Transform the DAG into an equivalent VSELECT. - return DAG.getNode(ISD::VSELECT, SDLoc(N), Ty, Cond, IfClr, IfSet); + return DAG.getNode(ISD::VSELECT, SDLoc(N), Ty, Cond, IfSet, IfClr); } return SDValue(); @@ -683,11 +781,11 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, static SDValue performSUBECombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, - const MipsSubtarget *Subtarget) { + const MipsSubtarget &Subtarget) { if (DCI.isBeforeLegalize()) return SDValue(); - if (Subtarget->hasMips32() && N->getValueType(0) == MVT::i32 && + if (Subtarget.hasMips32() && N->getValueType(0) == MVT::i32 && selectMSUB(N, &DAG)) return SDValue(N, 0); @@ -747,7 +845,7 @@ static SDValue performMULCombine(SDNode *N, SelectionDAG &DAG, static SDValue performDSPShiftCombine(unsigned Opc, SDNode *N, EVT Ty, SelectionDAG &DAG, - const MipsSubtarget *Subtarget) { + const MipsSubtarget &Subtarget) { // See if this is a vector splat immediate node. APInt SplatValue, SplatUndef; unsigned SplatBitSize; @@ -755,12 +853,12 @@ static SDValue performDSPShiftCombine(unsigned Opc, SDNode *N, EVT Ty, unsigned EltSize = Ty.getVectorElementType().getSizeInBits(); BuildVectorSDNode *BV = dyn_cast<BuildVectorSDNode>(N->getOperand(1)); - if (!Subtarget->hasDSP()) + if (!Subtarget.hasDSP()) return SDValue(); if (!BV || !BV->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs, - EltSize, !Subtarget->isLittle()) || + EltSize, !Subtarget.isLittle()) || (SplatBitSize != EltSize) || (SplatValue.getZExtValue() >= EltSize)) return SDValue(); @@ -771,7 +869,7 @@ static SDValue performDSPShiftCombine(unsigned Opc, SDNode *N, EVT Ty, static SDValue performSHLCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, - const MipsSubtarget *Subtarget) { + const MipsSubtarget &Subtarget) { EVT Ty = N->getValueType(0); if ((Ty != MVT::v2i16) && (Ty != MVT::v4i8)) @@ -794,10 +892,10 @@ static SDValue performSHLCombine(SDNode *N, SelectionDAG &DAG, // used for DSPr2. static SDValue performSRACombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, - const MipsSubtarget *Subtarget) { + const MipsSubtarget &Subtarget) { EVT Ty = N->getValueType(0); - if (Subtarget->hasMSA()) { + if (Subtarget.hasMSA()) { SDValue Op0 = N->getOperand(0); SDValue Op1 = N->getOperand(1); @@ -825,13 +923,14 @@ static SDValue performSRACombine(SDNode *N, SelectionDAG &DAG, SDValue Ops[] = { Op0Op0->getOperand(0), Op0Op0->getOperand(1), Op0Op0->getOperand(2) }; DAG.MorphNodeTo(Op0Op0.getNode(), MipsISD::VEXTRACT_SEXT_ELT, - Op0Op0->getVTList(), Ops, Op0Op0->getNumOperands()); + Op0Op0->getVTList(), + makeArrayRef(Ops, Op0Op0->getNumOperands())); return Op0Op0; } } } - if ((Ty != MVT::v2i16) && ((Ty != MVT::v4i8) || !Subtarget->hasDSPR2())) + if ((Ty != MVT::v2i16) && ((Ty != MVT::v4i8) || !Subtarget.hasDSPR2())) return SDValue(); return performDSPShiftCombine(MipsISD::SHRA_DSP, N, Ty, DAG, Subtarget); @@ -840,10 +939,10 @@ static SDValue performSRACombine(SDNode *N, SelectionDAG &DAG, static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, - const MipsSubtarget *Subtarget) { + const MipsSubtarget &Subtarget) { EVT Ty = N->getValueType(0); - if (((Ty != MVT::v2i16) || !Subtarget->hasDSPR2()) && (Ty != MVT::v4i8)) + if (((Ty != MVT::v2i16) || !Subtarget.hasDSPR2()) && (Ty != MVT::v4i8)) return SDValue(); return performDSPShiftCombine(MipsISD::SHRL_DSP, N, Ty, DAG, Subtarget); @@ -937,10 +1036,10 @@ static SDValue performVSELECTCombine(SDNode *N, SelectionDAG &DAG) { } static SDValue performXORCombine(SDNode *N, SelectionDAG &DAG, - const MipsSubtarget *Subtarget) { + const MipsSubtarget &Subtarget) { EVT Ty = N->getValueType(0); - if (Subtarget->hasMSA() && Ty.is128BitVector() && Ty.isInteger()) { + 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))) @@ -1045,6 +1144,18 @@ MipsSETargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, return emitINSERT_FW(MI, BB); case Mips::INSERT_FD_PSEUDO: return emitINSERT_FD(MI, BB); + case Mips::INSERT_B_VIDX_PSEUDO: + return emitINSERT_DF_VIDX(MI, BB, 1, false); + case Mips::INSERT_H_VIDX_PSEUDO: + return emitINSERT_DF_VIDX(MI, BB, 2, false); + case Mips::INSERT_W_VIDX_PSEUDO: + return emitINSERT_DF_VIDX(MI, BB, 4, false); + case Mips::INSERT_D_VIDX_PSEUDO: + return emitINSERT_DF_VIDX(MI, BB, 8, false); + case Mips::INSERT_FW_VIDX_PSEUDO: + return emitINSERT_DF_VIDX(MI, BB, 4, true); + case Mips::INSERT_FD_VIDX_PSEUDO: + return emitINSERT_DF_VIDX(MI, BB, 8, true); case Mips::FILL_FW_PSEUDO: return emitFILL_FW(MI, BB); case Mips::FILL_FD_PSEUDO: @@ -1077,14 +1188,7 @@ 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); - + Ops.push_back(Callee); MipsTargetLowering::getOpndList(Ops, RegsToPass, IsPICCall, GlobalOrExternal, InternalLinkage, CLI, Callee, Chain); } @@ -1113,12 +1217,12 @@ SDValue MipsSETargetLowering::lowerLOAD(SDValue Op, SelectionDAG &DAG) const { Nd.isNonTemporal(), Nd.isInvariant(), std::min(Nd.getAlignment(), 4U)); - if (!Subtarget->isLittle()) + 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); + return DAG.getMergeValues(Ops, DL); } SDValue MipsSETargetLowering::lowerSTORE(SDValue Op, SelectionDAG &DAG) const { @@ -1136,7 +1240,7 @@ SDValue MipsSETargetLowering::lowerSTORE(SDValue Op, SelectionDAG &DAG) const { SDValue Hi = DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, Val, DAG.getConstant(1, MVT::i32)); - if (!Subtarget->isLittle()) + if (!Subtarget.isLittle()) std::swap(Lo, Hi); // i32 store to lower address. @@ -1154,6 +1258,9 @@ SDValue MipsSETargetLowering::lowerSTORE(SDValue Op, SelectionDAG &DAG) const { SDValue MipsSETargetLowering::lowerMulDiv(SDValue Op, unsigned NewOpc, bool HasLo, bool HasHi, SelectionDAG &DAG) const { + // MIPS32r6/MIPS64r6 removed accumulator based multiplies. + assert(!Subtarget.hasMips32r6()); + EVT Ty = Op.getOperand(0).getValueType(); SDLoc DL(Op); SDValue Mult = DAG.getNode(NewOpc, DL, MVT::Untyped, @@ -1169,7 +1276,7 @@ SDValue MipsSETargetLowering::lowerMulDiv(SDValue Op, unsigned NewOpc, return HasLo ? Lo : Hi; SDValue Vals[] = { Lo, Hi }; - return DAG.getMergeValues(Vals, 2, DL); + return DAG.getMergeValues(Vals, DL); } @@ -1236,7 +1343,7 @@ static SDValue lowerDSPIntr(SDValue Op, SelectionDAG &DAG, unsigned Opc) { ResTys.push_back((*I == MVT::i64) ? MVT::Untyped : *I); // Create node. - SDValue Val = DAG.getNode(Opc, DL, ResTys, &Ops[0], Ops.size()); + SDValue Val = DAG.getNode(Opc, DL, ResTys, Ops); SDValue Out = (ResTys[0] == MVT::Untyped) ? extractLOHI(Val, DL, DAG) : Val; if (!HasChainIn) @@ -1244,7 +1351,7 @@ static SDValue lowerDSPIntr(SDValue Op, SelectionDAG &DAG, unsigned Opc) { assert(Val->getValueType(1) == MVT::Other); SDValue Vals[] = { Out, SDValue(Val.getNode(), 1) }; - return DAG.getMergeValues(Vals, 2, DL); + return DAG.getMergeValues(Vals, DL); } // Lower an MSA copy intrinsic into the specified SelectionDAG node @@ -1281,8 +1388,8 @@ static SDValue lowerMSASplatZExt(SDValue Op, unsigned OpNr, SelectionDAG &DAG) { 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()); + SDValue Result = DAG.getNode(ISD::BUILD_VECTOR, DL, ViaVecTy, + makeArrayRef(Ops, ViaVecTy.getVectorNumElements())); if (ViaVecTy != ResVecTy) Result = DAG.getNode(ISD::BITCAST, DL, ResVecTy, Result); @@ -1321,8 +1428,8 @@ static SDValue getBuildVectorSplat(EVT VecTy, SDValue SplatValue, SplatValueA, SplatValueB, SplatValueA, SplatValueB, SplatValueA, SplatValueB, SplatValueA, SplatValueB }; - SDValue Result = DAG.getNode(ISD::BUILD_VECTOR, DL, ViaVecTy, Ops, - ViaVecTy.getVectorNumElements()); + SDValue Result = DAG.getNode(ISD::BUILD_VECTOR, DL, ViaVecTy, + makeArrayRef(Ops, ViaVecTy.getVectorNumElements())); if (VecTy != ViaVecTy) Result = DAG.getNode(ISD::BITCAST, DL, VecTy, Result); @@ -1356,7 +1463,7 @@ static SDValue lowerMSABinaryBitImmIntr(SDValue Op, SelectionDAG &DAG, } } - if (Exp2Imm.getNode() == NULL) { + if (!Exp2Imm.getNode()) { // We couldnt constant fold, do a vector shift instead // Extend i32 to i64 if necessary. Sign or zero extend doesn't matter since @@ -1464,25 +1571,27 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, case Intrinsic::mips_binsli_h: case Intrinsic::mips_binsli_w: case Intrinsic::mips_binsli_d: { + // binsli_x(IfClear, IfSet, nbits) -> (vselect LBitsMask, IfSet, IfClear) 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)); + DAG.getConstant(Mask, VecTy, true), Op->getOperand(2), + Op->getOperand(1)); } case Intrinsic::mips_binsri_b: case Intrinsic::mips_binsri_h: case Intrinsic::mips_binsri_w: case Intrinsic::mips_binsri_d: { + // binsri_x(IfClear, IfSet, nbits) -> (vselect RBitsMask, IfSet, IfClear) 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)); + DAG.getConstant(Mask, VecTy, true), Op->getOperand(2), + Op->getOperand(1)); } case Intrinsic::mips_bmnz_v: return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0), Op->getOperand(3), @@ -1514,7 +1623,7 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, case Intrinsic::mips_bnegi_w: case Intrinsic::mips_bnegi_d: return lowerMSABinaryBitImmIntr(Op, DAG, ISD::XOR, Op->getOperand(2), - !Subtarget->isLittle()); + !Subtarget.isLittle()); case Intrinsic::mips_bnz_b: case Intrinsic::mips_bnz_h: case Intrinsic::mips_bnz_w: @@ -1525,13 +1634,15 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, return DAG.getNode(MipsISD::VANY_NONZERO, DL, Op->getValueType(0), Op->getOperand(1)); case Intrinsic::mips_bsel_v: + // bsel_v(Mask, IfClear, IfSet) -> (vselect Mask, IfSet, IfClear) return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0), - Op->getOperand(1), Op->getOperand(2), - Op->getOperand(3)); + Op->getOperand(1), Op->getOperand(3), + Op->getOperand(2)); case Intrinsic::mips_bseli_b: + // bseli_v(Mask, IfClear, IfSet) -> (vselect Mask, IfSet, IfClear) return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0), - Op->getOperand(1), Op->getOperand(2), - lowerMSASplatImm(Op, 3, DAG)); + Op->getOperand(1), lowerMSASplatImm(Op, 3, DAG), + Op->getOperand(2)); case Intrinsic::mips_bset_b: case Intrinsic::mips_bset_h: case Intrinsic::mips_bset_w: @@ -1548,7 +1659,7 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, case Intrinsic::mips_bseti_w: case Intrinsic::mips_bseti_d: return lowerMSABinaryBitImmIntr(Op, DAG, ISD::OR, Op->getOperand(2), - !Subtarget->isLittle()); + !Subtarget.isLittle()); case Intrinsic::mips_bz_b: case Intrinsic::mips_bz_h: case Intrinsic::mips_bz_w: @@ -1623,25 +1734,34 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, 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)); + if (Subtarget.hasMips64()) + // Lower directly into VEXTRACT_SEXT_ELT since i64 is legal on Mips64. + return lowerMSACopyIntr(Op, DAG, MipsISD::VEXTRACT_SEXT_ELT); + else { + // Lower into 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)); + if (Subtarget.hasMips64()) + // Lower directly into VEXTRACT_ZEXT_ELT since i64 is legal on Mips64. + return lowerMSACopyIntr(Op, DAG, MipsISD::VEXTRACT_ZEXT_ELT); + else { + // Lower into 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: @@ -1723,7 +1843,7 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, // 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()); + return DAG.getNode(ISD::BUILD_VECTOR, DL, ResTy, Ops); } case Intrinsic::mips_fexp2_w: case Intrinsic::mips_fexp2_d: { @@ -1798,12 +1918,20 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, 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_insve_b: + case Intrinsic::mips_insve_h: + case Intrinsic::mips_insve_w: + case Intrinsic::mips_insve_d: + return DAG.getNode(MipsISD::INSVE, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2), Op->getOperand(3), + DAG.getConstant(0, MVT::i32)); 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: { + case Intrinsic::mips_lsa: + case Intrinsic::mips_dlsa: { EVT ResTy = Op->getValueType(0); return DAG.getNode(ISD::ADD, SDLoc(Op), ResTy, Op->getOperand(1), DAG.getNode(ISD::SHL, SDLoc(Op), ResTy, @@ -2198,12 +2326,12 @@ SDValue MipsSETargetLowering::lowerBUILD_VECTOR(SDValue Op, unsigned SplatBitSize; bool HasAnyUndefs; - if (!Subtarget->hasMSA() || !ResTy.is128BitVector()) + if (!Subtarget.hasMSA() || !ResTy.is128BitVector()) return SDValue(); if (Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs, 8, - !Subtarget->isLittle()) && SplatBitSize <= 64) { + !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) @@ -2540,8 +2668,7 @@ static SDValue lowerVECTOR_SHUFFLE_VSHF(SDValue Op, EVT ResTy, ++I) Ops.push_back(DAG.getTargetConstant(*I, MaskEltTy)); - SDValue MaskVec = DAG.getNode(ISD::BUILD_VECTOR, DL, MaskVecTy, &Ops[0], - Ops.size()); + SDValue MaskVec = DAG.getNode(ISD::BUILD_VECTOR, DL, MaskVecTy, Ops); if (Using1stVec && Using2ndVec) { Op0 = Op->getOperand(0); @@ -2553,7 +2680,14 @@ static SDValue lowerVECTOR_SHUFFLE_VSHF(SDValue Op, EVT ResTy, else llvm_unreachable("shuffle vector mask references neither vector operand?"); - return DAG.getNode(MipsISD::VSHF, DL, ResTy, MaskVec, Op0, Op1); + // VECTOR_SHUFFLE concatenates the vectors in an vectorwise fashion. + // <0b00, 0b01> + <0b10, 0b11> -> <0b00, 0b01, 0b10, 0b11> + // VSHF concatenates the vectors in a bitwise fashion: + // <0b00, 0b01> + <0b10, 0b11> -> + // 0b0100 + 0b1110 -> 0b01001110 + // <0b10, 0b11, 0b00, 0b01> + // We must therefore swap the operands to get the correct result. + return DAG.getNode(MipsISD::VSHF, DL, ResTy, MaskVec, Op1, Op0); } // Lower VECTOR_SHUFFLE into one of a number of instructions depending on the @@ -2616,7 +2750,7 @@ emitBPOSGE32(MachineInstr *MI, MachineBasicBlock *BB) const{ const TargetRegisterClass *RC = &Mips::GPR32RegClass; DebugLoc DL = MI->getDebugLoc(); const BasicBlock *LLVM_BB = BB->getBasicBlock(); - MachineFunction::iterator It = llvm::next(MachineFunction::iterator(BB)); + MachineFunction::iterator It = std::next(MachineFunction::iterator(BB)); MachineFunction *F = BB->getParent(); MachineBasicBlock *FBB = F->CreateMachineBasicBlock(LLVM_BB); MachineBasicBlock *TBB = F->CreateMachineBasicBlock(LLVM_BB); @@ -2626,7 +2760,7 @@ emitBPOSGE32(MachineInstr *MI, MachineBasicBlock *BB) const{ 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)), + Sink->splice(Sink->begin(), BB, std::next(MachineBasicBlock::iterator(MI)), BB->end()); Sink->transferSuccessorsAndUpdatePHIs(BB); @@ -2681,7 +2815,7 @@ emitMSACBranchPseudo(MachineInstr *MI, MachineBasicBlock *BB, const TargetRegisterClass *RC = &Mips::GPR32RegClass; DebugLoc DL = MI->getDebugLoc(); const BasicBlock *LLVM_BB = BB->getBasicBlock(); - MachineFunction::iterator It = llvm::next(MachineFunction::iterator(BB)); + MachineFunction::iterator It = std::next(MachineFunction::iterator(BB)); MachineFunction *F = BB->getParent(); MachineBasicBlock *FBB = F->CreateMachineBasicBlock(LLVM_BB); MachineBasicBlock *TBB = F->CreateMachineBasicBlock(LLVM_BB); @@ -2691,7 +2825,7 @@ emitMSACBranchPseudo(MachineInstr *MI, MachineBasicBlock *BB, 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)), + Sink->splice(Sink->begin(), BB, std::next(MachineBasicBlock::iterator(MI)), BB->end()); Sink->transferSuccessorsAndUpdatePHIs(BB); @@ -2750,7 +2884,7 @@ emitCOPY_FW(MachineInstr *MI, MachineBasicBlock *BB) const{ 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::SPLATI_W), Wt).addReg(Ws).addImm(Lane); BuildMI(*BB, MI, DL, TII->get(Mips::COPY), Fd).addReg(Wt, 0, Mips::sub_lo); } @@ -2770,7 +2904,7 @@ emitCOPY_FW(MachineInstr *MI, MachineBasicBlock *BB) const{ // 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()); + assert(Subtarget.isFP64bit()); const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); @@ -2817,7 +2951,8 @@ MipsSETargetLowering::emitINSERT_FW(MachineInstr *MI, BuildMI(*BB, MI, DL, TII->get(Mips::INSVE_W), Wd) .addReg(Wd_in) .addImm(Lane) - .addReg(Wt); + .addReg(Wt) + .addImm(0); MI->eraseFromParent(); // The pseudo instruction is gone now. return BB; @@ -2832,7 +2967,7 @@ MipsSETargetLowering::emitINSERT_FW(MachineInstr *MI, MachineBasicBlock * MipsSETargetLowering::emitINSERT_FD(MachineInstr *MI, MachineBasicBlock *BB) const { - assert(Subtarget->isFP64bit()); + assert(Subtarget.isFP64bit()); const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); @@ -2850,7 +2985,133 @@ MipsSETargetLowering::emitINSERT_FD(MachineInstr *MI, BuildMI(*BB, MI, DL, TII->get(Mips::INSVE_D), Wd) .addReg(Wd_in) .addImm(Lane) - .addReg(Wt); + .addReg(Wt) + .addImm(0); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +// Emit the INSERT_([BHWD]|F[WD])_VIDX pseudo instruction. +// +// For integer: +// (INSERT_([BHWD]|F[WD])_PSEUDO $wd, $wd_in, $n, $rs) +// => +// (SLL $lanetmp1, $lane, <log2size) +// (SLD_B $wdtmp1, $wd_in, $wd_in, $lanetmp1) +// (INSERT_[BHWD], $wdtmp2, $wdtmp1, 0, $rs) +// (NEG $lanetmp2, $lanetmp1) +// (SLD_B $wd, $wdtmp2, $wdtmp2, $lanetmp2) +// +// For floating point: +// (INSERT_([BHWD]|F[WD])_PSEUDO $wd, $wd_in, $n, $fs) +// => +// (SUBREG_TO_REG $wt, $fs, <subreg>) +// (SLL $lanetmp1, $lane, <log2size) +// (SLD_B $wdtmp1, $wd_in, $wd_in, $lanetmp1) +// (INSVE_[WD], $wdtmp2, 0, $wdtmp1, 0) +// (NEG $lanetmp2, $lanetmp1) +// (SLD_B $wd, $wdtmp2, $wdtmp2, $lanetmp2) +MachineBasicBlock * +MipsSETargetLowering::emitINSERT_DF_VIDX(MachineInstr *MI, + MachineBasicBlock *BB, + unsigned EltSizeInBytes, + bool IsFP) const { + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + DebugLoc DL = MI->getDebugLoc(); + unsigned Wd = MI->getOperand(0).getReg(); + unsigned SrcVecReg = MI->getOperand(1).getReg(); + unsigned LaneReg = MI->getOperand(2).getReg(); + unsigned SrcValReg = MI->getOperand(3).getReg(); + + const TargetRegisterClass *VecRC = nullptr; + const TargetRegisterClass *GPRRC = + Subtarget.isGP64bit() ? &Mips::GPR64RegClass : &Mips::GPR32RegClass; + unsigned EltLog2Size; + unsigned InsertOp = 0; + unsigned InsveOp = 0; + switch (EltSizeInBytes) { + default: + llvm_unreachable("Unexpected size"); + case 1: + EltLog2Size = 0; + InsertOp = Mips::INSERT_B; + InsveOp = Mips::INSVE_B; + VecRC = &Mips::MSA128BRegClass; + break; + case 2: + EltLog2Size = 1; + InsertOp = Mips::INSERT_H; + InsveOp = Mips::INSVE_H; + VecRC = &Mips::MSA128HRegClass; + break; + case 4: + EltLog2Size = 2; + InsertOp = Mips::INSERT_W; + InsveOp = Mips::INSVE_W; + VecRC = &Mips::MSA128WRegClass; + break; + case 8: + EltLog2Size = 3; + InsertOp = Mips::INSERT_D; + InsveOp = Mips::INSVE_D; + VecRC = &Mips::MSA128DRegClass; + break; + } + + if (IsFP) { + unsigned Wt = RegInfo.createVirtualRegister(VecRC); + BuildMI(*BB, MI, DL, TII->get(Mips::SUBREG_TO_REG), Wt) + .addImm(0) + .addReg(SrcValReg) + .addImm(EltSizeInBytes == 8 ? Mips::sub_64 : Mips::sub_lo); + SrcValReg = Wt; + } + + // Convert the lane index into a byte index + if (EltSizeInBytes != 1) { + unsigned LaneTmp1 = RegInfo.createVirtualRegister(GPRRC); + BuildMI(*BB, MI, DL, TII->get(Mips::SLL), LaneTmp1) + .addReg(LaneReg) + .addImm(EltLog2Size); + LaneReg = LaneTmp1; + } + + // Rotate bytes around so that the desired lane is element zero + unsigned WdTmp1 = RegInfo.createVirtualRegister(VecRC); + BuildMI(*BB, MI, DL, TII->get(Mips::SLD_B), WdTmp1) + .addReg(SrcVecReg) + .addReg(SrcVecReg) + .addReg(LaneReg); + + unsigned WdTmp2 = RegInfo.createVirtualRegister(VecRC); + if (IsFP) { + // Use insve.df to insert to element zero + BuildMI(*BB, MI, DL, TII->get(InsveOp), WdTmp2) + .addReg(WdTmp1) + .addImm(0) + .addReg(SrcValReg) + .addImm(0); + } else { + // Use insert.df to insert to element zero + BuildMI(*BB, MI, DL, TII->get(InsertOp), WdTmp2) + .addReg(WdTmp1) + .addReg(SrcValReg) + .addImm(0); + } + + // Rotate elements the rest of the way for a full rotation. + // sld.df inteprets $rt modulo the number of columns so we only need to negate + // the lane index to do this. + unsigned LaneTmp2 = RegInfo.createVirtualRegister(GPRRC); + BuildMI(*BB, MI, DL, TII->get(Mips::SUB), LaneTmp2) + .addReg(Mips::ZERO) + .addReg(LaneReg); + BuildMI(*BB, MI, DL, TII->get(Mips::SLD_B), Wd) + .addReg(WdTmp2) + .addReg(WdTmp2) + .addReg(LaneTmp2); MI->eraseFromParent(); // The pseudo instruction is gone now. return BB; @@ -2895,7 +3156,7 @@ MipsSETargetLowering::emitFILL_FW(MachineInstr *MI, MachineBasicBlock * MipsSETargetLowering::emitFILL_FD(MachineInstr *MI, MachineBasicBlock *BB) const { - assert(Subtarget->isFP64bit()); + assert(Subtarget.isFP64bit()); const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); diff --git a/lib/Target/Mips/MipsSEISelLowering.h b/lib/Target/Mips/MipsSEISelLowering.h index c5210d94b34d..00d86834be0a 100644 --- a/lib/Target/Mips/MipsSEISelLowering.h +++ b/lib/Target/Mips/MipsSEISelLowering.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef MipsSEISELLOWERING_H -#define MipsSEISELLOWERING_H +#ifndef MIPSSEISELLOWERING_H +#define MIPSSEISELLOWERING_H #include "MipsISelLowering.h" #include "MipsRegisterInfo.h" @@ -20,7 +20,8 @@ namespace llvm { class MipsSETargetLowering : public MipsTargetLowering { public: - explicit MipsSETargetLowering(MipsTargetMachine &TM); + explicit MipsSETargetLowering(MipsTargetMachine &TM, + const MipsSubtarget &STI); /// \brief Enable MSA support for the given integer type and Register /// class. @@ -30,39 +31,35 @@ namespace llvm { void addMSAFloatType(MVT::SimpleValueType Ty, const TargetRegisterClass *RC); - virtual bool allowsUnalignedMemoryAccesses(EVT VT, bool *Fast) const; + bool allowsUnalignedMemoryAccesses(EVT VT, unsigned AS = 0, + bool *Fast = nullptr) const override; - virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; - virtual SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const; + SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override; - virtual MachineBasicBlock * - EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const; + MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *MBB) const override; - virtual bool isShuffleMaskLegal(const SmallVectorImpl<int> &Mask, - EVT VT) const { + bool isShuffleMaskLegal(const SmallVectorImpl<int> &Mask, + EVT VT) const override { return false; } - virtual const TargetRegisterClass *getRepRegClassFor(MVT VT) const { - if (VT == MVT::Untyped) - return Subtarget->hasDSP() ? &Mips::ACC64DSPRegClass : - &Mips::ACC64RegClass; - - return TargetLowering::getRepRegClassFor(VT); - } + const TargetRegisterClass *getRepRegClassFor(MVT VT) const override; private: - virtual bool - isEligibleForTailCallOptimization(const MipsCC &MipsCCInfo, - unsigned NextStackOffset, - const MipsFunctionInfo& FI) const; + bool isEligibleForTailCallOptimization(const MipsCC &MipsCCInfo, + unsigned NextStackOffset, + const MipsFunctionInfo& FI) const override; - virtual void + 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; + CallLoweringInfo &CLI, SDValue Callee, + SDValue Chain) const override; SDValue lowerLOAD(SDValue Op, SelectionDAG &DAG) const; SDValue lowerSTORE(SDValue Op, SelectionDAG &DAG) const; @@ -96,6 +93,11 @@ namespace llvm { /// \brief Emit the INSERT_FD pseudo instruction MachineBasicBlock *emitINSERT_FD(MachineInstr *MI, MachineBasicBlock *BB) const; + /// \brief Emit the INSERT_([BHWD]|F[WD])_VIDX pseudo instruction + MachineBasicBlock *emitINSERT_DF_VIDX(MachineInstr *MI, + MachineBasicBlock *BB, + unsigned EltSizeInBytes, + bool IsFP) const; /// \brief Emit the FILL_FW pseudo instruction MachineBasicBlock *emitFILL_FW(MachineInstr *MI, MachineBasicBlock *BB) const; diff --git a/lib/Target/Mips/MipsSEInstrInfo.cpp b/lib/Target/Mips/MipsSEInstrInfo.cpp index 02931a3e39ee..69cb74cb1e49 100644 --- a/lib/Target/Mips/MipsSEInstrInfo.cpp +++ b/lib/Target/Mips/MipsSEInstrInfo.cpp @@ -24,11 +24,10 @@ 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()) {} +MipsSEInstrInfo::MipsSEInstrInfo(const MipsSubtarget &STI) + : MipsInstrInfo(STI, STI.getRelocationModel() == Reloc::PIC_ ? Mips::B + : Mips::J), + RI(STI), IsN64(STI.isABI_N64()) {} const MipsRegisterInfo &MipsSEInstrInfo::getRegisterInfo() const { return RI; @@ -84,19 +83,25 @@ void MipsSEInstrInfo::copyPhysReg(MachineBasicBlock &MBB, unsigned DestReg, unsigned SrcReg, bool KillSrc) const { unsigned Opc = 0, ZeroReg = 0; + bool isMicroMips = Subtarget.inMicroMipsMode(); 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)) + if (Mips::GPR32RegClass.contains(SrcReg)) { + if (isMicroMips) + Opc = Mips::MOVE16_MM; + else + 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)) + else if (Mips::HI32RegClass.contains(SrcReg)) { + Opc = isMicroMips ? Mips::MFHI16_MM : Mips::MFHI; + SrcReg = 0; + } else if (Mips::LO32RegClass.contains(SrcReg)) { + Opc = isMicroMips ? Mips::MFLO16_MM : Mips::MFLO; + SrcReg = 0; + } else if (Mips::HI32DSPRegClass.contains(SrcReg)) Opc = Mips::MFHI_DSP; else if (Mips::LO32DSPRegClass.contains(SrcReg)) Opc = Mips::MFLO_DSP; @@ -259,18 +264,22 @@ loadRegFromStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, bool MipsSEInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { MachineBasicBlock &MBB = *MI->getParent(); + bool isMicroMips = Subtarget.inMicroMipsMode(); + unsigned Opc; switch(MI->getDesc().getOpcode()) { default: return false; case Mips::RetRA: - expandRetRA(MBB, MI, Mips::RET); + expandRetRA(MBB, MI); break; case Mips::PseudoMFHI: - expandPseudoMFHiLo(MBB, MI, Mips::MFHI); + Opc = isMicroMips ? Mips::MFHI16_MM : Mips::MFHI; + expandPseudoMFHiLo(MBB, MI, Opc); break; case Mips::PseudoMFLO: - expandPseudoMFHiLo(MBB, MI, Mips::MFLO); + Opc = isMicroMips ? Mips::MFLO16_MM : Mips::MFLO; + expandPseudoMFHiLo(MBB, MI, Opc); break; case Mips::PseudoMFHI64: expandPseudoMFHiLo(MBB, MI, Mips::MFHI64); @@ -350,7 +359,7 @@ unsigned MipsSEInstrInfo::getOppositeBranchOpc(unsigned Opc) const { void MipsSEInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const { - const MipsSubtarget &STI = TM.getSubtarget<MipsSubtarget>(); + const MipsSubtarget &STI = Subtarget; 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; @@ -358,7 +367,7 @@ void MipsSEInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount, 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); + unsigned Reg = loadImmediate(Amount, MBB, I, DL, nullptr); BuildMI(MBB, I, DL, get(ADDu), SP).addReg(SP).addReg(Reg, RegState::Kill); } } @@ -370,7 +379,7 @@ MipsSEInstrInfo::loadImmediate(int64_t Imm, MachineBasicBlock &MBB, MachineBasicBlock::iterator II, DebugLoc DL, unsigned *NewImm) const { MipsAnalyzeImmediate AnalyzeImm; - const MipsSubtarget &STI = TM.getSubtarget<MipsSubtarget>(); + const MipsSubtarget &STI = Subtarget; MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo(); unsigned Size = STI.isABI_N64() ? 64 : 32; unsigned LUi = STI.isABI_N64() ? Mips::LUi64 : Mips::LUi; @@ -418,9 +427,12 @@ unsigned MipsSEInstrInfo::getAnalyzableBrOpc(unsigned Opc) const { } void MipsSEInstrInfo::expandRetRA(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, - unsigned Opc) const { - BuildMI(MBB, I, I->getDebugLoc(), get(Opc)).addReg(Mips::RA); + MachineBasicBlock::iterator I) const { + if (Subtarget.isGP64bit()) + BuildMI(MBB, I, I->getDebugLoc(), get(Mips::PseudoReturn64)) + .addReg(Mips::RA_64); + else + BuildMI(MBB, I, I->getDebugLoc(), get(Mips::PseudoReturn)).addReg(Mips::RA); } std::pair<bool, bool> @@ -481,7 +493,8 @@ void MipsSEInstrInfo::expandCvtFPInt(MachineBasicBlock &MBB, DebugLoc DL = I->getDebugLoc(); bool DstIsLarger, SrcIsLarger; - tie(DstIsLarger, SrcIsLarger) = compareOpndSize(CvtOpc, *MBB.getParent()); + std::tie(DstIsLarger, SrcIsLarger) = + compareOpndSize(CvtOpc, *MBB.getParent()); if (DstIsLarger) TmpReg = getRegisterInfo().getSubReg(DstReg, Mips::sub_lo); @@ -505,9 +518,30 @@ void MipsSEInstrInfo::expandExtractElementF64(MachineBasicBlock &MBB, 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 + // FPXX on MIPS-II or MIPS32r1 should have been handled with a spill/reload + // in MipsSEFrameLowering.cpp. + assert(!(Subtarget.isABI_FPXX() && !Subtarget.hasMips32r2())); + + // FP64A (FP64 with nooddspreg) should have been handled with a spill/reload + // in MipsSEFrameLowering.cpp. + assert(!(Subtarget.isFP64bit() && !Subtarget.useOddSPReg())); + + if (SubIdx == Mips::sub_hi && Subtarget.hasMTHC1()) { + // FIXME: Strictly speaking MFHC1 only reads the top 32-bits however, we + // claim to read the whole 64-bits as part of a white lie used to + // temporarily work around a widespread bug in the -mfp64 support. + // The problem is that none of the 32-bit fpu ops mention the fact + // that they clobber the upper 32-bits of the 64-bit FPR. Fixing that + // requires a major overhaul of the FPU implementation which can't + // be done right now due to time constraints. + // MFHC1 is one of two instructions that are affected since they are + // the only instructions that don't read the lower 32-bits. + // We therefore pretend that it reads the bottom 32-bits to + // artificially create a dependency and prevent the scheduler + // changing the behaviour of the code. + BuildMI(MBB, I, dl, get(FP64 ? Mips::MFHC1_D64 : Mips::MFHC1_D32), DstReg) + .addReg(SrcReg); + } else BuildMI(MBB, I, dl, get(Mips::MFC1), DstReg).addReg(SubReg); } @@ -520,19 +554,49 @@ void MipsSEInstrInfo::expandBuildPairF64(MachineBasicBlock &MBB, DebugLoc dl = I->getDebugLoc(); const TargetRegisterInfo &TRI = getRegisterInfo(); - // For FP32 mode: - // mtc1 Lo, $fp - // mtc1 Hi, $fp + 1 - // For FP64 mode: + // When mthc1 is available, use: // mtc1 Lo, $fp // mthc1 Hi, $fp + // + // Otherwise, for O32 FPXX ABI: + // spill + reload via ldc1 + // This case is handled by the frame lowering code. + // + // Otherwise, for FP32: + // mtc1 Lo, $fp + // mtc1 Hi, $fp + 1 + // + // The case where dmtc1 is available doesn't need to be handled here + // because it never creates a BuildPairF64 node. + + // FPXX on MIPS-II or MIPS32r1 should have been handled with a spill/reload + // in MipsSEFrameLowering.cpp. + assert(!(Subtarget.isABI_FPXX() && !Subtarget.hasMips32r2())); + + // FP64A (FP64 with nooddspreg) should have been handled with a spill/reload + // in MipsSEFrameLowering.cpp. + assert(!(Subtarget.isFP64bit() && !Subtarget.useOddSPReg())); 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); + if (Subtarget.hasMTHC1()) { + // FIXME: The .addReg(DstReg) is a white lie used to temporarily work + // around a widespread bug in the -mfp64 support. + // The problem is that none of the 32-bit fpu ops mention the fact + // that they clobber the upper 32-bits of the 64-bit FPR. Fixing that + // requires a major overhaul of the FPU implementation which can't + // be done right now due to time constraints. + // MTHC1 is one of two instructions that are affected since they are + // the only instructions that don't read the lower 32-bits. + // We therefore pretend that it reads the bottom 32-bits to + // artificially create a dependency and prevent the scheduler + // changing the behaviour of the code. + BuildMI(MBB, I, dl, get(FP64 ? Mips::MTHC1_D64 : Mips::MTHC1_D32), DstReg) + .addReg(DstReg) + .addReg(HiReg); + } else if (Subtarget.isABI_FPXX()) + llvm_unreachable("BuildPairF64 not expanded in frame lowering code!"); else BuildMI(MBB, I, dl, Mtc1Tdd, TRI.getSubReg(DstReg, Mips::sub_hi)) .addReg(HiReg); @@ -543,29 +607,31 @@ void MipsSEInstrInfo::expandEhReturn(MachineBasicBlock &MBB, // 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 ADDU = Subtarget.isABI_N64() ? Mips::DADDu : Mips::ADDu; + unsigned SP = Subtarget.isGP64bit() ? Mips::SP_64 : Mips::SP; + unsigned RA = Subtarget.isGP64bit() ? Mips::RA_64 : Mips::RA; + unsigned T9 = Subtarget.isGP64bit() ? Mips::T9_64 : Mips::T9; + unsigned ZERO = Subtarget.isGP64bit() ? 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 + // jr $ra (via RetRA) + const TargetMachine &TM = MBB.getParent()->getTarget(); if (TM.getRelocationModel() == Reloc::PIC_) BuildMI(MBB, I, I->getDebugLoc(), TM.getInstrInfo()->get(ADDU), T9) - .addReg(TargetReg).addReg(ZERO); + .addReg(TargetReg) + .addReg(ZERO); BuildMI(MBB, I, I->getDebugLoc(), TM.getInstrInfo()->get(ADDU), RA) - .addReg(TargetReg).addReg(ZERO); + .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); + .addReg(SP) + .addReg(OffsetReg); + expandRetRA(MBB, I); } -const MipsInstrInfo *llvm::createMipsSEInstrInfo(MipsTargetMachine &TM) { - return new MipsSEInstrInfo(TM); +const MipsInstrInfo *llvm::createMipsSEInstrInfo(const MipsSubtarget &STI) { + return new MipsSEInstrInfo(STI); } diff --git a/lib/Target/Mips/MipsSEInstrInfo.h b/lib/Target/Mips/MipsSEInstrInfo.h index 6d2dd901f33b..9576fef1bd92 100644 --- a/lib/Target/Mips/MipsSEInstrInfo.h +++ b/lib/Target/Mips/MipsSEInstrInfo.h @@ -24,48 +24,48 @@ class MipsSEInstrInfo : public MipsInstrInfo { bool IsN64; public: - explicit MipsSEInstrInfo(MipsTargetMachine &TM); + explicit MipsSEInstrInfo(const MipsSubtarget &STI); - virtual const MipsRegisterInfo &getRegisterInfo() const; + const MipsRegisterInfo &getRegisterInfo() const override; /// 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; + unsigned isLoadFromStackSlot(const MachineInstr *MI, + int &FrameIndex) const override; /// 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; + unsigned isStoreToStackSlot(const MachineInstr *MI, + int &FrameIndex) const override; - virtual void copyPhysReg(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, DebugLoc DL, - unsigned DestReg, unsigned SrcReg, - bool KillSrc) const; + void copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const override; - virtual void storeRegToStack(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - unsigned SrcReg, bool isKill, int FrameIndex, - const TargetRegisterClass *RC, - const TargetRegisterInfo *TRI, - int64_t Offset) const; + void storeRegToStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const override; - virtual void loadRegFromStack(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - unsigned DestReg, int FrameIndex, - const TargetRegisterClass *RC, - const TargetRegisterInfo *TRI, - int64_t Offset) const; + void loadRegFromStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const override; - virtual bool expandPostRAPseudo(MachineBasicBlock::iterator MI) const; + bool expandPostRAPseudo(MachineBasicBlock::iterator MI) const override; - virtual unsigned getOppositeBranchOpc(unsigned Opc) const; + unsigned getOppositeBranchOpc(unsigned Opc) const override; /// Adjust SP by Amount bytes. void adjustStackPtr(unsigned SP, int64_t Amount, MachineBasicBlock &MBB, @@ -79,10 +79,9 @@ public: unsigned *NewImm) const; private: - virtual unsigned getAnalyzableBrOpc(unsigned Opc) const; + unsigned getAnalyzableBrOpc(unsigned Opc) const override; - void expandRetRA(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, - unsigned Opc) const; + void expandRetRA(MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; std::pair<bool, bool> compareOpndSize(unsigned Opc, const MachineFunction &MF) const; diff --git a/lib/Target/Mips/MipsSERegisterInfo.cpp b/lib/Target/Mips/MipsSERegisterInfo.cpp index 2d440840aaff..0af1a6b9e5c3 100644 --- a/lib/Target/Mips/MipsSERegisterInfo.cpp +++ b/lib/Target/Mips/MipsSERegisterInfo.cpp @@ -24,9 +24,8 @@ #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/DebugInfo.h" #include "llvm/IR/Function.h" #include "llvm/IR/Type.h" #include "llvm/Support/CommandLine.h" @@ -40,6 +39,8 @@ using namespace llvm; +#define DEBUG_TYPE "mips-reg-info" + MipsSERegisterInfo::MipsSERegisterInfo(const MipsSubtarget &ST) : MipsRegisterInfo(ST) {} @@ -62,21 +63,42 @@ MipsSERegisterInfo::intRegClass(unsigned Size) const { 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) { +/// Get the size of the offset supported by the given load/store. +/// The result includes the effects of any scale factors applied to the +/// instruction immediate. +static inline unsigned getLoadStoreOffsetSizeInBits(const unsigned Opcode) { switch (Opcode) { case Mips::LD_B: + case Mips::ST_B: + return 10; case Mips::LD_H: + case Mips::ST_H: + return 10 + 1 /* scale factor */; case Mips::LD_W: + case Mips::ST_W: + return 10 + 2 /* scale factor */; case Mips::LD_D: - case Mips::ST_B: + case Mips::ST_D: + return 10 + 3 /* scale factor */; + default: + return 16; + } +} + +/// Get the scale factor applied to the immediate in the given load/store. +static inline unsigned getLoadStoreOffsetAlign(const unsigned Opcode) { + switch (Opcode) { + case Mips::LD_H: case Mips::ST_H: + return 2; + case Mips::LD_W: case Mips::ST_W: + return 4; + case Mips::LD_D: case Mips::ST_D: - return true; + return 8; default: - return false; + return 1; } } @@ -131,13 +153,16 @@ void MipsSERegisterInfo::eliminateFI(MachineBasicBlock::iterator II, 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; + // For MSA instructions, this is a 10-bit signed immediate (scaled by + // element size), otherwise it is a 16-bit signed immediate. + unsigned OffsetBitSize = getLoadStoreOffsetSizeInBits(MI.getOpcode()); + unsigned OffsetAlign = getLoadStoreOffsetAlign(MI.getOpcode()); - 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 + if (OffsetBitSize < 16 && isInt<16>(Offset) && + (!isIntN(OffsetBitSize, Offset) || + OffsetToAlignment(Offset, OffsetAlign) != 0)) { + // If we have an offset that needs to fit into a signed n-bit immediate + // (where n < 16) 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; @@ -164,7 +189,7 @@ void MipsSERegisterInfo::eliminateFI(MachineBasicBlock::iterator II, *static_cast<const MipsSEInstrInfo *>( MBB.getParent()->getTarget().getInstrInfo()); unsigned Reg = TII.loadImmediate(Offset, MBB, II, DL, - OffsetBitSize == 16 ? &NewImm : NULL); + OffsetBitSize == 16 ? &NewImm : nullptr); BuildMI(MBB, II, DL, TII.get(ADDu), Reg).addReg(FrameReg) .addReg(Reg, RegState::Kill); diff --git a/lib/Target/Mips/MipsSERegisterInfo.h b/lib/Target/Mips/MipsSERegisterInfo.h index 76cdd9d230d3..f2f3a7e75fd8 100644 --- a/lib/Target/Mips/MipsSERegisterInfo.h +++ b/lib/Target/Mips/MipsSERegisterInfo.h @@ -24,16 +24,16 @@ class MipsSERegisterInfo : public MipsRegisterInfo { public: MipsSERegisterInfo(const MipsSubtarget &Subtarget); - bool requiresRegisterScavenging(const MachineFunction &MF) const; + bool requiresRegisterScavenging(const MachineFunction &MF) const override; - bool requiresFrameIndexScavenging(const MachineFunction &MF) const; + bool requiresFrameIndexScavenging(const MachineFunction &MF) const override; - virtual const TargetRegisterClass *intRegClass(unsigned Size) const; + const TargetRegisterClass *intRegClass(unsigned Size) const override; private: - virtual void eliminateFI(MachineBasicBlock::iterator II, unsigned OpNo, - int FrameIndex, uint64_t StackSize, - int64_t SPOffset) const; + void eliminateFI(MachineBasicBlock::iterator II, unsigned OpNo, + int FrameIndex, uint64_t StackSize, + int64_t SPOffset) const override; }; } // end namespace llvm diff --git a/lib/Target/Mips/MipsSchedule.td b/lib/Target/Mips/MipsSchedule.td index 2779064c4149..ea981996bf15 100644 --- a/lib/Target/Mips/MipsSchedule.td +++ b/lib/Target/Mips/MipsSchedule.td @@ -17,60 +17,295 @@ 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; +def II_ABS : InstrItinClass; +def II_ADDI : InstrItinClass; +def II_ADDIU : InstrItinClass; +def II_ADDU : InstrItinClass; +def II_ADD_D : InstrItinClass; +def II_ADD_S : InstrItinClass; +def II_AND : InstrItinClass; +def II_ANDI : InstrItinClass; +def II_BADDU : InstrItinClass; +def II_CEIL : InstrItinClass; +def II_CFC1 : InstrItinClass; +def II_CLO : InstrItinClass; +def II_CLZ : InstrItinClass; +def II_CTC1 : InstrItinClass; +def II_CVT : InstrItinClass; +def II_C_CC_D : InstrItinClass; // Any c.<cc>.d instruction +def II_C_CC_S : InstrItinClass; // Any c.<cc>.s instruction +def II_DADDIU : InstrItinClass; +def II_DADDU : InstrItinClass; +def II_DADD : InstrItinClass; +def II_DDIV : InstrItinClass; +def II_DDIVU : InstrItinClass; +def II_DIV : InstrItinClass; +def II_DIVU : InstrItinClass; +def II_DIV_D : InstrItinClass; +def II_DIV_S : InstrItinClass; +def II_DMFC1 : InstrItinClass; +def II_DMTC1 : InstrItinClass; +def II_DMUL : InstrItinClass; +def II_DMULT : InstrItinClass; +def II_DMULTU : InstrItinClass; +def II_DROTR : InstrItinClass; +def II_DROTR32 : InstrItinClass; +def II_DROTRV : InstrItinClass; +def II_DSLL : InstrItinClass; +def II_DSLL32 : InstrItinClass; +def II_DSLLV : InstrItinClass; +def II_DSRA : InstrItinClass; +def II_DSRA32 : InstrItinClass; +def II_DSRAV : InstrItinClass; +def II_DSRL : InstrItinClass; +def II_DSRL32 : InstrItinClass; +def II_DSRLV : InstrItinClass; +def II_DSUBU : InstrItinClass; +def II_DSUB : InstrItinClass; +def II_FLOOR : InstrItinClass; +def II_LB : InstrItinClass; +def II_LBU : InstrItinClass; +def II_LD : InstrItinClass; +def II_LDC1 : InstrItinClass; +def II_LDL : InstrItinClass; +def II_LDR : InstrItinClass; +def II_LDXC1 : InstrItinClass; +def II_LH : InstrItinClass; +def II_LHU : InstrItinClass; +def II_LUI : InstrItinClass; +def II_LUXC1 : InstrItinClass; +def II_LW : InstrItinClass; +def II_LWC1 : InstrItinClass; +def II_LWL : InstrItinClass; +def II_LWR : InstrItinClass; +def II_LWU : InstrItinClass; +def II_LWXC1 : InstrItinClass; +def II_MADD : InstrItinClass; +def II_MADDU : InstrItinClass; +def II_MADD_D : InstrItinClass; +def II_MADD_S : InstrItinClass; +def II_MFC1 : InstrItinClass; +def II_MFHC1 : InstrItinClass; +def II_MFHI_MFLO : InstrItinClass; // mfhi and mflo +def II_MOVF : InstrItinClass; +def II_MOVF_D : InstrItinClass; +def II_MOVF_S : InstrItinClass; +def II_MOVN : InstrItinClass; +def II_MOVN_D : InstrItinClass; +def II_MOVN_S : InstrItinClass; +def II_MOVT : InstrItinClass; +def II_MOVT_D : InstrItinClass; +def II_MOVT_S : InstrItinClass; +def II_MOVZ : InstrItinClass; +def II_MOVZ_D : InstrItinClass; +def II_MOVZ_S : InstrItinClass; +def II_MOV_D : InstrItinClass; +def II_MOV_S : InstrItinClass; +def II_MSUB : InstrItinClass; +def II_MSUBU : InstrItinClass; +def II_MSUB_D : InstrItinClass; +def II_MSUB_S : InstrItinClass; +def II_MTC1 : InstrItinClass; +def II_MTHC1 : InstrItinClass; +def II_MTHI_MTLO : InstrItinClass; // mthi and mtlo +def II_MUL : InstrItinClass; +def II_MULT : InstrItinClass; +def II_MULTU : InstrItinClass; +def II_MUL_D : InstrItinClass; +def II_MUL_S : InstrItinClass; +def II_NEG : InstrItinClass; +def II_NMADD_D : InstrItinClass; +def II_NMADD_S : InstrItinClass; +def II_NMSUB_D : InstrItinClass; +def II_NMSUB_S : InstrItinClass; +def II_NOR : InstrItinClass; +def II_OR : InstrItinClass; +def II_ORI : InstrItinClass; +def II_POP : InstrItinClass; +def II_RDHWR : InstrItinClass; +def II_RESTORE : InstrItinClass; +def II_ROTR : InstrItinClass; +def II_ROTRV : InstrItinClass; +def II_ROUND : InstrItinClass; +def II_SAVE : InstrItinClass; +def II_SB : InstrItinClass; +def II_SD : InstrItinClass; +def II_SDC1 : InstrItinClass; +def II_SDL : InstrItinClass; +def II_SDR : InstrItinClass; +def II_SDXC1 : InstrItinClass; +def II_SEB : InstrItinClass; +def II_SEH : InstrItinClass; +def II_SEQ_SNE : InstrItinClass; // seq and sne +def II_SEQI_SNEI : InstrItinClass; // seqi and snei +def II_SH : InstrItinClass; +def II_SLL : InstrItinClass; +def II_SLLV : InstrItinClass; +def II_SLTI_SLTIU : InstrItinClass; // slti and sltiu +def II_SLT_SLTU : InstrItinClass; // slt and sltu +def II_SQRT_D : InstrItinClass; +def II_SQRT_S : InstrItinClass; +def II_SRA : InstrItinClass; +def II_SRAV : InstrItinClass; +def II_SRL : InstrItinClass; +def II_SRLV : InstrItinClass; +def II_SUBU : InstrItinClass; +def II_SUB_D : InstrItinClass; +def II_SUB_S : InstrItinClass; +def II_SUXC1 : InstrItinClass; +def II_SW : InstrItinClass; +def II_SWC1 : InstrItinClass; +def II_SWL : InstrItinClass; +def II_SWR : InstrItinClass; +def II_SWXC1 : InstrItinClass; +def II_TRUNC : InstrItinClass; +def II_XOR : InstrItinClass; +def II_XORI : 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<II_ADDI , [InstrStage<1, [ALU]>]>, + InstrItinData<II_ADDIU , [InstrStage<1, [ALU]>]>, + InstrItinData<II_ADDU , [InstrStage<1, [ALU]>]>, + InstrItinData<II_AND , [InstrStage<1, [ALU]>]>, + InstrItinData<II_BADDU , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SLL , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SRA , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SRL , [InstrStage<1, [ALU]>]>, + InstrItinData<II_ROTR , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SLLV , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SRAV , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SRLV , [InstrStage<1, [ALU]>]>, + InstrItinData<II_ROTRV , [InstrStage<1, [ALU]>]>, + InstrItinData<II_CLO , [InstrStage<1, [ALU]>]>, + InstrItinData<II_CLZ , [InstrStage<1, [ALU]>]>, + InstrItinData<II_DADDIU , [InstrStage<1, [ALU]>]>, + InstrItinData<II_DADDU , [InstrStage<1, [ALU]>]>, + InstrItinData<II_DADD , [InstrStage<1, [ALU]>]>, + InstrItinData<II_DSLL , [InstrStage<1, [ALU]>]>, + InstrItinData<II_DSRL , [InstrStage<1, [ALU]>]>, + InstrItinData<II_DSRA , [InstrStage<1, [ALU]>]>, + InstrItinData<II_DSLLV , [InstrStage<1, [ALU]>]>, + InstrItinData<II_DSRLV , [InstrStage<1, [ALU]>]>, + InstrItinData<II_DSRAV , [InstrStage<1, [ALU]>]>, + InstrItinData<II_DSUBU , [InstrStage<1, [ALU]>]>, + InstrItinData<II_DSUB , [InstrStage<1, [ALU]>]>, + InstrItinData<II_DROTR , [InstrStage<1, [ALU]>]>, + InstrItinData<II_DROTRV , [InstrStage<1, [ALU]>]>, + InstrItinData<II_LUI , [InstrStage<1, [ALU]>]>, + InstrItinData<II_MOVF , [InstrStage<1, [ALU]>]>, + InstrItinData<II_MOVN , [InstrStage<1, [ALU]>]>, + InstrItinData<II_MOVN_S , [InstrStage<1, [ALU]>]>, + InstrItinData<II_MOVN_D , [InstrStage<1, [ALU]>]>, + InstrItinData<II_MOVT , [InstrStage<1, [ALU]>]>, + InstrItinData<II_MOVZ , [InstrStage<1, [ALU]>]>, + InstrItinData<II_NOR , [InstrStage<1, [ALU]>]>, + InstrItinData<II_OR , [InstrStage<1, [ALU]>]>, + InstrItinData<II_POP , [InstrStage<1, [ALU]>]>, + InstrItinData<II_RDHWR , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SUBU , [InstrStage<1, [ALU]>]>, + InstrItinData<II_XOR , [InstrStage<1, [ALU]>]>, + InstrItinData<II_ANDI , [InstrStage<1, [ALU]>]>, + InstrItinData<II_ORI , [InstrStage<1, [ALU]>]>, + InstrItinData<II_XORI , [InstrStage<1, [ALU]>]>, + InstrItinData<II_LB , [InstrStage<3, [ALU]>]>, + InstrItinData<II_LBU , [InstrStage<3, [ALU]>]>, + InstrItinData<II_LH , [InstrStage<3, [ALU]>]>, + InstrItinData<II_LHU , [InstrStage<3, [ALU]>]>, + InstrItinData<II_LW , [InstrStage<3, [ALU]>]>, + InstrItinData<II_LWL , [InstrStage<3, [ALU]>]>, + InstrItinData<II_LWR , [InstrStage<3, [ALU]>]>, + InstrItinData<II_LD , [InstrStage<3, [ALU]>]>, + InstrItinData<II_LDL , [InstrStage<3, [ALU]>]>, + InstrItinData<II_LDR , [InstrStage<3, [ALU]>]>, + InstrItinData<II_RESTORE , [InstrStage<3, [ALU]>]>, + InstrItinData<II_SB , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SH , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SW , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SWL , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SWR , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SDL , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SDR , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SD , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SAVE , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SEQ_SNE , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SEQI_SNEI , [InstrStage<1, [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]>]> + InstrItinData<II_DMUL , [InstrStage<17, [IMULDIV]>]>, + InstrItinData<II_DMULT , [InstrStage<17, [IMULDIV]>]>, + InstrItinData<II_DMULTU , [InstrStage<17, [IMULDIV]>]>, + InstrItinData<II_MADD , [InstrStage<17, [IMULDIV]>]>, + InstrItinData<II_MADDU , [InstrStage<17, [IMULDIV]>]>, + InstrItinData<II_MFHI_MFLO , [InstrStage<1, [IMULDIV]>]>, + InstrItinData<II_MSUB , [InstrStage<17, [IMULDIV]>]>, + InstrItinData<II_MSUBU , [InstrStage<17, [IMULDIV]>]>, + InstrItinData<II_MTHI_MTLO , [InstrStage<1, [IMULDIV]>]>, + InstrItinData<II_MUL , [InstrStage<17, [IMULDIV]>]>, + InstrItinData<II_MULT , [InstrStage<17, [IMULDIV]>]>, + InstrItinData<II_MULTU , [InstrStage<17, [IMULDIV]>]>, + InstrItinData<II_MSUB , [InstrStage<17, [IMULDIV]>]>, + InstrItinData<II_MSUBU , [InstrStage<17, [IMULDIV]>]>, + InstrItinData<II_DIV , [InstrStage<38, [IMULDIV]>]>, + InstrItinData<II_DIVU , [InstrStage<38, [IMULDIV]>]>, + InstrItinData<II_DDIV , [InstrStage<38, [IMULDIV]>]>, + InstrItinData<II_DDIVU , [InstrStage<38, [IMULDIV]>]>, + InstrItinData<II_CEIL , [InstrStage<1, [ALU]>]>, + InstrItinData<II_CVT , [InstrStage<1, [ALU]>]>, + InstrItinData<II_ABS , [InstrStage<1, [ALU]>]>, + InstrItinData<II_FLOOR , [InstrStage<1, [ALU]>]>, + InstrItinData<II_NEG , [InstrStage<1, [ALU]>]>, + InstrItinData<II_ROUND , [InstrStage<1, [ALU]>]>, + InstrItinData<II_TRUNC , [InstrStage<1, [ALU]>]>, + InstrItinData<II_MOV_D , [InstrStage<2, [ALU]>]>, + InstrItinData<II_MOV_S , [InstrStage<2, [ALU]>]>, + InstrItinData<II_CFC1 , [InstrStage<2, [ALU]>]>, + InstrItinData<II_CTC1 , [InstrStage<2, [ALU]>]>, + InstrItinData<II_MOVF_D , [InstrStage<2, [ALU]>]>, + InstrItinData<II_MOVF_S , [InstrStage<2, [ALU]>]>, + InstrItinData<II_MOVT_D , [InstrStage<2, [ALU]>]>, + InstrItinData<II_MOVT_S , [InstrStage<2, [ALU]>]>, + InstrItinData<II_MOVZ_D , [InstrStage<2, [ALU]>]>, + InstrItinData<II_MOVZ_S , [InstrStage<2, [ALU]>]>, + InstrItinData<II_C_CC_S , [InstrStage<3, [ALU]>]>, + InstrItinData<II_C_CC_D , [InstrStage<3, [ALU]>]>, + InstrItinData<II_ADD_D , [InstrStage<4, [ALU]>]>, + InstrItinData<II_ADD_S , [InstrStage<4, [ALU]>]>, + InstrItinData<II_SUB_D , [InstrStage<4, [ALU]>]>, + InstrItinData<II_SUB_S , [InstrStage<4, [ALU]>]>, + InstrItinData<II_MUL_S , [InstrStage<7, [ALU]>]>, + InstrItinData<II_MADD_S , [InstrStage<7, [ALU]>]>, + InstrItinData<II_MSUB_S , [InstrStage<7, [ALU]>]>, + InstrItinData<II_NMADD_S , [InstrStage<7, [ALU]>]>, + InstrItinData<II_NMSUB_S , [InstrStage<7, [ALU]>]>, + InstrItinData<II_MUL_D , [InstrStage<8, [ALU]>]>, + InstrItinData<II_MADD_D , [InstrStage<8, [ALU]>]>, + InstrItinData<II_MSUB_D , [InstrStage<8, [ALU]>]>, + InstrItinData<II_NMADD_D , [InstrStage<8, [ALU]>]>, + InstrItinData<II_NMSUB_D , [InstrStage<8, [ALU]>]>, + InstrItinData<II_DIV_S , [InstrStage<23, [ALU]>]>, + InstrItinData<II_DIV_D , [InstrStage<36, [ALU]>]>, + InstrItinData<II_SQRT_S , [InstrStage<54, [ALU]>]>, + InstrItinData<II_SQRT_D , [InstrStage<12, [ALU]>]>, + InstrItinData<II_LDC1 , [InstrStage<3, [ALU]>]>, + InstrItinData<II_LWC1 , [InstrStage<3, [ALU]>]>, + InstrItinData<II_LDXC1 , [InstrStage<3, [ALU]>]>, + InstrItinData<II_LWXC1 , [InstrStage<3, [ALU]>]>, + InstrItinData<II_LUXC1 , [InstrStage<3, [ALU]>]>, + InstrItinData<II_SDC1 , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SWC1 , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SDXC1 , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SWXC1 , [InstrStage<1, [ALU]>]>, + InstrItinData<II_SUXC1 , [InstrStage<1, [ALU]>]>, + InstrItinData<II_DMFC1 , [InstrStage<2, [ALU]>]>, + InstrItinData<II_DMTC1 , [InstrStage<2, [ALU]>]>, + InstrItinData<II_MFC1 , [InstrStage<2, [ALU]>]>, + InstrItinData<II_MTC1 , [InstrStage<2, [ALU]>]>, + InstrItinData<II_MFHC1 , [InstrStage<2, [ALU]>]>, + InstrItinData<II_MTHC1 , [InstrStage<2, [ALU]>]> ]>; diff --git a/lib/Target/Mips/MipsSelectionDAGInfo.cpp b/lib/Target/Mips/MipsSelectionDAGInfo.cpp index e4d70fcec591..edd8f670707f 100644 --- a/lib/Target/Mips/MipsSelectionDAGInfo.cpp +++ b/lib/Target/Mips/MipsSelectionDAGInfo.cpp @@ -11,13 +11,13 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "mips-selectiondag-info" #include "MipsTargetMachine.h" using namespace llvm; -MipsSelectionDAGInfo::MipsSelectionDAGInfo(const MipsTargetMachine &TM) - : TargetSelectionDAGInfo(TM) { -} +#define DEBUG_TYPE "mips-selectiondag-info" + +MipsSelectionDAGInfo::MipsSelectionDAGInfo(const DataLayout &DL) + : TargetSelectionDAGInfo(&DL) {} MipsSelectionDAGInfo::~MipsSelectionDAGInfo() { } diff --git a/lib/Target/Mips/MipsSelectionDAGInfo.h b/lib/Target/Mips/MipsSelectionDAGInfo.h index 6cafb558b35a..2b3d527fe6ff 100644 --- a/lib/Target/Mips/MipsSelectionDAGInfo.h +++ b/lib/Target/Mips/MipsSelectionDAGInfo.h @@ -22,7 +22,7 @@ class MipsTargetMachine; class MipsSelectionDAGInfo : public TargetSelectionDAGInfo { public: - explicit MipsSelectionDAGInfo(const MipsTargetMachine &TM); + explicit MipsSelectionDAGInfo(const DataLayout &DL); ~MipsSelectionDAGInfo(); }; diff --git a/lib/Target/Mips/MipsSubtarget.cpp b/lib/Target/Mips/MipsSubtarget.cpp index 0a81072b0858..5bf875daea99 100644 --- a/lib/Target/Mips/MipsSubtarget.cpp +++ b/lib/Target/Mips/MipsSubtarget.cpp @@ -11,13 +11,11 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "mips-subtarget" - #include "MipsMachineFunction.h" -#include "MipsSubtarget.h" -#include "MipsTargetMachine.h" #include "Mips.h" #include "MipsRegisterInfo.h" +#include "MipsSubtarget.h" +#include "MipsTargetMachine.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/Function.h" #include "llvm/Support/CommandLine.h" @@ -25,13 +23,14 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define DEBUG_TYPE "mips-subtarget" + #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( @@ -55,44 +54,96 @@ Mips16HardFloat("mips16-hard-float", cl::NotHidden, static cl::opt<bool> Mips16ConstantIslands( - "mips16-constant-islands", cl::Hidden, - cl::desc("MIPS: mips16 constant islands enable. experimental feature"), - cl::init(false)); + "mips16-constant-islands", cl::NotHidden, + cl::desc("MIPS: mips16 constant islands enable."), + cl::init(true)); + +/// Select the Mips CPU for the given triple and cpu name. +/// FIXME: Merge with the copy in MipsMCTargetDesc.cpp +static StringRef selectMipsCPU(Triple TT, StringRef CPU) { + if (CPU.empty() || CPU == "generic") { + if (TT.getArch() == Triple::mips || TT.getArch() == Triple::mipsel) + CPU = "mips32"; + else + CPU = "mips64"; + } + return CPU; +} void MipsSubtarget::anchor() { } +static std::string computeDataLayout(const MipsSubtarget &ST) { + std::string Ret = ""; + + // There are both little and big endian mips. + if (ST.isLittle()) + Ret += "e"; + else + Ret += "E"; + + Ret += "-m:m"; + + // Pointers are 32 bit on some ABIs. + if (!ST.isABI_N64()) + Ret += "-p:32:32"; + + // 8 and 16 bit integers only need no have natural alignment, but try to + // align them to 32 bits. 64 bit integers have natural alignment. + Ret += "-i8:8:32-i16:16:32-i64:64"; + + // 32 bit registers are always available and the stack is at least 64 bit + // aligned. On N64 64 bit registers are also available and the stack is + // 128 bit aligned. + if (ST.isABI_N64() || ST.isABI_N32()) + Ret += "-n32:64-S128"; + else + Ret += "-n32-S64"; + + return Ret; +} + 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); + MipsTargetMachine *_TM) + : MipsGenSubtargetInfo(TT, CPU, FS), MipsArchVersion(Mips32), + MipsABI(UnknownABI), IsLittle(little), IsSingleFloat(false), + IsFPXX(false), IsFP64bit(false), UseOddSPReg(true), IsNaN2008bit(false), + IsGP64bit(false), HasVFPU(false), HasCnMips(false), IsLinux(true), + HasMips3_32(false), HasMips3_32r2(false), HasMips4_32(false), + HasMips4_32r2(false), HasMips5_32r2(false), InMips16Mode(false), + InMips16HardFloat(Mips16HardFloat), InMicroMipsMode(false), HasDSP(false), + HasDSPR2(false), AllowMixed16_32(Mixed16_32 | Mips_Os16), Os16(Mips_Os16), + HasMSA(false), TM(_TM), TargetTriple(TT), + DL(computeDataLayout(initializeSubtargetDependencies(CPU, FS, TM))), + TSInfo(DL), JITInfo(), InstrInfo(MipsInstrInfo::create(*this)), + FrameLowering(MipsFrameLowering::create(*this)), + TLInfo(MipsTargetLowering::create(*TM, *this)) { PreviousInMips16Mode = InMips16Mode; - // Initialize scheduling itinerary for the specified CPU. - InstrItins = getInstrItineraryForCPU(CPUName); + // Don't even attempt to generate code for MIPS-I, MIPS-II, MIPS-III, and + // MIPS-V. They have not been tested and currently exist for the integrated + // assembler only. + if (MipsArchVersion == Mips1) + report_fatal_error("Code generation for MIPS-I is not implemented", false); + if (MipsArchVersion == Mips2) + report_fatal_error("Code generation for MIPS-II is not implemented", false); + if (MipsArchVersion == Mips3) + report_fatal_error("Code generation for MIPS-III is not implemented", + false); + if (MipsArchVersion == Mips5) + report_fatal_error("Code generation for MIPS-V is not implemented", false); - // Set MipsABI if it hasn't been set yet. - if (MipsABI == UnknownABI) - MipsABI = hasMips64() ? N64 : O32; + // Assert exactly one ABI was chosen. + assert(MipsABI != UnknownABI); + assert((((getFeatureBits() & Mips::FeatureO32) != 0) + + ((getFeatureBits() & Mips::FeatureEABI) != 0) + + ((getFeatureBits() & Mips::FeatureN32) != 0) + + ((getFeatureBits() & Mips::FeatureN64) != 0)) == 1); // Check if Architecture and ABI are compatible. - assert(((!hasMips64() && (isABI_O32() || isABI_EABI())) || - (hasMips64() && (isABI_N32() || isABI_N64()))) && + assert(((!isGP64bit() && (isABI_O32() || isABI_EABI())) || + (isGP64bit() && (isABI_N32() || isABI_N64()))) && "Invalid Arch & ABI pair."); if (hasMSA() && !isFP64bit()) @@ -100,73 +151,61 @@ MipsSubtarget::MipsSubtarget(const std::string &TT, const std::string &CPU, "See -mattr=+fp64.", false); + if (!isABI_O32() && !useOddSPReg()) + report_fatal_error("-mattr=+nooddspreg requires the O32 ABI.", false); + + if (IsFPXX && (isABI_N32() || isABI_N64())) + report_fatal_error("FPXX is not permitted for the N32/N64 ABI's.", false); + + if (hasMips32r6()) { + StringRef ISA = hasMips64r6() ? "MIPS64r6" : "MIPS32r6"; + + assert(isFP64bit()); + assert(isNaN2008()); + if (hasDSP()) + report_fatal_error(ISA + " is not compatible with the DSP ASE", 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; + // TODO: Investigate the IsLinux check. I suspect it's really checking for + // bare-metal. + UseSmallSection = !IsLinux && (TM->getRelocationModel() == Reloc::Static); } -bool -MipsSubtarget::enablePostRAScheduler(CodeGenOpt::Level OptLevel, - TargetSubtargetInfo::AntiDepBreakMode &Mode, - RegClassVector &CriticalPathRCs) const { - Mode = TargetSubtargetInfo::ANTIDEP_NONE; +/// This overrides the PostRAScheduler bit in the SchedModel for any CPU. +bool MipsSubtarget::enablePostMachineScheduler() const { return true; } + +void MipsSubtarget::getCriticalPathRCs(RegClassVector &CriticalPathRCs) const { CriticalPathRCs.clear(); - CriticalPathRCs.push_back(hasMips64() ? + CriticalPathRCs.push_back(isGP64bit() ? &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; - } +CodeGenOpt::Level MipsSubtarget::getOptLevelToEnablePostRAScheduler() const { + return CodeGenOpt::Aggressive; +} + +MipsSubtarget & +MipsSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS, + const TargetMachine *TM) { + std::string CPUName = selectMipsCPU(TargetTriple, CPU); + + // Parse features string. + ParseSubtargetFeatures(CPUName, FS); + // Initialize scheduling itinerary for the specified CPU. + InstrItins = getInstrItineraryForCPU(CPUName); + + if (InMips16Mode && !TM->Options.UseSoftFloat) + InMips16HardFloat = true; + + return *this; } -bool MipsSubtarget::mipsSEUsesSoftFloat() const { +bool MipsSubtarget::abiUsesSoftFloat() const { return TM->Options.UseSoftFloat && !InMips16HardFloat; } @@ -174,3 +213,7 @@ bool MipsSubtarget::useConstantIslands() { DEBUG(dbgs() << "use constant islands " << Mips16ConstantIslands << "\n"); return Mips16ConstantIslands; } + +Reloc::Model MipsSubtarget::getRelocationModel() const { + return TM->getRelocationModel(); +} diff --git a/lib/Target/Mips/MipsSubtarget.h b/lib/Target/Mips/MipsSubtarget.h index 6b2ab1238b87..f3264621a700 100644 --- a/lib/Target/Mips/MipsSubtarget.h +++ b/lib/Target/Mips/MipsSubtarget.h @@ -14,11 +14,15 @@ #ifndef MIPSSUBTARGET_H #define MIPSSUBTARGET_H -#include "MCTargetDesc/MipsReginfo.h" +#include "MipsFrameLowering.h" +#include "MipsISelLowering.h" +#include "MipsInstrInfo.h" +#include "MipsJITInfo.h" +#include "MipsSelectionDAGInfo.h" +#include "llvm/IR/DataLayout.h" #include "llvm/MC/MCInstrItineraries.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Target/TargetSubtargetInfo.h" - #include <string> #define GET_SUBTARGETINFO_HEADER @@ -39,9 +43,9 @@ public: }; protected: - enum MipsArchEnum { - Mips32, Mips32r2, Mips64, Mips64r2 + Mips1, Mips2, Mips32, Mips32r2, Mips32r6, Mips3, Mips4, Mips5, Mips64, + Mips64r2, Mips64r6 }; // Mips architecture version @@ -58,15 +62,28 @@ protected: // floating point registers instead of only using even ones. bool IsSingleFloat; + // IsFPXX - MIPS O32 modeless ABI. + bool IsFPXX; + // IsFP64bit - The target processor has 64-bit floating point registers. bool IsFP64bit; + /// Are odd single-precision registers permitted? + /// This corresponds to -modd-spreg and -mno-odd-spreg + bool UseOddSPReg; + + // IsNan2008 - IEEE 754-2008 NaN encoding. + bool IsNaN2008bit; + // IsFP64bit - General-purpose registers are 64 bits wide bool IsGP64bit; // HasVFPU - Processor has a vector floating point unit. bool HasVFPU; + // CPU supports cnMIPS (Cavium Networks Octeon CPU). + bool HasCnMips; + // isLinux - Target system is Linux. Is false we consider ELFOS for now. bool IsLinux; @@ -75,20 +92,20 @@ protected: /// Features related to the presence of specific instructions. - // HasSEInReg - SEB and SEH (signext in register) instructions. - bool HasSEInReg; + // HasMips3_32 - The subset of MIPS-III instructions added to MIPS32 + bool HasMips3_32; - // HasCondMov - Conditional mov (MOVZ, MOVN) instructions. - bool HasCondMov; + // HasMips3_32r2 - The subset of MIPS-III instructions added to MIPS32r2 + bool HasMips3_32r2; - // HasSwap - Byte and half swap instructions. - bool HasSwap; + // HasMips4_32 - Has the subset of MIPS-IV present in MIPS32 + bool HasMips4_32; - // HasBitCount - Count leading '1' and '0' bits. - bool HasBitCount; + // HasMips4_32r2 - Has the subset of MIPS-IV present in MIPS32r2 + bool HasMips4_32r2; - // HasFPIdx -- Floating point indexed load/store instructions. - bool HasFPIdx; + // HasMips5_32r2 - Has the subset of MIPS-V present in MIPS32r2 + bool HasMips5_32r2; // InMips16 -- can process Mips16 instructions bool InMips16Mode; @@ -118,68 +135,90 @@ protected: 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; + Triple TargetTriple; + + const DataLayout DL; // Calculates type size & alignment + const MipsSelectionDAGInfo TSInfo; + MipsJITInfo JITInfo; + std::unique_ptr<const MipsInstrInfo> InstrInfo; + std::unique_ptr<const MipsFrameLowering> FrameLowering; + std::unique_ptr<const MipsTargetLowering> TLInfo; + public: - virtual bool enablePostRAScheduler(CodeGenOpt::Level OptLevel, - AntiDepBreakMode& Mode, - RegClassVector& CriticalPathRCs) const; + /// This overrides the PostRAScheduler bit in the SchedModel for each CPU. + bool enablePostMachineScheduler() const override; + void getCriticalPathRCs(RegClassVector &CriticalPathRCs) const override; + CodeGenOpt::Level getOptLevelToEnablePostRAScheduler() const override; /// 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; } + bool isABI_FPXX() const { return isABI_O32() && IsFPXX; } 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); + const std::string &FS, bool little, 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 hasMips1() const { return MipsArchVersion >= Mips1; } + bool hasMips2() const { return MipsArchVersion >= Mips2; } + bool hasMips3() const { return MipsArchVersion >= Mips3; } + bool hasMips4() const { return MipsArchVersion >= Mips4; } + bool hasMips5() const { return MipsArchVersion >= Mips5; } + bool hasMips4_32() const { return HasMips4_32; } + bool hasMips4_32r2() const { return HasMips4_32r2; } + bool hasMips32() const { + return MipsArchVersion >= Mips32 && MipsArchVersion != Mips3 && + MipsArchVersion != Mips4 && MipsArchVersion != Mips5; + } + bool hasMips32r2() const { + return MipsArchVersion == Mips32r2 || MipsArchVersion == Mips32r6 || + MipsArchVersion == Mips64r2 || MipsArchVersion == Mips64r6; + } + bool hasMips32r6() const { + return MipsArchVersion == Mips32r6 || MipsArchVersion == Mips64r6; + } bool hasMips64() const { return MipsArchVersion >= Mips64; } - bool hasMips64r2() const { return MipsArchVersion == Mips64r2; } + bool hasMips64r2() const { + return MipsArchVersion == Mips64r2 || MipsArchVersion == Mips64r6; + } + bool hasMips64r6() const { return MipsArchVersion == Mips64r6; } + + bool hasCnMips() const { return HasCnMips; } bool isLittle() const { return IsLittle; } + bool isFPXX() const { return IsFPXX; } bool isFP64bit() const { return IsFP64bit; } + bool useOddSPReg() const { return UseOddSPReg; } + bool noOddSPReg() const { return !UseOddSPReg; } + bool isNaN2008() const { return IsNaN2008bit; } 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 inMips16Mode() const { return InMips16Mode; } bool inMips16ModeDefault() const { return InMips16Mode; } + // Hard float for mips16 means essentially to compile as soft float + // but to use a runtime library for soft float that is written with + // native mips32 floating point instructions (those runtime routines + // run in mips32 hard float mode). bool inMips16HardFloat() const { return inMips16Mode() && InMips16HardFloat; } @@ -192,19 +231,15 @@ public: bool hasStandardEncoding() const { return !inMips16Mode(); } - bool mipsSEUsesSoftFloat() const; + bool abiUsesSoftFloat() 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(); } + bool hasMTHC1() const { return hasMips32r2(); } const InstrItineraryData &getInstrItineraryData() const { return InstrItins; } bool allowMixed16_32() const { return inMips16ModeDefault() | @@ -212,23 +247,43 @@ public: 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(); + bool isTargetNaCl() const { return TargetTriple.isOSNaCl(); } + bool isNotTargetNaCl() const { return !TargetTriple.isOSNaCl(); } - unsigned stackAlignment() const { return hasMips64() ? 16 : 8; } + // 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(); - // Grab MipsRegInfo object - const MipsReginfo &getMReginfo() const { return MRI; } + unsigned stackAlignment() const { return hasMips64() ? 16 : 8; } // Grab relocation model - Reloc::Model getRelocationModel() const {return RM;} + Reloc::Model getRelocationModel() const; + + MipsSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS, + const TargetMachine *TM); - /// \brief Reset the subtarget for the Mips target. - void resetSubtarget(MachineFunction *MF); + /// Does the system support unaligned memory access. + /// + /// MIPS32r6/MIPS64r6 require full unaligned access support but does not + /// specify which component of the system provides it. Hardware, software, and + /// hybrid implementations are all valid. + bool systemSupportsUnalignedAccess() const { return hasMips32r6(); } + // Set helper classes + void setHelperClassesMips16(); + void setHelperClassesMipsSE(); + MipsJITInfo *getJITInfo() { return &JITInfo; } + const MipsSelectionDAGInfo *getSelectionDAGInfo() const { return &TSInfo; } + const DataLayout *getDataLayout() const { return &DL; } + const MipsInstrInfo *getInstrInfo() const { return InstrInfo.get(); } + const TargetFrameLowering *getFrameLowering() const { + return FrameLowering.get(); + } + const MipsRegisterInfo *getRegisterInfo() const { + return &InstrInfo->getRegisterInfo(); + } + const MipsTargetLowering *getTargetLowering() const { return TLInfo.get(); } }; } // End llvm namespace diff --git a/lib/Target/Mips/MipsTargetMachine.cpp b/lib/Target/Mips/MipsTargetMachine.cpp index 5046c1b782f6..bb1870ebe605 100644 --- a/lib/Target/Mips/MipsTargetMachine.cpp +++ b/lib/Target/Mips/MipsTargetMachine.cpp @@ -13,29 +13,29 @@ #include "MipsTargetMachine.h" #include "Mips.h" +#include "Mips16FrameLowering.h" +#include "Mips16HardFloat.h" +#include "Mips16ISelDAGToDAG.h" +#include "Mips16ISelLowering.h" +#include "Mips16InstrInfo.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 "MipsSEISelLowering.h" +#include "MipsSEInstrInfo.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/Support/raw_ostream.h" #include "llvm/Transforms/Scalar.h" using namespace llvm; - +#define DEBUG_TYPE "mips" extern "C" void LLVMInitializeMipsTarget() { // Register the target. @@ -45,73 +45,26 @@ extern "C" void LLVMInitializeMipsTarget() { 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() { +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(nullptr), DefaultSubtarget(TT, CPU, FS, isLittle, this), + NoMips16Subtarget(TT, CPU, FS.empty() ? "-mips16" : FS.str() + ",-mips16", + isLittle, this), + Mips16Subtarget(TT, CPU, FS.empty() ? "+mips16" : FS.str() + ",+mips16", + isLittle, this) { + Subtarget = &DefaultSubtarget; 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:: @@ -130,6 +83,23 @@ MipselTargetMachine(const Target &T, StringRef TT, CodeGenOpt::Level OL) : MipsTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, true) {} +void MipsTargetMachine::resetSubtarget(MachineFunction *MF) { + DEBUG(dbgs() << "resetSubtarget\n"); + AttributeSet FnAttrs = MF->getFunction()->getAttributes(); + bool Mips16Attr = FnAttrs.hasAttribute(AttributeSet::FunctionIndex, "mips16"); + bool NoMips16Attr = + FnAttrs.hasAttribute(AttributeSet::FunctionIndex, "nomips16"); + assert(!(Mips16Attr && NoMips16Attr) && + "mips16 and nomips16 specified on the same function"); + if (Mips16Attr) + Subtarget = &Mips16Subtarget; + else if (NoMips16Attr) + Subtarget = &NoMips16Subtarget; + else + Subtarget = &DefaultSubtarget; + return; +} + namespace { /// Mips Code Generator Pass Configuration Options. class MipsPassConfig : public TargetPassConfig { @@ -151,9 +121,13 @@ public: return *getMipsTargetMachine().getSubtargetImpl(); } - virtual void addIRPasses(); - virtual bool addInstSelector(); - virtual bool addPreEmitPass(); + void addIRPasses() override; + bool addInstSelector() override; + void addMachineSSAOptimization() override; + bool addPreEmitPass() override; + + bool addPreRegAlloc() override; + }; } // namespace @@ -172,18 +146,28 @@ void MipsPassConfig::addIRPasses() { // 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())); - } + addPass(createMipsModuleISelDag(getMipsTargetMachine())); + addPass(createMips16ISelDag(getMipsTargetMachine())); + addPass(createMipsSEISelDag(getMipsTargetMachine())); return false; } +void MipsPassConfig::addMachineSSAOptimization() { + addPass(createMipsOptimizePICCallPass(getMipsTargetMachine())); + TargetPassConfig::addMachineSSAOptimization(); +} + +bool MipsPassConfig::addPreRegAlloc() { + if (getOptLevel() == CodeGenOpt::None) { + addPass(createMipsOptimizePICCallPass(getMipsTargetMachine())); + return true; + } + else + return false; +} + void MipsTargetMachine::addAnalysisPasses(PassManagerBase &PM) { - if (Subtarget.allowMixed16_32()) { + if (Subtarget->allowMixed16_32()) { DEBUG(errs() << "No "); //FIXME: The Basic Target Transform Info // pass needs to become a function pass instead of @@ -200,15 +184,9 @@ void MipsTargetMachine::addAnalysisPasses(PassManagerBase &PM) { // 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)); - + addPass(createMipsLongBranchPass(TM)); + addPass(createMipsConstantIslandPass(TM)); return true; } diff --git a/lib/Target/Mips/MipsTargetMachine.h b/lib/Target/Mips/MipsTargetMachine.h index 5a9a11d861c0..bcf411f9cd6f 100644 --- a/lib/Target/Mips/MipsTargetMachine.h +++ b/lib/Target/Mips/MipsTargetMachine.h @@ -14,16 +14,9 @@ #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" @@ -32,70 +25,57 @@ 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; + MipsSubtarget *Subtarget; + MipsSubtarget DefaultSubtarget; + MipsSubtarget NoMips16Subtarget; + MipsSubtarget Mips16Subtarget; 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); + 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); + void addAnalysisPasses(PassManagerBase &PM) override; - 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; + const MipsInstrInfo *getInstrInfo() const override { + return getSubtargetImpl()->getInstrInfo(); } - - virtual MipsJITInfo *getJITInfo() - { return &JITInfo; } - - virtual const MipsRegisterInfo *getRegisterInfo() const { - return &InstrInfo->getRegisterInfo(); + const TargetFrameLowering *getFrameLowering() const override { + return getSubtargetImpl()->getFrameLowering(); } - - virtual const MipsTargetLowering *getTargetLowering() const { - return TLInfo.get(); + const MipsSubtarget *getSubtargetImpl() const override { + if (Subtarget) + return Subtarget; + return &DefaultSubtarget; } - - virtual const MipsSelectionDAGInfo* getSelectionDAGInfo() const { - return &TSInfo; + const InstrItineraryData *getInstrItineraryData() const override { + return Subtarget->inMips16Mode() + ? nullptr + : &getSubtargetImpl()->getInstrItineraryData(); + } + MipsJITInfo *getJITInfo() override { + return Subtarget->getJITInfo(); + } + const MipsRegisterInfo *getRegisterInfo() const override { + return getSubtargetImpl()->getRegisterInfo(); } + const MipsTargetLowering *getTargetLowering() const override { + return getSubtargetImpl()->getTargetLowering(); + } + const DataLayout *getDataLayout() const override { + return getSubtargetImpl()->getDataLayout(); + } + const MipsSelectionDAGInfo* getSelectionDAGInfo() const override { + return getSubtargetImpl()->getSelectionDAGInfo(); + } + /// \brief Reset the subtarget for the Mips target. + void resetSubtarget(MachineFunction *MF); // Pass Pipeline Configuration - virtual TargetPassConfig *createPassConfig(PassManagerBase &PM); - virtual bool addCodeEmitter(PassManagerBase &PM, JITCodeEmitter &JCE); - - // Set helper classes - void setHelperClassesMips16(); - - void setHelperClassesMipsSE(); - - + TargetPassConfig *createPassConfig(PassManagerBase &PM) override; + bool addCodeEmitter(PassManagerBase &PM, JITCodeEmitter &JCE) override; }; /// MipsebTargetMachine - Mips32/64 big endian target machine. diff --git a/lib/Target/Mips/MipsTargetObjectFile.cpp b/lib/Target/Mips/MipsTargetObjectFile.cpp index 4c748c5b57cd..13f9408f4e6e 100644 --- a/lib/Target/Mips/MipsTargetObjectFile.cpp +++ b/lib/Target/Mips/MipsTargetObjectFile.cpp @@ -37,21 +37,6 @@ void MipsTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM){ 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 @@ -103,7 +88,7 @@ IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM, const MCSection *MipsTargetObjectFile:: SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, - Mangler *Mang, const TargetMachine &TM) const { + Mangler &Mang, const TargetMachine &TM) const { // TODO: Could also support "weak" symbols as well with ".gnu.linkonce.s.*" // sections? diff --git a/lib/Target/Mips/MipsTargetObjectFile.h b/lib/Target/Mips/MipsTargetObjectFile.h index c0e9140c829c..2bf5a75be90c 100644 --- a/lib/Target/Mips/MipsTargetObjectFile.h +++ b/lib/Target/Mips/MipsTargetObjectFile.h @@ -17,10 +17,9 @@ namespace llvm { class MipsTargetObjectFile : public TargetLoweringObjectFileELF { const MCSection *SmallDataSection; const MCSection *SmallBSSSection; - const MCSection *ReginfoSection; public: - void Initialize(MCContext &Ctx, const TargetMachine &TM); + void Initialize(MCContext &Ctx, const TargetMachine &TM) override; /// IsGlobalInSmallSection - Return true if this global address should be @@ -31,12 +30,8 @@ namespace llvm { 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; } + SectionKind Kind, Mangler &Mang, + const TargetMachine &TM) const override; }; } // end namespace llvm diff --git a/lib/Target/Mips/MipsTargetStreamer.h b/lib/Target/Mips/MipsTargetStreamer.h index 96966fd7cbc0..99f7d4c92cfb 100644 --- a/lib/Target/Mips/MipsTargetStreamer.h +++ b/lib/Target/Mips/MipsTargetStreamer.h @@ -12,14 +12,83 @@ #include "llvm/MC/MCELFStreamer.h" #include "llvm/MC/MCStreamer.h" +#include "MCTargetDesc/MipsABIFlagsSection.h" namespace llvm { -class MipsTargetStreamer : public MCTargetStreamer { - virtual void anchor(); +struct MipsABIFlagsSection; + +class MipsTargetStreamer : public MCTargetStreamer { public: - virtual void emitMipsHackELFFlags(unsigned Flags) = 0; - virtual void emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val) = 0; + MipsTargetStreamer(MCStreamer &S); + virtual void emitDirectiveSetMicroMips(); + virtual void emitDirectiveSetNoMicroMips(); + virtual void emitDirectiveSetMips16(); + virtual void emitDirectiveSetNoMips16(); + + virtual void emitDirectiveSetReorder(); + virtual void emitDirectiveSetNoReorder(); + virtual void emitDirectiveSetMacro(); + virtual void emitDirectiveSetNoMacro(); + virtual void emitDirectiveSetAt(); + virtual void emitDirectiveSetNoAt(); + virtual void emitDirectiveEnd(StringRef Name); + + virtual void emitDirectiveEnt(const MCSymbol &Symbol); + virtual void emitDirectiveAbiCalls(); + virtual void emitDirectiveNaN2008(); + virtual void emitDirectiveNaNLegacy(); + virtual void emitDirectiveOptionPic0(); + virtual void emitDirectiveOptionPic2(); + virtual void emitFrame(unsigned StackReg, unsigned StackSize, + unsigned ReturnReg); + virtual void emitMask(unsigned CPUBitmask, int CPUTopSavedRegOff); + virtual void emitFMask(unsigned FPUBitmask, int FPUTopSavedRegOff); + + virtual void emitDirectiveSetMips32R2(); + virtual void emitDirectiveSetMips64(); + virtual void emitDirectiveSetMips64R2(); + virtual void emitDirectiveSetDsp(); + + // PIC support + virtual void emitDirectiveCpload(unsigned RegNo); + virtual void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, + const MCSymbol &Sym, bool IsReg); + + /// Emit a '.module fp=value' directive using the given values. + /// Updates the .MIPS.abiflags section + virtual void emitDirectiveModuleFP(MipsABIFlagsSection::FpABIKind Value, + bool Is32BitABI) { + ABIFlagsSection.setFpABI(Value, Is32BitABI); + } + + /// Emit a '.module fp=value' directive using the current values of the + /// .MIPS.abiflags section. + void emitDirectiveModuleFP() { + emitDirectiveModuleFP(ABIFlagsSection.getFpABI(), + ABIFlagsSection.Is32BitABI); + } + + virtual void emitDirectiveModuleOddSPReg(bool Enabled, bool IsO32ABI); + virtual void emitDirectiveSetFp(MipsABIFlagsSection::FpABIKind Value){}; + virtual void emitMipsAbiFlags(){}; + void setCanHaveModuleDir(bool Can) { canHaveModuleDirective = Can; } + bool getCanHaveModuleDir() { return canHaveModuleDirective; } + + // This method enables template classes to set internal abi flags + // structure values. + template <class PredicateLibrary> + void updateABIInfo(const PredicateLibrary &P) { + ABIFlagsSection.setAllFromPredicates(P); + } + + MipsABIFlagsSection &getABIFlagsSection() { return ABIFlagsSection; } + +protected: + MipsABIFlagsSection ABIFlagsSection; + +private: + bool canHaveModuleDirective; }; // This part is for ascii assembly output @@ -27,18 +96,106 @@ 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); + MipsTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS); + void emitDirectiveSetMicroMips() override; + void emitDirectiveSetNoMicroMips() override; + void emitDirectiveSetMips16() override; + void emitDirectiveSetNoMips16() override; + + void emitDirectiveSetReorder() override; + void emitDirectiveSetNoReorder() override; + void emitDirectiveSetMacro() override; + void emitDirectiveSetNoMacro() override; + void emitDirectiveSetAt() override; + void emitDirectiveSetNoAt() override; + void emitDirectiveEnd(StringRef Name) override; + + void emitDirectiveEnt(const MCSymbol &Symbol) override; + void emitDirectiveAbiCalls() override; + void emitDirectiveNaN2008() override; + void emitDirectiveNaNLegacy() override; + void emitDirectiveOptionPic0() override; + void emitDirectiveOptionPic2() override; + void emitFrame(unsigned StackReg, unsigned StackSize, + unsigned ReturnReg) override; + void emitMask(unsigned CPUBitmask, int CPUTopSavedRegOff) override; + void emitFMask(unsigned FPUBitmask, int FPUTopSavedRegOff) override; + + void emitDirectiveSetMips32R2() override; + void emitDirectiveSetMips64() override; + void emitDirectiveSetMips64R2() override; + void emitDirectiveSetDsp() override; + + // PIC support + virtual void emitDirectiveCpload(unsigned RegNo); + void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, + const MCSymbol &Sym, bool IsReg) override; + + // ABI Flags + void emitDirectiveModuleFP(MipsABIFlagsSection::FpABIKind Value, + bool Is32BitABI) override; + void emitDirectiveModuleOddSPReg(bool Enabled, bool IsO32ABI) override; + void emitDirectiveSetFp(MipsABIFlagsSection::FpABIKind Value) override; + void emitMipsAbiFlags() override; }; // This part is for ELF object output class MipsTargetELFStreamer : public MipsTargetStreamer { + bool MicroMipsEnabled; + const MCSubtargetInfo &STI; + bool Pic; + public: + bool isMicroMipsEnabled() const { return MicroMipsEnabled; } MCELFStreamer &getStreamer(); - virtual void emitMipsHackELFFlags(unsigned Flags); - virtual void emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val); + MipsTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI); + + void emitLabel(MCSymbol *Symbol) override; + void emitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; + void finish() override; + + void emitDirectiveSetMicroMips() override; + void emitDirectiveSetNoMicroMips() override; + void emitDirectiveSetMips16() override; + void emitDirectiveSetNoMips16() override; + + void emitDirectiveSetReorder() override; + void emitDirectiveSetNoReorder() override; + void emitDirectiveSetMacro() override; + void emitDirectiveSetNoMacro() override; + void emitDirectiveSetAt() override; + void emitDirectiveSetNoAt() override; + void emitDirectiveEnd(StringRef Name) override; + + void emitDirectiveEnt(const MCSymbol &Symbol) override; + void emitDirectiveAbiCalls() override; + void emitDirectiveNaN2008() override; + void emitDirectiveNaNLegacy() override; + void emitDirectiveOptionPic0() override; + void emitDirectiveOptionPic2() override; + void emitFrame(unsigned StackReg, unsigned StackSize, + unsigned ReturnReg) override; + void emitMask(unsigned CPUBitmask, int CPUTopSavedRegOff) override; + void emitFMask(unsigned FPUBitmask, int FPUTopSavedRegOff) override; + + void emitDirectiveSetMips32R2() override; + void emitDirectiveSetMips64() override; + void emitDirectiveSetMips64R2() override; + void emitDirectiveSetDsp() override; + + // PIC support + virtual void emitDirectiveCpload(unsigned RegNo); + void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, + const MCSymbol &Sym, bool IsReg) override; + + // ABI Flags + void emitDirectiveModuleOddSPReg(bool Enabled, bool IsO32ABI) override; + void emitMipsAbiFlags() override; + +protected: + bool isO32() const { return STI.getFeatureBits() & Mips::FeatureO32; } + bool isN32() const { return STI.getFeatureBits() & Mips::FeatureN32; } + bool isN64() const { return STI.getFeatureBits() & Mips::FeatureN64; } }; } - #endif diff --git a/lib/Target/Mips/TargetInfo/CMakeLists.txt b/lib/Target/Mips/TargetInfo/CMakeLists.txt index 4172d00a33f0..3347a99a4321 100644 --- a/lib/Target/Mips/TargetInfo/CMakeLists.txt +++ b/lib/Target/Mips/TargetInfo/CMakeLists.txt @@ -1,7 +1,3 @@ -include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) - add_llvm_library(LLVMMipsInfo MipsTargetInfo.cpp ) - -add_dependencies(LLVMMipsInfo MipsCommonTableGen) diff --git a/lib/Target/Mips/TargetInfo/LLVMBuild.txt b/lib/Target/Mips/TargetInfo/LLVMBuild.txt index 2d425686227f..6235bfc3fd18 100644 --- a/lib/Target/Mips/TargetInfo/LLVMBuild.txt +++ b/lib/Target/Mips/TargetInfo/LLVMBuild.txt @@ -19,5 +19,5 @@ type = Library name = MipsInfo parent = Mips -required_libraries = MC Support Target +required_libraries = Support add_to_library_groups = Mips |
