diff options
Diffstat (limited to 'lib/Target/Mips')
90 files changed, 6619 insertions, 3166 deletions
diff --git a/lib/Target/Mips/Android.mk b/lib/Target/Mips/Android.mk index 4d49583..74b8a3b 100644 --- a/lib/Target/Mips/Android.mk +++ b/lib/Target/Mips/Android.mk @@ -14,6 +14,7 @@ mips_codegen_TBLGEN_TABLES := \ mips_codegen_SRC_FILES := \ Mips16FrameLowering.cpp \ Mips16HardFloat.cpp \ + Mips16HardFloatInfo.cpp \ Mips16ISelDAGToDAG.cpp \ Mips16ISelLowering.cpp \ Mips16InstrInfo.cpp \ @@ -33,6 +34,7 @@ mips_codegen_SRC_FILES := \ MipsMCInstLower.cpp \ MipsModuleISelDAGToDAG.cpp \ MipsOs16.cpp \ + MipsOptimizePICCall.cpp \ MipsRegisterInfo.cpp \ MipsSEFrameLowering.cpp \ MipsSEISelDAGToDAG.cpp \ @@ -64,6 +66,7 @@ include $(BUILD_HOST_STATIC_LIBRARY) # For the device only # ===================================================== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) include $(CLEAR_VARS) include $(CLEAR_TBLGEN_VARS) @@ -79,3 +82,4 @@ include $(LLVM_DEVICE_BUILD_MK) include $(LLVM_TBLGEN_RULES_MK) include $(LLVM_GEN_INTRINSICS_MK) include $(BUILD_STATIC_LIBRARY) +endif diff --git a/lib/Target/Mips/AsmParser/Android.mk b/lib/Target/Mips/AsmParser/Android.mk index 7d1817d..7d8eec1 100644 --- a/lib/Target/Mips/AsmParser/Android.mk +++ b/lib/Target/Mips/AsmParser/Android.mk @@ -39,6 +39,7 @@ include $(BUILD_HOST_STATIC_LIBRARY) #===---------------------------------------------------------------=== # libLLVMMipsAsmParser (target) #===---------------------------------------------------------------=== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) include $(CLEAR_VARS) include $(CLEAR_TBLGEN_VARS) @@ -52,3 +53,4 @@ TBLGEN_TD_DIR := $(LOCAL_PATH)/.. include $(LLVM_DEVICE_BUILD_MK) include $(LLVM_TBLGEN_RULES_MK) include $(BUILD_STATIC_LIBRARY) +endif diff --git a/lib/Target/Mips/AsmParser/CMakeLists.txt b/lib/Target/Mips/AsmParser/CMakeLists.txt index 28f5219..f167556 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/MipsAsmParser.cpp b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index cdae6c2..911a119 100644 --- a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -7,21 +7,25 @@ // //===----------------------------------------------------------------------===// +#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; @@ -54,16 +58,14 @@ 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" @@ -73,8 +75,15 @@ class MipsAsmParser : public MCTargetAsmParser { MCStreamer &Out, unsigned &ErrorInfo, bool MatchingInlineAsm); + /// Parse a register as used in CFI directives bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc); + bool ParseParenSuffix(StringRef Name, + SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + bool ParseBracketSuffix(StringRef Name, + SmallVectorImpl<MCParsedAsmOperand *> &Operands); + bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, SmallVectorImpl<MCParsedAsmOperand *> &Operands); @@ -82,95 +91,36 @@ class MipsAsmParser : public MCTargetAsmParser { bool ParseDirective(AsmToken DirectiveID); MipsAsmParser::OperandMatchResultTy - parseRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands, int RegKind); - - MipsAsmParser::OperandMatchResultTy - parseMSARegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands, int RegKind); - - MipsAsmParser::OperandMatchResultTy - parseMSACtrlRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands, - int RegKind); - - MipsAsmParser::OperandMatchResultTy parseMemOperand(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - bool parsePtrReg(SmallVectorImpl<MCParsedAsmOperand *> &Operands, - int RegKind); - - MipsAsmParser::OperandMatchResultTy - parsePtrReg(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseGPR32(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseGPR64(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseHWRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseCCRRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseAFGR64Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseFGR64Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseFGR32Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseFGRH32Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseFCCRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseACC64DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseLO32DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MipsAsmParser::OperandMatchResultTy MatchAnyRegisterNameWithoutDollar( + SmallVectorImpl<MCParsedAsmOperand *> &Operands, StringRef Identifier, + SMLoc S); MipsAsmParser::OperandMatchResultTy - parseHI32DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MatchAnyRegisterWithoutDollar(SmallVectorImpl<MCParsedAsmOperand *> &Operands, + SMLoc S); MipsAsmParser::OperandMatchResultTy - parseCOP2(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + ParseAnyRegister(SmallVectorImpl<MCParsedAsmOperand *> &Operands); MipsAsmParser::OperandMatchResultTy - parseMSA128BRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + ParseImm(SmallVectorImpl<MCParsedAsmOperand *> &Operands); MipsAsmParser::OperandMatchResultTy - parseMSA128HRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseMSA128WRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseMSA128DRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseMSA128CtrlRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + ParseJumpTarget(SmallVectorImpl<MCParsedAsmOperand *> &Operands); MipsAsmParser::OperandMatchResultTy parseInvNum(SmallVectorImpl<MCParsedAsmOperand *> &Operands); MipsAsmParser::OperandMatchResultTy - parseLSAImm(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + ParseLSAImm(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - bool searchSymbolAlias(SmallVectorImpl<MCParsedAsmOperand*> &Operands, - unsigned RegKind); + bool searchSymbolAlias(SmallVectorImpl<MCParsedAsmOperand *> &Operands); bool ParseOperand(SmallVectorImpl<MCParsedAsmOperand *> &, StringRef Mnemonic); - int tryParseRegister(bool is64BitReg); - - bool tryParseRegisterOperand(SmallVectorImpl<MCParsedAsmOperand *> &Operands, - bool is64BitReg); - bool needsExpansion(MCInst &Inst); void expandInstruction(MCInst &Inst, SMLoc IDLoc, @@ -192,9 +142,10 @@ class MipsAsmParser : public MCTargetAsmParser { const MCExpr *evaluateRelocExpr(const MCExpr *Expr, StringRef RelocStr); bool isEvaluated(const MCExpr *Expr); + bool parseSetFeature(uint64_t Feature); + bool parseDirectiveCPSetup(); bool parseDirectiveSet(); - bool parseDirectiveMipsHackStocg(); - bool parseDirectiveMipsHackELFFlags(); + bool parseDirectiveOption(); bool parseSetAtDirective(); bool parseSetNoAtDirective(); @@ -202,25 +153,34 @@ class MipsAsmParser : public MCTargetAsmParser { bool parseSetNoMacroDirective(); bool parseSetReorderDirective(); bool parseSetNoReorderDirective(); + bool parseSetNoMips16Directive(); bool parseSetAssignment(); - bool parseDirectiveWord(unsigned Size, SMLoc L); + bool parseDataDirective(unsigned Size, SMLoc L); bool parseDirectiveGpWord(); + bool parseDirectiveGpDWord(); MCSymbolRefExpr::VariantKind getVariantKind(StringRef Symbol); - bool isMips64() const { - return (STI.getFeatureBits() & Mips::FeatureMips64) != 0; + bool isGP64() const { + return (STI.getFeatureBits() & Mips::FeatureGP64Bit) != 0; } bool isFP64() const { return (STI.getFeatureBits() & Mips::FeatureFP64Bit) != 0; } + bool isN32() const { return STI.getFeatureBits() & Mips::FeatureN32; } bool isN64() const { return STI.getFeatureBits() & Mips::FeatureN64; } - int matchRegisterName(StringRef Symbol, bool is64BitReg); + bool isMicroMips() const { + return STI.getFeatureBits() & Mips::FeatureMicroMips; + } + + bool parseRegister(unsigned &RegNum); + + bool eatComma(StringRef ErrorStr); int matchCPURegisterName(StringRef Symbol); @@ -236,10 +196,10 @@ class MipsAsmParser : public MCTargetAsmParser { int matchMSA128CtrlRegisterName(StringRef Name); - int regKindToRegClass(int RegKind); - unsigned getReg(int RC, int RegNo); + unsigned getGPR(int RegNo); + int getATReg(); bool processInstruction(MCInst &Inst, SMLoc IDLoc, @@ -250,17 +210,39 @@ 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: MipsAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser, const MCInstrInfo &MII) - : MCTargetAsmParser(), STI(sti), Parser(parser), - hasConsumedDollar(false) { + : MCTargetAsmParser(), STI(sti), Parser(parser) { // Initialize the set of available features. setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + + // 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); } MCAsmParser &getParser() const { return Parser; } MCAsmLexer &getLexer() const { return Parser.getLexer(); } + + /// Warn if RegNo is the current assembler temporary. + void WarnIfAssemblerTemporary(int RegNo, SMLoc Loc); }; } @@ -269,53 +251,56 @@ 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 isGP64()) + RegKind_FGR = 2, /// FGR32, FGR64, AFGR64 (depending on context and + /// isFP64()) + 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 + + /// 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 }; 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) {} + MipsOperand(KindTy K, MipsAsmParser &Parser) + : MCParsedAsmOperand(), Kind(K), AsmParser(Parser) {} + + /// 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,30 +308,161 @@ 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 MipsOperand *CreateReg(unsigned Index, RegKind RegKind, + const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + MipsOperand *Op = new 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 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) @@ -357,6 +473,91 @@ 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())); + } + + 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 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,19 +567,38 @@ 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 isReg() const { + // 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 { return Kind == k_Immediate; } - bool isToken() const { return Kind == k_Token; } + bool isConstantImm() const { + return isImm() && dyn_cast<MCConstantExpr>(getImm()); + } + bool isToken() const { + // 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 { return Kind == k_Memory; } - bool isPtrReg() const { return Kind == k_PtrReg; } bool isInvNum() const { return Kind == k_Immediate; } - bool isLSAImm() const { return Kind == k_LSAImm; } + 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!"); @@ -386,26 +606,27 @@ public: } unsigned getReg() const { - assert((Kind == k_Register) && "Invalid access!"); - return Reg.RegNum; - } + // 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 +636,9 @@ public: return Mem.Off; } - static MipsOperand *CreateToken(StringRef Str, SMLoc S) { - MipsOperand *Op = new MipsOperand(k_Token); + static MipsOperand *CreateToken(StringRef Str, SMLoc S, + MipsAsmParser &Parser) { + MipsOperand *Op = new MipsOperand(k_Token, Parser); Op->Tok.Data = Str.data(); Op->Tok.Length = Str.size(); Op->StartLoc = S; @@ -424,41 +646,75 @@ 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; + /// Create a numeric register (e.g. $1). The exact register remains + /// unresolved until an instruction successfully matches + static 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 *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 register that is definitely a GPR. + /// This is typically only used for named registers such as $gp. + static MipsOperand *CreateGPRReg(unsigned Index, + const MCRegisterInfo *RegInfo, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_GPR, 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 FGR. + /// This is typically only used for named registers such as $f0. + static MipsOperand *CreateFGRReg(unsigned Index, + const MCRegisterInfo *RegInfo, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_FGR, RegInfo, S, E, Parser); } - static MipsOperand *CreateLSAImm(const MCExpr *Val, SMLoc S, SMLoc E) { - MipsOperand *Op = new MipsOperand(k_LSAImm); + /// Create a register that is definitely an FCC. + /// This is typically only used for named registers such as $fcc0. + static MipsOperand *CreateFCCReg(unsigned Index, + const MCRegisterInfo *RegInfo, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_FCC, RegInfo, S, E, Parser); + } + + /// Create a register that is definitely an ACC. + /// This is typically only used for named registers such as $ac0. + static MipsOperand *CreateACCReg(unsigned Index, + const MCRegisterInfo *RegInfo, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_ACC, RegInfo, S, E, Parser); + } + + /// Create a register that is definitely an MSA128. + /// This is typically only used for named registers such as $w0. + static MipsOperand *CreateMSA128Reg(unsigned Index, + const MCRegisterInfo *RegInfo, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_MSA128, RegInfo, S, E, Parser); + } + + /// Create a register that is definitely an MSACtrl. + /// This is typically only used for named registers such as $msaaccess. + static MipsOperand *CreateMSACtrlReg(unsigned Index, + const MCRegisterInfo *RegInfo, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_MSACtrl, RegInfo, S, E, Parser); + } + + static MipsOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + MipsOperand *Op = new MipsOperand(k_Immediate, Parser); Op->Imm.Val = Val; Op->StartLoc = S; Op->EndLoc = E; return Op; } - static MipsOperand *CreateMem(unsigned Base, const MCExpr *Off, - SMLoc S, SMLoc E) { - MipsOperand *Op = new MipsOperand(k_Memory); + static MipsOperand *CreateMem(MipsOperand *Base, const MCExpr *Off, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + MipsOperand *Op = new MipsOperand(k_Memory, Parser); Op->Mem.Base = Base; Op->Mem.Off = Off; Op->StartLoc = S; @@ -466,79 +722,33 @@ public: return Op; } - bool isGPR32Asm() const { - return Kind == k_Register && Reg.Kind == Kind_GPR32; + bool isGPRAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index <= 31; } - void addRegAsmOperands(MCInst &Inst, unsigned N) const { - Inst.addOperand(MCOperand::CreateReg(Reg.RegNum)); + bool isFGRAsmReg() const { + // AFGR64 is $0-$15 but we handle this in getAFGR64() + return isRegIdx() && RegIdx.Kind & RegKind_FGR && RegIdx.Index <= 31; } - - bool isGPR64Asm() const { - return Kind == k_Register && Reg.Kind == Kind_GPR64; + bool isHWRegsAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_HWRegs && RegIdx.Index <= 31; } - - bool isHWRegsAsm() const { - assert((Kind == k_Register) && "Invalid access!"); - return Reg.Kind == Kind_HWRegs; + bool isCCRAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_CCR && RegIdx.Index <= 31; } - - bool isCCRAsm() const { - assert((Kind == k_Register) && "Invalid access!"); - return Reg.Kind == Kind_CCRRegs; + bool isFCCAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_FCC && RegIdx.Index <= 7; } - - bool isAFGR64Asm() const { - return Kind == k_Register && Reg.Kind == Kind_AFGR64Regs; - } - - bool isFGR64Asm() const { - return Kind == k_Register && Reg.Kind == Kind_FGR64Regs; - } - - bool isFGR32Asm() const { - return (Kind == k_Register) && Reg.Kind == Kind_FGR32Regs; - } - - bool isFGRH32Asm() const { - return (Kind == k_Register) && Reg.Kind == Kind_FGRH32Regs; - } - - bool isFCCRegsAsm() const { - return (Kind == k_Register) && Reg.Kind == Kind_FCCRegs; - } - - bool isACC64DSPAsm() const { - return Kind == k_Register && Reg.Kind == Kind_ACC64DSP; + bool isACCAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_ACC && RegIdx.Index <= 3; } - - bool isLO32DSPAsm() const { - return Kind == k_Register && Reg.Kind == Kind_LO32DSP; - } - - bool isHI32DSPAsm() const { - return Kind == k_Register && Reg.Kind == Kind_HI32DSP; - } - - bool isCOP2Asm() const { return Kind == k_Register && Reg.Kind == Kind_COP2; } - - bool isMSA128BAsm() const { - return Kind == k_Register && Reg.Kind == Kind_MSA128BRegs; - } - - bool isMSA128HAsm() const { - return Kind == k_Register && Reg.Kind == Kind_MSA128HRegs; - } - - bool isMSA128WAsm() const { - return Kind == k_Register && Reg.Kind == Kind_MSA128WRegs; + bool isCOP2AsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_COP2 && 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. @@ -547,7 +757,29 @@ public: SMLoc getEndLoc() const { return EndLoc; } virtual void print(raw_ostream &OS) const { - llvm_unreachable("unimplemented!"); + 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 +794,57 @@ 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(isMicroMips() ? 17 : 18, Offset.getImm())) + return Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), 1LL << (isMicroMips() ? 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(isMicroMips() ? 17 : 18, Offset.getImm())) + return Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), 1LL << (isMicroMips() ? 1 : 2))) + return Error(IDLoc, "branch to misaligned address"); + break; + } + } + if (MCID.hasDelaySlot() && Options.isReorder()) { // If this instruction has a delay slot and .set reorder is active, // emit a NOP after it. @@ -624,6 +906,10 @@ bool MipsAsmParser::needsExpansion(MCInst &Inst) { case Mips::LoadImm32Reg: case Mips::LoadAddr32Imm: case Mips::LoadAddr32Reg: + case Mips::SUBi: + case Mips::SUBiu: + case Mips::DSUBi: + case Mips::DSUBiu: return true; default: return false; @@ -639,6 +925,30 @@ void MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc, return expandLoadAddressImm(Inst, IDLoc, Instructions); case Mips::LoadAddr32Reg: return expandLoadAddressReg(Inst, IDLoc, Instructions); + case Mips::SUBi: + Instructions.push_back(MCInstBuilder(Mips::ADDi) + .addReg(Inst.getOperand(0).getReg()) + .addReg(Inst.getOperand(1).getReg()) + .addImm(-Inst.getOperand(2).getImm())); + return; + case Mips::SUBiu: + Instructions.push_back(MCInstBuilder(Mips::ADDiu) + .addReg(Inst.getOperand(0).getReg()) + .addReg(Inst.getOperand(1).getReg()) + .addImm(-Inst.getOperand(2).getImm())); + return; + case Mips::DSUBi: + Instructions.push_back(MCInstBuilder(Mips::DADDi) + .addReg(Inst.getOperand(0).getReg()) + .addReg(Inst.getOperand(1).getReg()) + .addImm(-Inst.getOperand(2).getImm())); + return; + case Mips::DSUBiu: + Instructions.push_back(MCInstBuilder(Mips::DADDiu) + .addReg(Inst.getOperand(0).getReg()) + .addReg(Inst.getOperand(1).getReg()) + .addImm(-Inst.getOperand(2).getImm())); + return; } } @@ -772,7 +1082,7 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, const MCExpr *ExprOffset; unsigned TmpRegNum; unsigned AtRegNum = getReg( - (isMips64()) ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, getATReg()); + (isGP64()) ? 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(); @@ -823,7 +1133,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)); @@ -861,7 +1171,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: @@ -886,14 +1196,22 @@ bool MipsAsmParser::MatchAndEmitInstruction( 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 +1228,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 +1245,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 (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 (isN32() || isN64()) { + // 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) + 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 +1337,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 +1345,35 @@ bool MipsAssemblerOptions::setATReg(unsigned Reg) { return true; } -int MipsAsmParser::getATReg() { return Options.getATRegNum(); } +int MipsAsmParser::getATReg() { + int AT = Options.getATRegNum(); + if (AT == 0) + TokError("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(isGP64() ? 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; - - 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) { + DEBUG(dbgs() << "ParseOperand\n"); + // 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 +1385,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 +1394,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 +1414,18 @@ 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::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 +1436,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 +1448,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 +1483,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 +1519,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 +1569,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<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 = isGP64() ? Operand.getGPR64Reg() : Operand.getGPR32Reg(); + } + + return (RegNo == (unsigned)-1); + } + + assert(Operands.size() == 0); return (RegNo == (unsigned)-1); } @@ -1384,7 +1623,7 @@ bool MipsAsmParser::parseMemOffset(const MCExpr *&Res, bool isParenExpr) { MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - + DEBUG(dbgs() << "parseMemOperand\n"); const MCExpr *IdVal = 0; SMLoc S; bool isParenExpr = false; @@ -1407,7 +1646,7 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( 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 +1654,9 @@ 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)); + MipsOperand *Base = MipsOperand::CreateGPRReg( + 0, getContext().getRegisterInfo(), S, E, *this); + Operands.push_back(MipsOperand::CreateMem(Base, IdVal, S, E, *this)); return MatchOperand_Success; } Error(Parser.getTok().getLoc(), "'(' expected"); @@ -1426,8 +1666,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; @@ -1445,7 +1684,6 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( // Replace the register operand with the memory operand. MipsOperand *op = static_cast<MipsOperand *>(Operands.back()); - int RegNo = op->getReg(); // Remove the register from the operands. Operands.pop_back(); // Add the memory operand. @@ -1458,599 +1696,193 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( getContext()); } - Operands.push_back(MipsOperand::CreateMem(RegNo, IdVal, S, E)); - delete op; + Operands.push_back(MipsOperand::CreateMem(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( + SmallVectorImpl<MCParsedAsmOperand *> &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); + MipsOperand *op = + MipsOperand::CreateImm(Const, S, Parser.getTok().getLoc(), *this); + Operands.push_back(op); + 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( + SmallVectorImpl<MCParsedAsmOperand *> &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); + return MatchOperand_NoMatch; } 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::MatchAnyRegisterWithoutDollar( + SmallVectorImpl<MCParsedAsmOperand *> &Operands, SMLoc S) { + auto Token = Parser.getLexer().peekTok(false); + + 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::parseFGR64Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - if (!isFP64()) - return MatchOperand_NoMatch; - return parseRegs(Operands, (int)MipsOperand::Kind_FGR64Regs); -} + DEBUG(dbgs() << Parser.getTok().getKind() << "\n"); -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseFGR32Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_FGR32Regs); + return MatchOperand_NoMatch; } -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseFGRH32Regs( +MipsAsmParser::OperandMatchResultTy MipsAsmParser::ParseAnyRegister( SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_FGRH32Regs); -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseFCCRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_FCCRegs); -} + DEBUG(dbgs() << "ParseAnyRegister\n"); -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseACC64DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_ACC64DSP); -} + auto Token = Parser.getTok(); -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseLO32DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - // If the first token is not '$' we have an error. - if (Parser.getTok().isNot(AsmToken::Dollar)) - return MatchOperand_NoMatch; + SMLoc S = Token.getLoc(); - SMLoc S = Parser.getTok().getLoc(); - Parser.Lex(); // Eat the '$' - - const AsmToken &Tok = Parser.getTok(); // Get next token. - - if (Tok.isNot(AsmToken::Identifier)) - return MatchOperand_NoMatch; - - if (!Tok.getIdentifier().startswith("ac")) - return MatchOperand_NoMatch; - - StringRef NumString = Tok.getIdentifier().substr(2); - - unsigned IntVal; - if (NumString.getAsInteger(10, IntVal)) - return MatchOperand_NoMatch; - - unsigned Reg = matchRegisterByNumber(IntVal, Mips::LO32DSPRegClassID); - - MipsOperand *Op = MipsOperand::CreateReg(Reg, S, Parser.getTok().getLoc()); - Op->setRegKind(MipsOperand::Kind_LO32DSP); - Operands.push_back(Op); - - Parser.Lex(); // Eat the register number. - return MatchOperand_Success; -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseHI32DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - // If the first token is not '$' we have an error. - if (Parser.getTok().isNot(AsmToken::Dollar)) - return MatchOperand_NoMatch; - - SMLoc S = Parser.getTok().getLoc(); - Parser.Lex(); // Eat the '$' - - const AsmToken &Tok = Parser.getTok(); // Get next token. - - if (Tok.isNot(AsmToken::Identifier)) - return MatchOperand_NoMatch; - - if (!Tok.getIdentifier().startswith("ac")) - return MatchOperand_NoMatch; - - StringRef NumString = Tok.getIdentifier().substr(2); - - unsigned IntVal; - if (NumString.getAsInteger(10, IntVal)) + 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::HI32DSPRegClassID); - - MipsOperand *Op = MipsOperand::CreateReg(Reg, S, Parser.getTok().getLoc()); - Op->setRegKind(MipsOperand::Kind_HI32DSP); - Operands.push_back(Op); - - Parser.Lex(); // Eat the register number. - return MatchOperand_Success; + OperandMatchResultTy ResTy = MatchAnyRegisterWithoutDollar(Operands, S); + if (ResTy == MatchOperand_Success) { + Parser.Lex(); // $ + Parser.Lex(); // identifier + } + return ResTy; } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseCOP2(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - // If the first token is not '$' we have an error. - if (Parser.getTok().isNot(AsmToken::Dollar)) +MipsAsmParser::ParseImm(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + switch (getLexer().getKind()) { + default: return MatchOperand_NoMatch; + case AsmToken::LParen: + case AsmToken::Minus: + case AsmToken::Plus: + case AsmToken::Integer: + 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::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); + 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::parseMSA128BRegs( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128BRegs); -} - -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128HRegs( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128HRegs); -} - -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128WRegs( +MipsAsmParser::OperandMatchResultTy MipsAsmParser::ParseJumpTarget( SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128WRegs); -} + DEBUG(dbgs() << "ParseJumpTarget\n"); -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128DRegs( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128DRegs); -} + SMLoc S = getLexer().getLoc(); -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128CtrlRegs( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseMSACtrlRegs(Operands, (int)MipsOperand::Kind_MSA128CtrlRegs); -} + // Integers and expressions are acceptable + OperandMatchResultTy ResTy = ParseImm(Operands); + if (ResTy != MatchOperand_NoMatch) + return ResTy; -bool MipsAsmParser::searchSymbolAlias( - SmallVectorImpl<MCParsedAsmOperand *> &Operands, unsigned RegKind) { + // Registers are a valid target and have priority over symbols. + ResTy = ParseAnyRegister(Operands); + if (ResTy != MatchOperand_NoMatch) + return ResTy; - 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 @@ -2067,12 +1899,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(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { switch (getLexer().getKind()) { default: return MatchOperand_NoMatch; @@ -2105,8 +1937,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 +1963,87 @@ 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) .Default(MCSymbolRefExpr::VK_None); + assert (VK != MCSymbolRefExpr::VK_None); + return VK; } +/// 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, SmallVectorImpl<MCParsedAsmOperand *> &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, SmallVectorImpl<MCParsedAsmOperand *> &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, SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + DEBUG(dbgs() << "ParseInstruction\n"); // 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 +2053,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 +2065,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)) { @@ -2222,7 +2130,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 +2161,7 @@ bool MipsAsmParser::parseSetReorderDirective() { return false; } Options.setReorder(); + getTargetStreamer().emitDirectiveSetReorder(); Parser.Lex(); // Consume the EndOfStatement. return false; } @@ -2265,6 +2174,7 @@ bool MipsAsmParser::parseSetNoReorderDirective() { return false; } Options.setNoreorder(); + getTargetStreamer().emitDirectiveSetNoReorder(); Parser.Lex(); // Consume the EndOfStatement. return false; } @@ -2297,6 +2207,18 @@ 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::parseSetAssignment() { StringRef Name; const MCExpr *Value; @@ -2308,22 +2230,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 +2243,156 @@ 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::parseRegister(unsigned &RegNum) { + if (!getLexer().is(AsmToken::Dollar)) + return false; + + Parser.Lex(); + + const AsmToken &Reg = Parser.getTok(); + if (Reg.is(AsmToken::Identifier)) { + RegNum = matchCPURegisterName(Reg.getIdentifier()); + } else if (Reg.is(AsmToken::Integer)) { + RegNum = Reg.getIntVal(); + } else { + return false; + } + + Parser.Lex(); + return true; +} + +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::parseDirectiveCPSetup() { + unsigned FuncReg; + unsigned Save; + bool SaveIsReg = true; + + if (!parseRegister(FuncReg)) + return reportParseError("expected register containing function address"); + FuncReg = getGPR(FuncReg); + + if (!eatComma("expected comma parsing directive")) + return true; + + if (!parseRegister(Save)) { + const AsmToken &Tok = Parser.getTok(); + if (Tok.is(AsmToken::Integer)) { + Save = Tok.getIntVal(); + SaveIsReg = false; + Parser.Lex(); + } else + return reportParseError("expected save register or stack offset"); + } else + Save = getGPR(Save); + + if (!eatComma("expected comma parsing directive")) + return true; + + StringRef Name; + if (Parser.parseIdentifier(Name)) + reportParseError("expected identifier"); + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + unsigned GPReg = getGPR(matchCPURegisterName("gp")); + + // FIXME: The code below this point should be in the TargetStreamers. + // Only N32 and N64 emit anything for .cpsetup + // FIXME: We should only emit something for PIC mode too. + if (!isN32() && !isN64()) + return false; + + MCStreamer &TS = getStreamer(); + MCInst Inst; + // Either store the old $gp in a register or on the stack + if (SaveIsReg) { + // move $save, $gpreg + Inst.setOpcode(Mips::DADDu); + Inst.addOperand(MCOperand::CreateReg(Save)); + Inst.addOperand(MCOperand::CreateReg(GPReg)); + Inst.addOperand(MCOperand::CreateReg(getGPR(0))); + } else { + // sd $gpreg, offset($sp) + Inst.setOpcode(Mips::SD); + Inst.addOperand(MCOperand::CreateReg(GPReg)); + Inst.addOperand(MCOperand::CreateReg(getGPR(matchCPURegisterName("sp")))); + Inst.addOperand(MCOperand::CreateImm(Save)); + } + TS.EmitInstruction(Inst, STI); + Inst.clear(); + + const MCSymbolRefExpr *HiExpr = MCSymbolRefExpr::Create( + Sym->getName(), MCSymbolRefExpr::VK_Mips_GPOFF_HI, + getContext()); + const MCSymbolRefExpr *LoExpr = MCSymbolRefExpr::Create( + Sym->getName(), MCSymbolRefExpr::VK_Mips_GPOFF_LO, + getContext()); + // lui $gp, %hi(%neg(%gp_rel(funcSym))) + Inst.setOpcode(Mips::LUi); + Inst.addOperand(MCOperand::CreateReg(GPReg)); + Inst.addOperand(MCOperand::CreateExpr(HiExpr)); + TS.EmitInstruction(Inst, STI); + Inst.clear(); + + // addiu $gp, $gp, %lo(%neg(%gp_rel(funcSym))) + Inst.setOpcode(Mips::ADDiu); + Inst.addOperand(MCOperand::CreateReg(GPReg)); + Inst.addOperand(MCOperand::CreateReg(GPReg)); + Inst.addOperand(MCOperand::CreateExpr(LoExpr)); + TS.EmitInstruction(Inst, STI); + Inst.clear(); + + // daddu $gp, $gp, $funcreg + Inst.setOpcode(Mips::DADDu); + Inst.addOperand(MCOperand::CreateReg(GPReg)); + Inst.addOperand(MCOperand::CreateReg(GPReg)); + Inst.addOperand(MCOperand::CreateReg(FuncReg)); + TS.EmitInstruction(Inst, STI); + return false; +} + bool MipsAsmParser::parseDirectiveSet() { // Get the next token. @@ -2353,14 +2410,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 +2437,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 +2478,70 @@ 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; +} + +bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { StringRef IDVal = DirectiveID.getString(); + if (IDVal == ".dword") { + parseDataDirective(8, DirectiveID.getLoc()); + return false; + } + if (IDVal == ".ent") { // Ignore this directive for now. Parser.Lex(); @@ -2478,21 +2577,35 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { } 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 == ".mips_hack_stocg") - return parseDirectiveMipsHackStocg(); + 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_elf_flags") - return parseDirectiveMipsHackELFFlags(); + if (IDVal == ".cpsetup") + return parseDirectiveCPSetup(); return true; } diff --git a/lib/Target/Mips/CMakeLists.txt b/lib/Target/Mips/CMakeLists.txt index 6acc9a8..c304ee3 100644 --- a/lib/Target/Mips/CMakeLists.txt +++ b/lib/Target/Mips/CMakeLists.txt @@ -16,6 +16,7 @@ add_public_tablegen_target(MipsCommonTableGen) add_llvm_target(MipsCodeGen Mips16FrameLowering.cpp Mips16HardFloat.cpp + Mips16HardFloatInfo.cpp Mips16InstrInfo.cpp Mips16ISelDAGToDAG.cpp Mips16ISelLowering.cpp @@ -34,6 +35,7 @@ add_llvm_target(MipsCodeGen MipsMCInstLower.cpp MipsMachineFunction.cpp MipsModuleISelDAGToDAG.cpp + MipsOptimizePICCall.cpp MipsOs16.cpp MipsRegisterInfo.cpp MipsSEFrameLowering.cpp @@ -47,8 +49,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/Android.mk b/lib/Target/Mips/Disassembler/Android.mk index 868b43a..20fd87a 100644 --- a/lib/Target/Mips/Disassembler/Android.mk +++ b/lib/Target/Mips/Disassembler/Android.mk @@ -11,6 +11,7 @@ mips_disassembler_SRC_FILES := \ # For the device # ===================================================== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) include $(CLEAR_VARS) include $(CLEAR_TBLGEN_VARS) @@ -26,6 +27,7 @@ TBLGEN_TD_DIR := $(LOCAL_PATH)/.. include $(LLVM_DEVICE_BUILD_MK) include $(LLVM_TBLGEN_RULES_MK) include $(BUILD_STATIC_LIBRARY) +endif # For the host # ===================================================== diff --git a/lib/Target/Mips/Disassembler/CMakeLists.txt b/lib/Target/Mips/Disassembler/CMakeLists.txt index fe1dc75..a64d02c 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/MipsDisassembler.cpp b/lib/Target/Mips/Disassembler/MipsDisassembler.cpp index 60508a8..fc3b922 100644 --- a/lib/Target/Mips/Disassembler/MipsDisassembler.cpp +++ b/lib/Target/Mips/Disassembler/MipsDisassembler.cpp @@ -263,6 +263,11 @@ static DecodeStatus DecodeExtSize(MCInst &Inst, 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); namespace llvm { extern Target TheMipselTarget, TheMipsTarget, TheMips64Target, TheMips64elTarget; @@ -304,9 +309,54 @@ extern "C" void LLVMInitializeMipsDisassembler() { createMips64elDisassembler); } - #include "MipsGenDisassemblerTables.inc" +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; +} + /// readInstruction - read four bytes from the MemoryObject /// and return 32 bit word sorted according to the given endianess static DecodeStatus readInstruction32(const MemoryObject ®ion, @@ -565,7 +615,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 +661,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)); diff --git a/lib/Target/Mips/InstPrinter/Android.mk b/lib/Target/Mips/InstPrinter/Android.mk index fc256cd..f4f3a4f 100644 --- a/lib/Target/Mips/InstPrinter/Android.mk +++ b/lib/Target/Mips/InstPrinter/Android.mk @@ -29,6 +29,7 @@ include $(BUILD_HOST_STATIC_LIBRARY) # For the device only # ===================================================== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) include $(CLEAR_VARS) include $(CLEAR_TBLGEN_VARS) @@ -44,3 +45,4 @@ LOCAL_C_INCLUDES += $(LOCAL_PATH)/.. include $(LLVM_DEVICE_BUILD_MK) include $(LLVM_TBLGEN_RULES_MK) include $(BUILD_STATIC_LIBRARY) +endif diff --git a/lib/Target/Mips/InstPrinter/CMakeLists.txt b/lib/Target/Mips/InstPrinter/CMakeLists.txt index 3e9fbf1..2a67fba 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 7884589..c8f08f1 100644 --- a/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp +++ b/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp @@ -13,6 +13,7 @@ #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" @@ -83,6 +84,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 +130,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(); @@ -286,3 +310,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 f75ae24..2b745f0 100644 --- a/lib/Target/Mips/InstPrinter/MipsInstPrinter.h +++ b/lib/Target/Mips/InstPrinter/MipsInstPrinter.h @@ -104,6 +104,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 a95d6bc..e6d3a42 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/Android.mk b/lib/Target/Mips/MCTargetDesc/Android.mk index 3da6944..7ee11a1 100644 --- a/lib/Target/Mips/MCTargetDesc/Android.mk +++ b/lib/Target/Mips/MCTargetDesc/Android.mk @@ -9,10 +9,12 @@ mips_mc_desc_TBLGEN_TABLES := \ mips_mc_desc_SRC_FILES := \ MipsAsmBackend.cpp \ MipsELFObjectWriter.cpp \ + MipsELFStreamer.cpp \ MipsMCAsmInfo.cpp \ MipsMCCodeEmitter.cpp \ + MipsMCExpr.cpp \ MipsMCTargetDesc.cpp \ - MipsReginfo.cpp \ + MipsNaClELFStreamer.cpp \ MipsTargetStreamer.cpp # For the host @@ -36,6 +38,7 @@ include $(BUILD_HOST_STATIC_LIBRARY) # For the device only # ===================================================== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) include $(CLEAR_VARS) include $(CLEAR_TBLGEN_VARS) @@ -52,3 +55,4 @@ include $(LLVM_DEVICE_BUILD_MK) include $(LLVM_TBLGEN_RULES_MK) include $(LLVM_GEN_INTRINSICS_MK) include $(BUILD_STATIC_LIBRARY) +endif diff --git a/lib/Target/Mips/MCTargetDesc/CMakeLists.txt b/lib/Target/Mips/MCTargetDesc/CMakeLists.txt index 9116748..d3e2fd7 100644 --- a/lib/Target/Mips/MCTargetDesc/CMakeLists.txt +++ b/lib/Target/Mips/MCTargetDesc/CMakeLists.txt @@ -1,11 +1,11 @@ add_llvm_library(LLVMMipsDesc MipsAsmBackend.cpp + MipsELFObjectWriter.cpp + MipsELFStreamer.cpp MipsMCAsmInfo.cpp MipsMCCodeEmitter.cpp + MipsMCExpr.cpp MipsMCTargetDesc.cpp - MipsELFObjectWriter.cpp - MipsReginfo.cpp + MipsNaClELFStreamer.cpp MipsTargetStreamer.cpp ) - -add_dependencies(LLVMMipsDesc MipsCommonTableGen) diff --git a/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp index 3e70b23..0f99ecc 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 = NULL) { + + 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: @@ -56,8 +63,11 @@ 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_26: // So far we are only using this type for jumps. @@ -86,196 +96,196 @@ 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; } return Value; } -namespace { -class MipsAsmBackend : public MCAsmBackend { - Triple::OSType OSType; - bool IsLittle; // Big or little endian - bool Is64Bit; // 32 or 64 bit words - -public: - MipsAsmBackend(const Target &T, Triple::OSType _OSType, - bool _isLittle, bool _is64Bit) - :MCAsmBackend(), OSType(_OSType), IsLittle(_isLittle), Is64Bit(_is64Bit) {} - - MCObjectWriter *createObjectWriter(raw_ostream &OS) const { - return createMipsELFObjectWriter(OS, - MCELFObjectTargetWriter::getOSABI(OSType), IsLittle, Is64Bit); - } - - /// ApplyFixup - Apply the \p Value for given \p Fixup into the provided - /// data fragment, at the offset specified by the fixup and following the - /// fixup kind as appropriate. - void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t Value) const { - MCFixupKind Kind = Fixup.getKind(); - Value = adjustFixupValue((unsigned)Kind, Value); - - if (!Value) - return; // Doesn't change encoding. - - // Where do we start in the object - unsigned Offset = Fixup.getOffset(); - // Number of bytes we need to fixup - unsigned NumBytes = (getFixupKindInfo(Kind).TargetSize + 7) / 8; - // Used to point to big endian bytes - unsigned FullSize; +MCObjectWriter *MipsAsmBackend::createObjectWriter(raw_ostream &OS) const { + return createMipsELFObjectWriter(OS, + MCELFObjectTargetWriter::getOSABI(OSType), IsLittle, Is64Bit); +} - switch ((unsigned)Kind) { - case Mips::fixup_Mips_16: - FullSize = 2; - break; - case Mips::fixup_Mips_64: - FullSize = 8; - break; - default: - FullSize = 4; - break; - } +// Little-endian fixup data byte ordering: +// mips32r2: a | b | x | x +// microMIPS: x | x | a | b - // Grab current value, if any, from bits. - uint64_t CurVal = 0; +static bool needsMMLEByteOrder(unsigned Kind) { + return Kind >= Mips::fixup_MICROMIPS_26_S1 && + Kind < Mips::LastTargetFixupKind; +} - for (unsigned i = 0; i != NumBytes; ++i) { - unsigned Idx = IsLittle ? i : (FullSize - 1 - i); - CurVal |= (uint64_t)((uint8_t)Data[Offset + Idx]) << (i*8); - } +// Calculate index for microMIPS specific little endian byte order +static unsigned calculateMMLEIndex(unsigned i) { + assert(i <= 3 && "Index out of range!"); - uint64_t Mask = ((uint64_t)(-1) >> - (64 - getFixupKindInfo(Kind).TargetSize)); - CurVal |= Value & Mask; + return (1 - i / 2) * 2 + i % 2; +} - // 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); - } +/// 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); + + if (!Value) + return; // Doesn't change encoding. + + // Where do we start in the object + unsigned Offset = Fixup.getOffset(); + // Number of bytes we need to fixup + unsigned NumBytes = (getFixupKindInfo(Kind).TargetSize + 7) / 8; + // Used to point to big endian bytes + unsigned FullSize; + + switch ((unsigned)Kind) { + case 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 - /// @{ - - /// MayNeedRelaxation - Check whether the given instruction may need - /// relaxation. - /// - /// \param Inst - The instruction to test. - bool mayNeedRelaxation(const MCInst &Inst) const { - return false; - } - - /// fixupNeedsRelaxation - Target specific predicate for whether a given - /// fixup requires the associated instruction to be relaxed. - bool fixupNeedsRelaxation(const MCFixup &Fixup, - uint64_t Value, - const MCRelaxableFragment *DF, - const MCAsmLayout &Layout) const { - // FIXME. - assert(0 && "RelaxInstruction() unimplemented"); - return false; - } + uint64_t Mask = ((uint64_t)(-1) >> + (64 - getFixupKindInfo(Kind).TargetSize)); + CurVal |= Value & Mask; - /// 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 { + // 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); } +} - /// @} - - /// 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; +const MCFixupKindInfo &MipsAsmBackend:: +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_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 } + }; + + if (Kind < FirstTargetFixupKind) + return MCAsmBackend::getFixupKindInfo(Kind); + + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); + return Infos[Kind - FirstTargetFixupKind]; +} - uint64_t NumNops = Count / 4; - for (uint64_t i = 0; i != NumNops; ++i) - OW->Write32(0); - return true; - } -}; // class MipsAsmBackend +/// 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; + + uint64_t NumNops = Count / 4; + for (uint64_t i = 0; i != NumNops; ++i) + OW->Write32(0); + return true; +} -} // namespace +/// 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 +319,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 0000000..cc5207a --- /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; + + void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, + uint64_t Value, bool IsPCRel) const; + + const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const; + + unsigned getNumFixupKinds() const { + 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 { + return false; + } + + /// fixupNeedsRelaxation - Target specific predicate for whether a given + /// fixup requires the associated instruction to be relaxed. + bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const { + // FIXME. + assert(0 && "RelaxInstruction() unimplemented"); + return false; + } + + /// RelaxInstruction - Relax the instruction in the given fragment + /// to the next wider instruction. + /// + /// \param Inst - The instruction to relax, which may be the same + /// as the output. + /// \param [out] Res On return, the relaxed instruction. + void relaxInstruction(const MCInst &Inst, MCInst &Res) const {} + + /// @} + + bool writeNopData(uint64_t Count, MCObjectWriter *OW) const; + + void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout, + const MCFixup &Fixup, const MCFragment *DF, + const MCValue &Target, uint64_t &Value, + bool &IsResolved); + +}; // class MipsAsmBackend + +} // namespace + +#endif diff --git a/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h b/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h index 7a55efd..d2323dc 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 83c7d4b..794978b 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,9 @@ 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(unsigned Type) const override; }; } @@ -60,26 +42,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 +175,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; @@ -226,91 +197,39 @@ unsigned MipsELFObjectWriter::GetRelocType(const MCValue &Target, return Type; } -// Return true if R is either a GOT16 against a local symbol or HI16. -static bool NeedsMatchingLo(const MCAssembler &Asm, const RelEntry &R) { - if (!R.Sym) - return false; - - MCSymbolData &SD = Asm.getSymbolData(R.Sym->AliasedSymbol()); - - return ((R.Reloc.Type == ELF::R_MIPS_GOT16) && !SD.isExternal()) || - (R.Reloc.Type == ELF::R_MIPS_HI16); -} - -static bool HasMatchingLo(const MCAssembler &Asm, RelLsIter I, RelLsIter Last) { - if (I == Last) +bool +MipsELFObjectWriter::needsRelocateWithSymbol(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; + + case ELF::R_MIPS_GOT16: + case ELF::R_MIPS16_GOT16: + case ELF::R_MICROMIPS_GOT16: + llvm_unreachable("Should have been handled already"); + + // 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; + + 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 0000000..fe37829 --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp @@ -0,0 +1,19 @@ +//===-------- 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" + +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 0000000..641f8cf --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.h @@ -0,0 +1,42 @@ +//===-------- 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 "llvm/MC/MCELFStreamer.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCSubtargetInfo; + +class MipsELFStreamer : public MCELFStreamer { + +public: + MipsELFStreamer(MCContext &Context, MCAsmBackend &MAB, raw_ostream &OS, + MCCodeEmitter *Emitter, const MCSubtargetInfo &STI) + : MCELFStreamer(Context, MAB, OS, Emitter) {} + + virtual ~MipsELFStreamer() {} +}; + +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 6ed44b7..dc6192c 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h +++ b/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h @@ -155,6 +155,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/MipsMCCodeEmitter.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp index 66428bd..edd2146 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 GET_INSTRMAP_INFO #include "MipsGenInstrInfo.inc" - -using namespace llvm; - -namespace { -class MipsMCCodeEmitter : public MCCodeEmitter { - MipsMCCodeEmitter(const MipsMCCodeEmitter &) LLVM_DELETED_FUNCTION; - void operator=(const MipsMCCodeEmitter &) LLVM_DELETED_FUNCTION; - const MCInstrInfo &MCII; - MCContext &Ctx; - const MCSubtargetInfo &STI; - bool IsLittleEndian; - bool IsMicroMips; - -public: - MipsMCCodeEmitter(const MCInstrInfo &mcii, MCContext &Ctx_, - const MCSubtargetInfo &sti, bool IsLittle) : - MCII(mcii), Ctx(Ctx_), STI (sti), IsLittleEndian(IsLittle) { - IsMicroMips = STI.getFeatureBits() & Mips::FeatureMicroMips; - } - - ~MipsMCCodeEmitter() {} - - void EmitByte(unsigned char C, raw_ostream &OS) const { - OS << (char)C; - } - - void EmitInstruction(uint64_t Val, unsigned Size, raw_ostream &OS) const { - // Output the instruction encoding in little endian byte order. - // Little-endian byte ordering: - // mips32r2: 4 | 3 | 2 | 1 - // microMIPS: 2 | 1 | 4 | 3 - if (IsLittleEndian && Size == 4 && IsMicroMips) { - EmitInstruction(Val>>16, 2, OS); - EmitInstruction(Val, 2, OS); - } else { - for (unsigned i = 0; i < Size; ++i) { - unsigned Shift = IsLittleEndian ? i * 8 : (Size - 1 - i) * 8; - EmitByte((Val >> Shift) & 0xff, OS); - } - } - } - - void EncodeInstruction(const MCInst &MI, raw_ostream &OS, - SmallVectorImpl<MCFixup> &Fixups) const; - - // getBinaryCodeForInstr - TableGen'erated function for getting the - // binary encoding for an instruction. - uint64_t getBinaryCodeForInstr(const MCInst &MI, - SmallVectorImpl<MCFixup> &Fixups) const; - - // getBranchJumpOpValue - Return binary encoding of the jump - // target operand. If the machine operand requires relocation, - // record the relocation and return zero. - unsigned getJumpTargetOpValue(const MCInst &MI, unsigned OpNo, - SmallVectorImpl<MCFixup> &Fixups) const; - - // getBranchJumpOpValueMM - Return binary encoding of the microMIPS jump - // target operand. If the machine operand requires relocation, - // record the relocation and return zero. - unsigned getJumpTargetOpValueMM(const MCInst &MI, unsigned OpNo, - SmallVectorImpl<MCFixup> &Fixups) const; - - // getBranchTargetOpValue - Return binary encoding of the branch - // target operand. If the machine operand requires relocation, - // record the relocation and return zero. - unsigned getBranchTargetOpValue(const MCInst &MI, unsigned OpNo, - SmallVectorImpl<MCFixup> &Fixups) const; - - // getBranchTargetOpValue - Return binary encoding of the microMIPS branch - // target operand. If the machine operand requires relocation, - // record the relocation and return zero. - unsigned getBranchTargetOpValueMM(const MCInst &MI, unsigned OpNo, - SmallVectorImpl<MCFixup> &Fixups) const; - - // getMachineOpValue - Return binary encoding of operand. If the machin - // operand requires relocation, record the relocation and return zero. - unsigned getMachineOpValue(const MCInst &MI,const MCOperand &MO, - SmallVectorImpl<MCFixup> &Fixups) const; - - unsigned getMemEncoding(const MCInst &MI, unsigned OpNo, - SmallVectorImpl<MCFixup> &Fixups) const; - unsigned getMemEncodingMMImm12(const MCInst &MI, unsigned OpNo, - SmallVectorImpl<MCFixup> &Fixups) const; - unsigned getSizeExtEncoding(const MCInst &MI, unsigned OpNo, - SmallVectorImpl<MCFixup> &Fixups) const; - unsigned getSizeInsEncoding(const MCInst &MI, unsigned OpNo, - SmallVectorImpl<MCFixup> &Fixups) const; - - // getLSAImmEncoding - Return binary encoding of LSA immediate. - unsigned getLSAImmEncoding(const MCInst &MI, unsigned OpNo, - SmallVectorImpl<MCFixup> &Fixups) const; - - unsigned - getExprOpValue(const MCExpr *Expr,SmallVectorImpl<MCFixup> &Fixups) const; - -}; // class MipsMCCodeEmitter -} // namespace - -MCCodeEmitter *llvm::createMipsMCCodeEmitterEB(const MCInstrInfo &MCII, - const MCRegisterInfo &MRI, - const MCSubtargetInfo &STI, - MCContext &Ctx) -{ - return new MipsMCCodeEmitter(MCII, Ctx, STI, false); +#undef GET_INSTRMAP_INFO + +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); @@ -313,7 +247,8 @@ getBranchTargetOpValueMM(const MCInst &MI, unsigned OpNo, /// 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 +265,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 +282,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 +295,129 @@ 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::SymbolRef) { - Mips::Fixups FixupKind = Mips::Fixups(0); - switch(cast<MCSymbolRefExpr>(Expr)->getKind()) { - default: llvm_unreachable("Unknown fixup kind!"); - break; - case MCSymbolRefExpr::VK_Mips_GPOFF_HI : - FixupKind = Mips::fixup_Mips_GPOFF_HI; - break; - case MCSymbolRefExpr::VK_Mips_GPOFF_LO : - FixupKind = Mips::fixup_Mips_GPOFF_LO; - break; - case MCSymbolRefExpr::VK_Mips_GOT_PAGE : - FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_GOT_PAGE - : Mips::fixup_Mips_GOT_PAGE; - break; - case MCSymbolRefExpr::VK_Mips_GOT_OFST : - FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_GOT_OFST - : Mips::fixup_Mips_GOT_OFST; - break; - case MCSymbolRefExpr::VK_Mips_GOT_DISP : - FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_GOT_DISP - : Mips::fixup_Mips_GOT_DISP; - break; - case MCSymbolRefExpr::VK_Mips_GPREL: - FixupKind = Mips::fixup_Mips_GPREL16; - break; - case MCSymbolRefExpr::VK_Mips_GOT_CALL: - FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_CALL16 - : Mips::fixup_Mips_CALL16; - break; - case MCSymbolRefExpr::VK_Mips_GOT16: - FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_GOT16 - : Mips::fixup_Mips_GOT_Global; - break; - case MCSymbolRefExpr::VK_Mips_GOT: - FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_GOT16 - : Mips::fixup_Mips_GOT_Local; - break; - case MCSymbolRefExpr::VK_Mips_ABS_HI: - FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_HI16 - : Mips::fixup_Mips_HI16; - break; - case MCSymbolRefExpr::VK_Mips_ABS_LO: - FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_LO16 - : Mips::fixup_Mips_LO16; - break; - case MCSymbolRefExpr::VK_Mips_TLSGD: - FixupKind = Mips::fixup_Mips_TLSGD; - break; - case MCSymbolRefExpr::VK_Mips_TLSLDM: - FixupKind = Mips::fixup_Mips_TLSLDM; - break; - case MCSymbolRefExpr::VK_Mips_DTPREL_HI: - FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_TLS_DTPREL_HI16 - : Mips::fixup_Mips_DTPREL_HI; - break; - case MCSymbolRefExpr::VK_Mips_DTPREL_LO: - FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_TLS_DTPREL_LO16 - : Mips::fixup_Mips_DTPREL_LO; - break; - case MCSymbolRefExpr::VK_Mips_GOTTPREL: - FixupKind = Mips::fixup_Mips_GOTTPREL; - break; - case MCSymbolRefExpr::VK_Mips_TPREL_HI: - FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_TLS_TPREL_HI16 - : Mips::fixup_Mips_TPREL_HI; - break; - case MCSymbolRefExpr::VK_Mips_TPREL_LO: - FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_TLS_TPREL_LO16 - : Mips::fixup_Mips_TPREL_LO; - break; - case MCSymbolRefExpr::VK_Mips_HIGHER: - FixupKind = Mips::fixup_Mips_HIGHER; - break; - case MCSymbolRefExpr::VK_Mips_HIGHEST: - FixupKind = Mips::fixup_Mips_HIGHEST; - break; - case MCSymbolRefExpr::VK_Mips_GOT_HI16: - FixupKind = Mips::fixup_Mips_GOT_HI16; - break; - case MCSymbolRefExpr::VK_Mips_GOT_LO16: - FixupKind = Mips::fixup_Mips_GOT_LO16; - break; - case MCSymbolRefExpr::VK_Mips_CALL_HI16: - FixupKind = Mips::fixup_Mips_CALL_HI16; - break; - case MCSymbolRefExpr::VK_Mips_CALL_LO16: - FixupKind = Mips::fixup_Mips_CALL_LO16; - break; - } // switch + 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); + + 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; + } // switch Fixups.push_back(MCFixup::Create(0, Expr, MCFixupKind(FixupKind))); return 0; @@ -464,7 +429,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 +443,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,21 +529,23 @@ 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" diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h b/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h new file mode 100644 index 0000000..49a2490 --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h @@ -0,0 +1,125 @@ +//===-- 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; + + // 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; + + // 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 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 0000000..c7ba12d --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp @@ -0,0 +1,114 @@ +//===-- 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. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mipsmcexpr" +#include "MipsMCExpr.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" + +using namespace llvm; + +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); +} + +// FIXME: This basically copies MCObjectStreamer::AddValueSymbols. Perhaps +// that method should be made public? +static void AddValueSymbolsImpl(const MCExpr *Value, MCAssembler *Asm) { + switch (Value->getKind()) { + case MCExpr::Target: + llvm_unreachable("Can't handle nested target expr!"); + + case MCExpr::Constant: + break; + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value); + AddValueSymbolsImpl(BE->getLHS(), Asm); + AddValueSymbolsImpl(BE->getRHS(), Asm); + break; + } + + case MCExpr::SymbolRef: + Asm->getOrCreateSymbolData(cast<MCSymbolRefExpr>(Value)->getSymbol()); + break; + + case MCExpr::Unary: + AddValueSymbolsImpl(cast<MCUnaryExpr>(Value)->getSubExpr(), Asm); + break; + } +} + +void MipsMCExpr::AddValueSymbols(MCAssembler *Asm) const { + AddValueSymbolsImpl(getSubExpr(), Asm); +} diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h b/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h new file mode 100644 index 0000000..722bba7 --- /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; + bool EvaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout) const; + void AddValueSymbols(MCAssembler *) const; + const MCSection *FindAssociatedSection() const { + return getSubExpr()->FindAssociatedSection(); + } + + // There are no TLS MipsMCExprs at the moment. + void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {} + + 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 0000000..6992d06 --- /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 = NULL); +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 5548aaa..eecca68 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" @@ -39,36 +41,18 @@ 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; } @@ -131,21 +109,29 @@ 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); - - return llvm::createAsmStreamer(Ctx, S, OS, isVerboseAsm, useLoc, useCFI, - useDwarfDirectory, InstPrint, CE, TAB, - ShowInst); + bool isVerboseAsm, bool useCFI, bool useDwarfDirectory, + MCInstPrinter *InstPrint, MCCodeEmitter *CE, + MCAsmBackend *TAB, bool ShowInst) { + MCStreamer *S = + llvm::createAsmStreamer(Ctx, OS, isVerboseAsm, useCFI, useDwarfDirectory, + InstPrint, CE, TAB, ShowInst); + new MipsTargetAsmStreamer(*S, OS); + return S; } extern "C" void LLVMInitializeMipsTargetMC() { diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h b/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h index eabebfe..161d1ea 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 0000000..639a058 --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp @@ -0,0 +1,255 @@ +//===-- 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. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips-mc-nacl" + +#include "Mips.h" +#include "MipsELFStreamer.h" +#include "MipsMCNaCl.h" +#include "llvm/MC/MCELFStreamer.h" + +using namespace llvm; + +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) { + return MI.getOpcode() == Mips::JR || MI.getOpcode() == Mips::RET; + } + + bool isStackPointerFirstOperand(const MCInst &MI) { + return (MI.getNumOperands() > 0 && MI.getOperand(0).isReg() + && MI.getOperand(0).getReg() == Mips::SP); + } + + bool isCall(unsigned Opcode, bool *IsIndirectCall) { + *IsIndirectCall = false; + + switch (Opcode) { + default: + return false; + + case Mips::JAL: + case Mips::BAL_BR: + case Mips::BLTZAL: + case Mips::BGEZAL: + return true; + + case Mips::JALR: + *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. + virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) { + // 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) { + if (PendingCall) + report_fatal_error("Dangerous instruction in branch delay slot!"); + + bool MaskBefore = (IsMemAccess + && baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx) + .getReg())); + bool MaskAfter = IsSPFirstOperand && !IsStore; + if (MaskBefore || MaskAfter) + sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter); + else + MipsELFStreamer::EmitInstruction(Inst, STI); + return; + } + + // 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.getOpcode(), &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::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: + *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/MipsReginfo.cpp b/lib/Target/Mips/MCTargetDesc/MipsReginfo.cpp deleted file mode 100644 index 1dc9bcb..0000000 --- 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 039b8ea..0000000 --- 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 5e90bbc..fb6aff2 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -11,57 +11,368 @@ // //===----------------------------------------------------------------------===// +#include "InstPrinter/MipsInstPrinter.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); - -// pin vtable to this file +// Pin vtable to this file. void MipsTargetStreamer::anchor() {} -MipsTargetAsmStreamer::MipsTargetAsmStreamer(formatted_raw_ostream &OS) - : OS(OS) {} +MipsTargetStreamer::MipsTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {} + +MipsTargetAsmStreamer::MipsTargetAsmStreamer(MCStreamer &S, + formatted_raw_ostream &OS) + : MipsTargetStreamer(S), OS(OS) {} + +void MipsTargetAsmStreamer::emitDirectiveSetMicroMips() { + OS << "\t.set\tmicromips\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoMicroMips() { + OS << "\t.set\tnomicromips\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips16() { + OS << "\t.set\tmips16\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoMips16() { + OS << "\t.set\tnomips16\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveSetReorder() { + OS << "\t.set\treorder\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoReorder() { + OS << "\t.set\tnoreorder\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveSetMacro() { + OS << "\t.set\tmacro\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoMacro() { + OS << "\t.set\tnomacro\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveSetAt() { + OS << "\t.set\tat\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoAt() { + OS << "\t.set\tnoat\n"; +} + +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::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"; +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips64() { + OS << "\t.set\tmips64\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips64R2() { + OS << "\t.set\tmips64r2\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveSetDsp() { + OS << "\t.set\tdsp\n"; +} +// 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::emitFMask(unsigned FPUBitmask, + int FPUTopSavedRegOff) { + OS << "\t.fmask\t"; + printHex32(FPUBitmask, OS); + OS << "," << FPUTopSavedRegOff << '\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(); + 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::FeatureMips64r2) + EFlags |= ELF::EF_MIPS_ARCH_64R2; + else if (Features & Mips::FeatureMips64) + EFlags |= ELF::EF_MIPS_ARCH_64; + else if (Features & Mips::FeatureMips4) + EFlags |= ELF::EF_MIPS_ARCH_4; + else if (Features & Mips::FeatureMips32r2) + EFlags |= ELF::EF_MIPS_ARCH_32R2; + else if (Features & Mips::FeatureMips32) + EFlags |= ELF::EF_MIPS_ARCH_32; + + if (T.isArch64Bit()) { + if (Features & Mips::FeatureN32) + EFlags |= ELF::EF_MIPS_ABI2; + else if (Features & Mips::FeatureO32) { + EFlags |= ELF::EF_MIPS_ABI_O32; + EFlags |= ELF::EF_MIPS_32BITMODE; /* Compatibility Mode */ + } + // No need to set any bit for N64 which is the default ABI at the moment + // for 64-bit Mips architectures. + } else { + if (Features & Mips::FeatureMips64r2 || Features & Mips::FeatureMips64) + EFlags |= ELF::EF_MIPS_32BITMODE; + + // ABI + EFlags |= ELF::EF_MIPS_ABI_O32; + } + + MCA.setELFHeaderEFlags(EFlags); +} -void MipsTargetAsmStreamer::emitMipsHackELFFlags(unsigned Flags) { - if (!PrintHackDirectives) +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, ELF::STO_MIPS_MICROMIPS >> 2); +} + +void MipsTargetELFStreamer::finish() { + MCAssembler &MCA = getStreamer().getAssembler(); + MCContext &Context = MCA.getContext(); + MCStreamer &OS = getStreamer(); + Triple T(STI.getTargetTriple()); + uint64_t Features = STI.getFeatureBits(); + + if (T.isArch64Bit() && (Features & Mips::FeatureN64)) { + const MCSectionELF *Sec = Context.getELFSection( + ".MIPS.options", ELF::SHT_MIPS_OPTIONS, + ELF::SHF_ALLOC | ELF::SHF_MIPS_NOSTRIP, SectionKind::getMetadata()); + OS.SwitchSection(Sec); - OS << "\t.mips_hack_elf_flags 0x"; - OS.write_hex(Flags); - OS << '\n'; + 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 { + const MCSectionELF *Sec = + Context.getELFSection(".reginfo", ELF::SHT_MIPS_REGINFO, ELF::SHF_ALLOC, + SectionKind::getMetadata()); + OS.SwitchSection(Sec); + + 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 + } } -void MipsTargetAsmStreamer::emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val) { - if (!PrintHackDirectives) + +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; - OS << "\t.mips_hack_stocg "; - OS << Sym->getName(); - OS << ", "; - OS << Val; - OS << '\n'; + 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); + return static_cast<MCELFStreamer &>(Streamer); } -void MipsTargetELFStreamer::emitMipsHackELFFlags(unsigned Flags) { +void MipsTargetELFStreamer::emitDirectiveSetMicroMips() { + MicroMipsEnabled = true; + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags |= ELF::EF_MIPS_MICROMIPS; MCA.setELFHeaderEFlags(Flags); } -// Set a symbol's STO flags -void MipsTargetELFStreamer::emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val) { - MCSymbolData &Data = getStreamer().getOrCreateSymbolData(Sym); - // The "other" values are stored in the last 6 bits of the second byte - // The traditional defines for STO values assume the full byte and thus - // the shift to pack it. - MCELF::setOther(Data, Val >> 2); +void MipsTargetELFStreamer::emitDirectiveSetNoMicroMips() { + MicroMipsEnabled = false; +} + +void MipsTargetELFStreamer::emitDirectiveSetMips16() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags |= ELF::EF_MIPS_ARCH_ASE_M16; + MCA.setELFHeaderEFlags(Flags); +} + +void MipsTargetELFStreamer::emitDirectiveSetNoMips16() { + // FIXME: implement. +} + +void MipsTargetELFStreamer::emitDirectiveSetReorder() { + // FIXME: implement. +} + +void MipsTargetELFStreamer::emitDirectiveSetNoReorder() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags |= ELF::EF_MIPS_NOREORDER; + MCA.setELFHeaderEFlags(Flags); +} + +void MipsTargetELFStreamer::emitDirectiveSetMacro() { + // FIXME: implement. +} + +void MipsTargetELFStreamer::emitDirectiveSetNoMacro() { + // FIXME: implement. +} + +void MipsTargetELFStreamer::emitDirectiveSetAt() { + // FIXME: implement. +} + +void MipsTargetELFStreamer::emitDirectiveSetNoAt() { + // FIXME: implement. +} + +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::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() { + // No action required for ELF output. +} + +void MipsTargetELFStreamer::emitDirectiveSetMips64() { + // No action required for ELF output. +} + +void MipsTargetELFStreamer::emitDirectiveSetMips64R2() { + // No action required for ELF output. +} + +void MipsTargetELFStreamer::emitDirectiveSetDsp() { + // No action required for ELF output. } diff --git a/lib/Target/Mips/MSA.txt b/lib/Target/Mips/MSA.txt index d1c4193..113375f 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/MicroMipsInstrFPU.td b/lib/Target/Mips/MicroMipsInstrFPU.td new file mode 100644 index 0000000..91d447a --- /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>; +def SWXC1_MM : MMRel, SWXC1_FT<"swxc1", FGR32Opnd, II_SWXC1, store>, + SWXC1_FM_MM<0x88>; +def LUXC1_MM : MMRel, LWXC1_FT<"luxc1", AFGR64Opnd, II_LUXC1>, + LWXC1_FM_MM<0x148>; +def SUXC1_MM : MMRel, SWXC1_FT<"suxc1", AFGR64Opnd, II_SUXC1>, + SWXC1_FM_MM<0x188>; + +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>; +def BC1T_MM : MMRel, BC1F_FT<"bc1t", brtarget_mm, IIBranch, MIPS_BRANCH_T>, + BC1F_FM_MM<0x1d>; + +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>; +def CVT_L_D64_MM : MMRel, ABSS_FT<"cvt.l.d", FGR64Opnd, FGR64Opnd, II_CVT>, + ROUND_W_FM_MM<1, 0x4>; + +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>, Requires<[NotFP64bit, HasStdEnc]>; + +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>; +def MTHC1_MM : MMRel, MTC1_FT<"mthc1", FGRH32Opnd, GPR32Opnd, II_MTHC1>, + MFC1_FM_MM<7>; + +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 c12a32e..15b951d 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 d9507fa..3f13e83 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,18 +212,18 @@ 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>; /// 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>; + def SEH_MM : MMRel, SignExtInReg<"seh", i16, GPR32Opnd, II_SEH>, SEB_FM_MM<0x0ec>; /// Word Swap Bytes Within Halfwords def WSBH_MM : MMRel, SubwordSwap<"wsbh", GPR32Opnd>, SEB_FM_MM<0x1ec>; @@ -175,13 +238,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 JALR_MM : JumpLinkReg<"jalr", GPR32Opnd>, JALR_FM_MM<0x03c>; def RET_MM : MMRel, RetBase<"ret", GPR32Opnd>, JR_FM_MM<0x3c>; /// Branch Instructions @@ -202,6 +261,16 @@ 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>; + def DI_MM : MMRel, DEI_FT<"di", GPR32Opnd>, EI_FM_MM<0x11d>; + /// 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 +285,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 : InstAlias<"wait", (WAIT_MM 0x0), 1>; } diff --git a/lib/Target/Mips/Mips.h b/lib/Target/Mips/Mips.h index e796deb..d512d65 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 b8e3f39..10a4699 100644 --- a/lib/Target/Mips/Mips.td +++ b/lib/Target/Mips/Mips.td @@ -63,10 +63,13 @@ def FeatureMips32r2 : SubtargetFeature<"mips32r2", "MipsArchVersion", "Mips32r2", "Mips32r2 ISA Support", [FeatureMips32, FeatureSEInReg, FeatureSwap, FeatureFPIdx]>; +def FeatureMips4 : SubtargetFeature<"mips4", "MipsArchVersion", + "Mips4", "MIPS IV ISA Support", + [FeatureGP64Bit, FeatureFP64Bit, + FeatureCondMov]>; def FeatureMips64 : SubtargetFeature<"mips64", "MipsArchVersion", "Mips64", "Mips64 ISA Support", - [FeatureGP64Bit, FeatureFP64Bit, - FeatureMips32, FeatureFPIdx]>; + [FeatureMips4, FeatureMips32, FeatureFPIdx]>; def FeatureMips64r2 : SubtargetFeature<"mips64r2", "MipsArchVersion", "Mips64r2", "Mips64r2 ISA Support", [FeatureMips64, FeatureMips32r2]>; @@ -83,6 +86,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 +97,13 @@ 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 MipsAsmWriter : AsmWriter { - string AsmWriterClassName = "InstPrinter"; - bit isMCAsmWriter = 1; -} +def : Proc<"mips32", [FeatureMips32, FeatureO32]>; +def : Proc<"mips32r2", [FeatureMips32r2, FeatureO32]>; +def : Proc<"mips4", [FeatureMips4, FeatureN64]>; +def : Proc<"mips64", [FeatureMips64, FeatureN64]>; +def : Proc<"mips64r2", [FeatureMips64r2, FeatureN64]>; +def : Proc<"mips16", [FeatureMips16, FeatureO32]>; +def : Proc<"octeon", [FeatureMips64r2, FeatureN64, FeatureCnMips]>; def MipsAsmParser : AsmParser { let ShouldEmitMatchRegisterName = 0; @@ -116,6 +120,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 6655ff9..028b049 100644 --- a/lib/Target/Mips/Mips16FrameLowering.cpp +++ b/lib/Target/Mips/Mips16FrameLowering.cpp @@ -15,6 +15,7 @@ #include "MCTargetDesc/MipsBaseInfo.h" #include "Mips16InstrInfo.h" #include "MipsInstrInfo.h" +#include "MipsRegisterInfo.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" @@ -47,27 +48,27 @@ 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 S1 = MRI->getDwarfRegNum(Mips::S1, true); - MMI.addFrameInst(MCCFIInstruction::createOffset(CSLabel, S1, -12)); - - unsigned S0 = MRI->getDwarfRegNum(Mips::S0, true); - MMI.addFrameInst(MCCFIInstruction::createOffset(CSLabel, S0, -16)); - - unsigned RA = MRI->getDwarfRegNum(Mips::RA, true); - MMI.addFrameInst(MCCFIInstruction::createOffset(CSLabel, RA, -4)); - + 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(); + + 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); @@ -168,10 +169,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/Mips16HardFloat.cpp b/lib/Target/Mips/Mips16HardFloat.cpp index 81bf18c..d321e21 100644 --- a/lib/Target/Mips/Mips16HardFloat.cpp +++ b/lib/Target/Mips/Mips16HardFloat.cpp @@ -14,6 +14,7 @@ #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> @@ -167,6 +168,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 +245,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; @@ -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 = 0; + if (V) T = V->getType(); + const PointerType *PFT=0; + if (T) PFT = dyn_cast<PointerType>(T); + const FunctionType *FT=0; + 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/Mips16HardFloatInfo.cpp b/lib/Target/Mips/Mips16HardFloatInfo.cpp new file mode 100644 index 0000000..d8b685e --- /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 } }, + { 0, { 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 0; +} +} +} diff --git a/lib/Target/Mips/Mips16HardFloatInfo.h b/lib/Target/Mips/Mips16HardFloatInfo.h new file mode 100644 index 0000000..02444d9 --- /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 4948f40..9e36546 100644 --- a/lib/Target/Mips/Mips16ISelDAGToDAG.cpp +++ b/lib/Target/Mips/Mips16ISelDAGToDAG.cpp @@ -13,8 +13,8 @@ #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,11 +24,11 @@ #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" diff --git a/lib/Target/Mips/Mips16ISelLowering.cpp b/lib/Target/Mips/Mips16ISelLowering.cpp index 61d8bb8..5c6f302 100644 --- a/lib/Target/Mips/Mips16ISelLowering.cpp +++ b/lib/Target/Mips/Mips16ISelLowering.cpp @@ -12,12 +12,14 @@ //===----------------------------------------------------------------------===// #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; @@ -159,7 +161,9 @@ llvm::createMips16TargetLowering(MipsTargetMachine &TM) { } bool -Mips16TargetLowering::allowsUnalignedMemoryAccesses(EVT VT, bool *Fast) const { +Mips16TargetLowering::allowsUnalignedMemoryAccesses(EVT VT, + unsigned, + bool *Fast) const { return false; } @@ -429,8 +433,7 @@ getOpndList(SmallVectorImpl<SDValue> &Ops, const char* Mips16HelperFunction = 0; 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. @@ -444,7 +447,29 @@ getOpndList(SmallVectorImpl<SDValue> &Ops, 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), @@ -524,8 +549,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 +611,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 +675,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 +769,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 33b953f..618ec90 100644 --- a/lib/Target/Mips/Mips16ISelLowering.h +++ b/lib/Target/Mips/Mips16ISelLowering.h @@ -21,7 +21,8 @@ namespace llvm { public: explicit Mips16TargetLowering(MipsTargetMachine &TM); - virtual bool allowsUnalignedMemoryAccesses(EVT VT, bool *Fast) const; + virtual bool allowsUnalignedMemoryAccesses(EVT VT, unsigned AddrSpace, + bool *Fast) const; virtual MachineBasicBlock * EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const; diff --git a/lib/Target/Mips/Mips16InstrInfo.cpp b/lib/Target/Mips/Mips16InstrInfo.cpp index 000ea28..43c2fbd 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,13 +29,6 @@ using namespace llvm; -static cl::opt<bool> NeverUseSaveRestore( - "mips16-never-use-save-restore", - cl::init(false), - cl::desc("For testing ability to adjust stack pointer " - "without save/restore instruction"), - cl::Hidden); - Mips16InstrInfo::Mips16InstrInfo(MipsTargetMachine &tm) : MipsInstrInfo(tm, Mips::Bimm16), @@ -175,45 +169,56 @@ 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 { 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 +227,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. @@ -281,7 +275,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); @@ -393,7 +387,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 +411,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 +420,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 || diff --git a/lib/Target/Mips/Mips16InstrInfo.h b/lib/Target/Mips/Mips16InstrInfo.h index d9a594b..e93925c 100644 --- a/lib/Target/Mips/Mips16InstrInfo.h +++ b/lib/Target/Mips/Mips16InstrInfo.h @@ -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) { diff --git a/lib/Target/Mips/Mips16InstrInfo.td b/lib/Target/Mips/Mips16InstrInfo.td index 7441c78..11166c4 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; // // @@ -1374,7 +1378,9 @@ def: Mips16Pat< 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 +1896,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 9d0f2c9..3a50ed9 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" diff --git a/lib/Target/Mips/Mips64InstrInfo.td b/lib/Target/Mips/Mips64InstrInfo.td index 15ef654..7115d11 100644 --- a/lib/Target/Mips/Mips64InstrInfo.td +++ b/lib/Target/Mips/Mips64InstrInfo.td @@ -54,7 +54,7 @@ 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 DADDiu : ArithLogicI<"daddiu", simm16_64, GPR64Opnd, II_DADDIU, immSExt16, add>, ADDI_FM<0x19>, IsAsCheapAsAMove; @@ -63,86 +63,91 @@ 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>, +def DADD : ArithLogicR<"dadd", GPR64Opnd, 1, II_DADD>, ADD_FM<0, 0x2c>; +def DADDu : ArithLogicR<"daddu", GPR64Opnd, 1, II_DADDU, add>, ADD_FM<0, 0x2d>; -def DSUBu : ArithLogicR<"dsubu", GPR64Opnd, 0, IIArith, sub>, +def DSUBu : ArithLogicR<"dsubu", GPR64Opnd, 0, II_DSUBU, sub>, ADD_FM<0, 0x2f>; +def DSUB : ArithLogicR<"dsub", GPR64Opnd, 0, II_DSUB, sub>, ADD_FM<0, 0x2e>; 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>, +def DSLL : shift_rotate_imm<"dsll", uimm6, GPR64Opnd, II_DSLL, shl, immZExt6>, SRA_FM<0x38, 0>; -def DSRL : shift_rotate_imm<"dsrl", uimm6, GPR64Opnd, srl, immZExt6>, +def DSRL : shift_rotate_imm<"dsrl", uimm6, GPR64Opnd, II_DSRL, srl, immZExt6>, SRA_FM<0x3a, 0>; -def DSRA : shift_rotate_imm<"dsra", uimm6, GPR64Opnd, sra, immZExt6>, +def DSRA : shift_rotate_imm<"dsra", uimm6, GPR64Opnd, II_DSRA, 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 DSLLV : shift_rotate_reg<"dsllv", GPR64Opnd, II_DSLLV, shl>, + SRLV_FM<0x14, 0>; +def DSRLV : shift_rotate_reg<"dsrlv", GPR64Opnd, II_DSRLV, srl>, + SRLV_FM<0x16, 0>; +def DSRAV : shift_rotate_reg<"dsrav", GPR64Opnd, II_DSRAV, sra>, + SRLV_FM<0x17, 0>; +def DSLL32 : shift_rotate_imm<"dsll32", uimm5, GPR64Opnd, II_DSLL32>, + SRA_FM<0x3c, 0>; +def DSRL32 : shift_rotate_imm<"dsrl32", uimm5, GPR64Opnd, II_DSRL32>, + SRA_FM<0x3e, 0>; +def DSRA32 : shift_rotate_imm<"dsra32", uimm5, GPR64Opnd, II_DSRA32>, + SRA_FM<0x3f, 0>; // Rotate Instructions let Predicates = [HasMips64r2, HasStdEnc] in { - def DROTR : shift_rotate_imm<"drotr", uimm6, GPR64Opnd, rotr, immZExt6>, - SRA_FM<0x3a, 1>; - def DROTRV : shift_rotate_reg<"drotrv", GPR64Opnd, rotr>, + def DROTR : shift_rotate_imm<"drotr", uimm6, GPR64Opnd, II_DROTR, rotr, + immZExt6>, SRA_FM<0x3a, 1>; + def DROTRV : shift_rotate_reg<"drotrv", GPR64Opnd, II_DROTRV, rotr>, SRLV_FM<0x16, 1>; - def DROTR32 : shift_rotate_imm<"drotr32", uimm5, GPR64Opnd>, SRA_FM<0x3e, 1>; + def DROTR32 : shift_rotate_imm<"drotr32", uimm5, GPR64Opnd, II_DROTR32>, + SRA_FM<0x3e, 1>; } /// Load and Store Instructions /// aligned let isCodeGenOnly = 1 in { -def LB64 : Load<"lb", GPR64Opnd, sextloadi8, IILoad>, LW_FM<0x20>; -def LBu64 : Load<"lbu", GPR64Opnd, zextloadi8, IILoad>, LW_FM<0x24>; -def LH64 : Load<"lh", GPR64Opnd, sextloadi16, IILoad>, LW_FM<0x21>; -def LHu64 : Load<"lhu", GPR64Opnd, zextloadi16, IILoad>, LW_FM<0x25>; -def LW64 : Load<"lw", GPR64Opnd, sextloadi32, IILoad>, LW_FM<0x23>; -def SB64 : Store<"sb", GPR64Opnd, truncstorei8, IIStore>, LW_FM<0x28>; -def SH64 : Store<"sh", GPR64Opnd, truncstorei16, IIStore>, LW_FM<0x29>; -def SW64 : Store<"sw", GPR64Opnd, truncstorei32, IIStore>, LW_FM<0x2b>; +def 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>; +def LD : Load<"ld", GPR64Opnd, load, II_LD>, LW_FM<0x37>; +def SD : Store<"sd", GPR64Opnd, store, II_SD>, LW_FM<0x3f>; /// load/store left/right let isCodeGenOnly = 1 in { -def LWL64 : LoadLeftRight<"lwl", MipsLWL, GPR64Opnd, IILoad>, LW_FM<0x22>; -def LWR64 : LoadLeftRight<"lwr", MipsLWR, GPR64Opnd, IILoad>, LW_FM<0x26>; -def SWL64 : StoreLeftRight<"swl", MipsSWL, GPR64Opnd, IIStore>, LW_FM<0x2a>; -def SWR64 : StoreLeftRight<"swr", MipsSWR, GPR64Opnd, IIStore>, LW_FM<0x2e>; +def 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>; +def LDR : LoadLeftRight<"ldr", MipsLDR, GPR64Opnd, II_LDR>, LW_FM<0x1b>; +def SDL : StoreLeftRight<"sdl", MipsSDL, GPR64Opnd, II_SDL>, LW_FM<0x2c>; +def SDR : StoreLeftRight<"sdr", MipsSDR, GPR64Opnd, II_SDR>, LW_FM<0x2d>; /// Load-linked, Store-conditional def LLD : LLBase<"lld", GPR64Opnd>, LW_FM<0x34>; @@ -159,25 +164,26 @@ 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 TAILCALL64_R : TailCallReg<GPR64Opnd, JR, GPR32Opnd>; } /// Multiply and Divide Instructions. -def DMULT : Mult<"dmult", IIImult, GPR64Opnd, [HI0_64, LO0_64]>, +def DMULT : Mult<"dmult", II_DMULT, GPR64Opnd, [HI0_64, LO0_64]>, MULT_FM<0, 0x1c>; -def DMULTu : Mult<"dmultu", IIImult, GPR64Opnd, [HI0_64, LO0_64]>, +def DMULTu : Mult<"dmultu", II_DMULTU, GPR64Opnd, [HI0_64, LO0_64]>, MULT_FM<0, 0x1d>; def PseudoDMULT : MultDivPseudo<DMULT, ACC128, GPR64Opnd, MipsMult, - IIImult>; + II_DMULT>; 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>; +def DSDIV : Div<"ddiv", II_DDIV, GPR64Opnd, [HI0_64, LO0_64]>, + MULT_FM<0, 0x1e>; +def DUDIV : Div<"ddivu", II_DDIVU, GPR64Opnd, [HI0_64, LO0_64]>, + MULT_FM<0, 0x1f>; def PseudoDSDIV : MultDivPseudo<DSDIV, ACC128, GPR64Opnd, MipsDivRem, - IIIdiv, 0, 1, 1>; + II_DDIV, 0, 1, 1>; def PseudoDUDIV : MultDivPseudo<DUDIV, ACC128, GPR64Opnd, MipsDivRemU, - IIIdiv, 0, 1, 1>; + II_DDIVU, 0, 1, 1>; let isCodeGenOnly = 1 in { def MTHI64 : MoveToLOHI<"mthi", GPR64Opnd, [HI0_64]>, MTLO_FM<0x11>; @@ -189,8 +195,8 @@ def PseudoMFLO64 : PseudoMFLOHI<GPR64, ACC128, MipsMFLO>; def PseudoMTLOHI64 : PseudoMTLOHI<ACC128, GPR64>; /// Sign Ext In Register Instructions. -def SEB64 : SignExtInReg<"seb", i8, GPR64Opnd>, SEB_FM<0x10, 0x20>; -def SEH64 : SignExtInReg<"seh", i16, GPR64Opnd>, SEB_FM<0x18, 0x20>; +def SEB64 : SignExtInReg<"seb", i8, GPR64Opnd, II_SEB>, SEB_FM<0x10, 0x20>; +def SEH64 : SignExtInReg<"seh", i16, GPR64Opnd, II_SEH>, SEB_FM<0x18, 0x20>; } /// Count Leading @@ -216,13 +222,76 @@ 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>; } + +// Cavium Octeon cmMIPS instructions +let Predicates = [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"; } + +// 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 SNE : SetCC64_R<"sne", setne>, SEQ_FM<0x2b>; +} + +} + //===----------------------------------------------------------------------===// // Arbitrary patterns that map to one or more instructions //===----------------------------------------------------------------------===// @@ -313,6 +382,43 @@ def : InstAlias<"daddu $rs, $rt, $imm", def : InstAlias<"dadd $rs, $rt, $imm", (DADDi GPR64Opnd:$rs, GPR64Opnd:$rt, simm16_64:$imm), 0>; +def : InstAlias<"daddu $rs, $imm", + (DADDiu GPR64Opnd:$rs, GPR64Opnd:$rs, simm16_64:$imm), + 0>; +def : InstAlias<"dadd $rs, $imm", + (DADDi GPR64Opnd:$rs, GPR64Opnd:$rs, simm16_64:$imm), + 0>; +def : InstAlias<"add $rs, $imm", + (ADDi GPR32Opnd:$rs, GPR32Opnd:$rs, simm16:$imm), + 0>; +def : InstAlias<"addu $rs, $imm", + (ADDiu GPR32Opnd:$rs, GPR32Opnd:$rs, simm16:$imm), + 0>; +let isPseudo=1, usesCustomInserter=1, isCodeGenOnly=1 in { +def SUBi : MipsInst<(outs GPR32Opnd: $rt), (ins GPR32Opnd: $rs, simm16: $imm), + "sub\t$rt, $rs, $imm", [], II_DSUB, Pseudo>; +def SUBiu : MipsInst<(outs GPR32Opnd: $rt), (ins GPR32Opnd: $rs, simm16: $imm), + "subu\t$rt, $rs, $imm", [], II_DSUB, Pseudo>; +def DSUBi : MipsInst<(outs GPR64Opnd: $rt), (ins GPR64Opnd: $rs, simm16_64: $imm), + "ssub\t$rt, $rs, $imm", [], II_DSUB, Pseudo>; +def DSUBiu : MipsInst<(outs GPR64Opnd: $rt), (ins GPR64Opnd: $rs, simm16_64: $imm), + "ssubu\t$rt, $rs, $imm", [], II_DSUB, Pseudo>; +} +def : InstAlias<"dsubu $rt, $rs, $imm", + (DSUBiu GPR64Opnd:$rt, GPR64Opnd:$rs, simm16_64: $imm), + 0>; +def : InstAlias<"sub $rs, $imm", + (SUBi GPR32Opnd:$rs, GPR32Opnd:$rs, simm16:$imm), + 0>; +def : InstAlias<"subu $rs, $imm", + (SUBiu GPR32Opnd:$rs, GPR32Opnd:$rs, simm16:$imm), + 0>; +def : InstAlias<"dsub $rs, $imm", + (DSUBi GPR64Opnd:$rs, GPR64Opnd:$rs, simm16_64:$imm), + 0>; +def : InstAlias<"dsubu $rs, $imm", + (DSUBiu GPR64Opnd:$rs, GPR64Opnd:$rs, simm16_64:$imm), + 0>; /// Move between CPU and coprocessor registers let DecoderNamespace = "Mips64", Predicates = [HasMips64] in { diff --git a/lib/Target/Mips/MipsAsmPrinter.cpp b/lib/Target/Mips/MipsAsmPrinter.cpp index 45c4398..d5df855 100644 --- a/lib/Target/Mips/MipsAsmPrinter.cpp +++ b/lib/Target/Mips/MipsAsmPrinter.cpp @@ -15,6 +15,7 @@ #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,26 +28,32 @@ #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; MipsTargetStreamer &MipsAsmPrinter::getTargetStreamer() { - return static_cast<MipsTargetStreamer &>(OutStreamer.getTargetStreamer()); + return static_cast<MipsTargetStreamer &>(*OutStreamer.getTargetStreamer()); } bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) { @@ -55,7 +62,23 @@ bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) { 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; } @@ -129,7 +152,7 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { MCInst TmpInst0; MCInstLowering.Lower(I, TmpInst0); - OutStreamer.EmitInstruction(TmpInst0); + EmitToStreamer(OutStreamer, TmpInst0); } while ((++I != E) && I->isInsideBundle()); // Delay slot check } @@ -170,7 +193,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 +241,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 +261,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 +276,33 @@ 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(); + // leave out until FSF available gas has micromips changes + // 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 +312,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 +510,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 +558,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 +619,299 @@ 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")); - } + getTargetStreamer().emitDirectiveAbiCalls(); + Reloc::Model RM = Subtarget->getRelocationModel(); + if (RM == Reloc::Static && !Subtarget->hasMips64()) + 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())); // TODO: handle O64 ABI - if (OutStreamer.hasRawTextSupport()) { - if (Subtarget->isABI_EABI()) { - if (Subtarget->isGP32bit()) - OutStreamer.EmitRawText(StringRef("\t.section .gcc_compiled_long32")); - else - OutStreamer.EmitRawText(StringRef("\t.section .gcc_compiled_long64")); - } - } - // return to previous section - if (OutStreamer.hasRawTextSupport()) - OutStreamer.EmitRawText(StringRef("\t.previous")); + 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())); + } +} +void MipsAsmPrinter::EmitJal(MCSymbol *Symbol) { + MCInst I; + I.setOpcode(Mips::JAL); + I.addOperand( + MCOperand::CreateExpr(MCSymbolRefExpr::Create(Symbol, OutContext))); + OutStreamer.EmitInstruction(I, getSubtargetInfo()); } -static void emitELFHeaderFlagsCG(MipsTargetStreamer &TargetStreamer, - const MipsSubtarget &Subtarget) { - // Update e_header flags - unsigned EFlags = 0; +void MipsAsmPrinter::EmitInstrReg(unsigned Opcode, unsigned Reg) { + MCInst I; + I.setOpcode(Opcode); + I.addOperand(MCOperand::CreateReg(Reg)); + 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::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()); +} - if (Subtarget.inMips16Mode()) - EFlags |= ELF::EF_MIPS_ARCH_ASE_M16; - else - EFlags |= ELF::EF_MIPS_NOREORDER; - - // Architecture - if (Subtarget.hasMips64r2()) - EFlags |= ELF::EF_MIPS_ARCH_64R2; - else if (Subtarget.hasMips64()) - EFlags |= ELF::EF_MIPS_ARCH_64; - else if (Subtarget.hasMips32r2()) - EFlags |= ELF::EF_MIPS_ARCH_32R2; - else - EFlags |= ELF::EF_MIPS_ARCH_32; +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; + } +} - TargetStreamer.emitMipsHackELFFlags(EFlags); +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, 0); + // + // .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); + + 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 +919,28 @@ 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); + } +} + // 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 11c6acd..3e9093e 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" @@ -50,7 +51,29 @@ 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); public: @@ -62,8 +85,6 @@ public: : AsmPrinter(TM, Streamer), MCP(0), InConstantPool(false), MCInstLowering(*this) { Subtarget = &TM.getSubtarget<MipsSubtarget>(); - UsingConstantPools = - (Subtarget->inMips16Mode() && Subtarget->useConstantIslands()); } virtual const char *getPassName() const { @@ -72,15 +93,16 @@ public: virtual bool runOnMachineFunction(MachineFunction &MF); - virtual void EmitConstantPool() LLVM_OVERRIDE { + virtual 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 printSavedRegsBitmask(); void emitFrameDirective(); const char *getCurrentABIString() const; virtual void EmitFunctionEntryLabel(); diff --git a/lib/Target/Mips/MipsCallingConv.td b/lib/Target/Mips/MipsCallingConv.td index 66391cb..615310f 100644 --- a/lib/Target/Mips/MipsCallingConv.td +++ b/lib/Target/Mips/MipsCallingConv.td @@ -192,8 +192,15 @@ 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, @@ -246,4 +253,6 @@ 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 ca4163d..ea49086 100644 --- a/lib/Target/Mips/MipsCodeEmitter.cpp +++ b/lib/Target/Mips/MipsCodeEmitter.cpp @@ -24,8 +24,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" @@ -112,13 +112,11 @@ private: 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; - /// Expand pseudo instructions with accumulator register operands. void expandACCInstr(MachineBasicBlock::instr_iterator MI, MachineBasicBlock &MBB, unsigned Opc) const; @@ -224,6 +222,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. @@ -273,14 +277,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(), diff --git a/lib/Target/Mips/MipsCondMov.td b/lib/Target/Mips/MipsCondMov.td index 2de1430..567eef9 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,94 +103,94 @@ multiclass MovnPats<RegisterClass CRC, RegisterClass DRC, Instruction MOVNInst, } // Instantiation of instructions. -def MOVZ_I_I : MMRel, CMov_I_I_FT<"movz", GPR32Opnd, GPR32Opnd, IIArith>, +def MOVZ_I_I : MMRel, CMov_I_I_FT<"movz", GPR32Opnd, GPR32Opnd, II_MOVZ>, ADD_FM<0, 0xa>; let Predicates = [HasStdEnc], isCodeGenOnly = 1 in { - def MOVZ_I_I64 : CMov_I_I_FT<"movz", GPR32Opnd, GPR64Opnd, IIArith>, + def MOVZ_I_I64 : CMov_I_I_FT<"movz", GPR32Opnd, GPR64Opnd, II_MOVZ>, ADD_FM<0, 0xa>; - def MOVZ_I64_I : CMov_I_I_FT<"movz", GPR64Opnd, GPR32Opnd, IIArith>, + def MOVZ_I64_I : CMov_I_I_FT<"movz", GPR64Opnd, GPR32Opnd, II_MOVZ>, ADD_FM<0, 0xa>; - def MOVZ_I64_I64 : CMov_I_I_FT<"movz", GPR64Opnd, GPR64Opnd, IIArith>, + def MOVZ_I64_I64 : CMov_I_I_FT<"movz", GPR64Opnd, GPR64Opnd, II_MOVZ>, ADD_FM<0, 0xa>; } -def MOVN_I_I : MMRel, CMov_I_I_FT<"movn", GPR32Opnd, GPR32Opnd, IIArith>, +def MOVN_I_I : MMRel, CMov_I_I_FT<"movn", GPR32Opnd, GPR32Opnd, II_MOVN>, ADD_FM<0, 0xb>; let Predicates = [HasStdEnc], isCodeGenOnly = 1 in { - def MOVN_I_I64 : CMov_I_I_FT<"movn", GPR32Opnd, GPR64Opnd, IIArith>, + def MOVN_I_I64 : CMov_I_I_FT<"movn", GPR32Opnd, GPR64Opnd, II_MOVN>, ADD_FM<0, 0xb>; - def MOVN_I64_I : CMov_I_I_FT<"movn", GPR64Opnd, GPR32Opnd, IIArith>, + def MOVN_I64_I : CMov_I_I_FT<"movn", GPR64Opnd, GPR32Opnd, II_MOVN>, ADD_FM<0, 0xb>; - def MOVN_I64_I64 : CMov_I_I_FT<"movn", GPR64Opnd, GPR64Opnd, IIArith>, + def MOVN_I64_I64 : CMov_I_I_FT<"movn", GPR64Opnd, GPR64Opnd, II_MOVN>, ADD_FM<0, 0xb>; } -def MOVZ_I_S : CMov_I_F_FT<"movz.s", GPR32Opnd, FGR32Opnd, IIFmove>, +def MOVZ_I_S : MMRel, CMov_I_F_FT<"movz.s", GPR32Opnd, FGR32Opnd, II_MOVZ_S>, CMov_I_F_FM<18, 16>; let isCodeGenOnly = 1 in -def MOVZ_I64_S : CMov_I_F_FT<"movz.s", GPR64Opnd, FGR32Opnd, IIFmove>, +def MOVZ_I64_S : CMov_I_F_FT<"movz.s", GPR64Opnd, FGR32Opnd, II_MOVZ_S>, CMov_I_F_FM<18, 16>, Requires<[HasMips64, HasStdEnc]>; -def MOVN_I_S : CMov_I_F_FT<"movn.s", GPR32Opnd, FGR32Opnd, IIFmove>, +def MOVN_I_S : MMRel, CMov_I_F_FT<"movn.s", GPR32Opnd, FGR32Opnd, II_MOVN_S>, CMov_I_F_FM<19, 16>; let isCodeGenOnly = 1 in -def MOVN_I64_S : CMov_I_F_FT<"movn.s", GPR64Opnd, FGR32Opnd, IIFmove>, +def MOVN_I64_S : CMov_I_F_FT<"movn.s", GPR64Opnd, FGR32Opnd, II_MOVN_S>, CMov_I_F_FM<19, 16>, Requires<[HasMips64, HasStdEnc]>; let Predicates = [NotFP64bit, HasStdEnc] in { - def MOVZ_I_D32 : CMov_I_F_FT<"movz.d", GPR32Opnd, AFGR64Opnd, IIFmove>, - CMov_I_F_FM<18, 17>; - def MOVN_I_D32 : CMov_I_F_FT<"movn.d", GPR32Opnd, AFGR64Opnd, IIFmove>, - CMov_I_F_FM<19, 17>; + def MOVZ_I_D32 : MMRel, CMov_I_F_FT<"movz.d", GPR32Opnd, AFGR64Opnd, + II_MOVZ_D>, CMov_I_F_FM<18, 17>; + def MOVN_I_D32 : MMRel, CMov_I_F_FT<"movn.d", GPR32Opnd, AFGR64Opnd, + II_MOVN_D>, CMov_I_F_FM<19, 17>; } let Predicates = [IsFP64bit, HasStdEnc], DecoderNamespace = "Mips64" in { - def MOVZ_I_D64 : CMov_I_F_FT<"movz.d", GPR32Opnd, FGR64Opnd, IIFmove>, + def MOVZ_I_D64 : CMov_I_F_FT<"movz.d", GPR32Opnd, FGR64Opnd, II_MOVZ_D>, CMov_I_F_FM<18, 17>; - def MOVN_I_D64 : CMov_I_F_FT<"movn.d", GPR32Opnd, FGR64Opnd, IIFmove>, + def MOVN_I_D64 : CMov_I_F_FT<"movn.d", GPR32Opnd, FGR64Opnd, II_MOVN_D>, CMov_I_F_FM<19, 17>; let isCodeGenOnly = 1 in { def MOVZ_I64_D64 : CMov_I_F_FT<"movz.d", GPR64Opnd, FGR64Opnd, - IIFmove>, CMov_I_F_FM<18, 17>; + II_MOVZ_D>, 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>; + II_MOVN_D>, CMov_I_F_FM<19, 17>; } } -def MOVT_I : MMRel, CMov_F_I_FT<"movt", GPR32Opnd, IIArith, MipsCMovFP_T>, +def MOVT_I : MMRel, CMov_F_I_FT<"movt", GPR32Opnd, II_MOVT, MipsCMovFP_T>, CMov_F_I_FM<1>; let isCodeGenOnly = 1 in -def MOVT_I64 : CMov_F_I_FT<"movt", GPR64Opnd, IIArith, MipsCMovFP_T>, +def MOVT_I64 : CMov_F_I_FT<"movt", GPR64Opnd, II_MOVT, MipsCMovFP_T>, CMov_F_I_FM<1>, Requires<[HasMips64, HasStdEnc]>; -def MOVF_I : MMRel, CMov_F_I_FT<"movf", GPR32Opnd, IIArith, MipsCMovFP_F>, +def MOVF_I : MMRel, CMov_F_I_FT<"movf", GPR32Opnd, II_MOVF, MipsCMovFP_F>, CMov_F_I_FM<0>; let isCodeGenOnly = 1 in -def MOVF_I64 : CMov_F_I_FT<"movf", GPR64Opnd, IIArith, MipsCMovFP_F>, +def MOVF_I64 : CMov_F_I_FT<"movf", GPR64Opnd, II_MOVF, MipsCMovFP_F>, CMov_F_I_FM<0>, Requires<[HasMips64, HasStdEnc]>; -def MOVT_S : CMov_F_F_FT<"movt.s", FGR32Opnd, IIFmove, MipsCMovFP_T>, +def MOVT_S : MMRel, CMov_F_F_FT<"movt.s", FGR32Opnd, II_MOVT_S, MipsCMovFP_T>, CMov_F_F_FM<16, 1>; -def MOVF_S : CMov_F_F_FT<"movf.s", FGR32Opnd, IIFmove, MipsCMovFP_F>, +def MOVF_S : MMRel, CMov_F_F_FT<"movf.s", FGR32Opnd, II_MOVF_S, MipsCMovFP_F>, CMov_F_F_FM<16, 0>; let Predicates = [NotFP64bit, HasStdEnc] in { - def MOVT_D32 : CMov_F_F_FT<"movt.d", AFGR64Opnd, IIFmove, MipsCMovFP_T>, - CMov_F_F_FM<17, 1>; - def MOVF_D32 : CMov_F_F_FT<"movf.d", AFGR64Opnd, IIFmove, MipsCMovFP_F>, - CMov_F_F_FM<17, 0>; + def MOVT_D32 : MMRel, CMov_F_F_FT<"movt.d", AFGR64Opnd, II_MOVT_D, + MipsCMovFP_T>, CMov_F_F_FM<17, 1>; + def MOVF_D32 : MMRel, CMov_F_F_FT<"movf.d", AFGR64Opnd, II_MOVF_D, + MipsCMovFP_F>, CMov_F_F_FM<17, 0>; } let Predicates = [IsFP64bit, HasStdEnc], DecoderNamespace = "Mips64" in { - def MOVT_D64 : CMov_F_F_FT<"movt.d", FGR64Opnd, IIFmove, MipsCMovFP_T>, + def MOVT_D64 : CMov_F_F_FT<"movt.d", FGR64Opnd, II_MOVT_D, MipsCMovFP_T>, CMov_F_F_FM<17, 1>; - def MOVF_D64 : CMov_F_F_FT<"movf.d", FGR64Opnd, IIFmove, MipsCMovFP_F>, + def MOVF_D64 : CMov_F_F_FT<"movf.d", FGR64Opnd, II_MOVF_D, MipsCMovFP_F>, CMov_F_F_FM<17, 0>; } diff --git a/lib/Target/Mips/MipsConstantIslandPass.cpp b/lib/Target/Mips/MipsConstantIslandPass.cpp index c46bbac..e5642ba 100644 --- a/lib/Target/Mips/MipsConstantIslandPass.cpp +++ b/lib/Target/Mips/MipsConstantIslandPass.cpp @@ -17,7 +17,7 @@ // // 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. // // @@ -34,15 +34,15 @@ #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; @@ -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 { @@ -277,16 +384,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 +423,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) { @@ -509,10 +604,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) @@ -603,6 +698,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 +778,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 +920,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); @@ -1062,7 +1206,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 +1265,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 +1318,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 +1375,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 +1393,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 +1418,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 +1435,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) @@ -1380,7 +1525,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 +1545,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 +1578,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 +1612,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 +1649,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 +1657,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 +1683,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/MipsDelaySlotFiller.cpp b/lib/Target/Mips/MipsDelaySlotFiller.cpp index ffbd83b..eef9f38 100644 --- a/lib/Target/Mips/MipsDelaySlotFiller.cpp +++ b/lib/Target/Mips/MipsDelaySlotFiller.cpp @@ -13,6 +13,7 @@ #define DEBUG_TYPE "delay-slot-filler" +#include "MCTargetDesc/MipsMCNaCl.h" #include "Mips.h" #include "MipsInstrInfo.h" #include "MipsTargetMachine.h" @@ -65,20 +66,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); @@ -514,8 +501,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 +532,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 +564,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 +581,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; } @@ -640,8 +639,12 @@ MachineBasicBlock *Filler::selectSuccBB(MachineBasicBlock &B) const { return NULL; // Select the successor with the larget edge weight. - CmpWeight Cmp(B, getAnalysis<MachineBranchProbabilityInfo>()); - MachineBasicBlock *S = *std::max_element(B.succ_begin(), B.succ_end(), Cmp); + 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() ? NULL : S; } @@ -714,6 +717,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/MipsISelDAGToDAG.cpp b/lib/Target/Mips/MipsISelDAGToDAG.cpp index c417bd5..941aeac 100644 --- a/lib/Target/Mips/MipsISelDAGToDAG.cpp +++ b/lib/Target/Mips/MipsISelDAGToDAG.cpp @@ -13,23 +13,23 @@ #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" @@ -93,6 +93,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."); diff --git a/lib/Target/Mips/MipsISelDAGToDAG.h b/lib/Target/Mips/MipsISelDAGToDAG.h index a4d9da5..4546182 100644 --- a/lib/Target/Mips/MipsISelDAGToDAG.h +++ b/lib/Target/Mips/MipsISelDAGToDAG.h @@ -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); diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index 1e8250c..abf36da 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -197,16 +197,14 @@ 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"; + case MipsISD::INSVE: return "MipsISD::INSVE"; default: return NULL; } } -MipsTargetLowering:: -MipsTargetLowering(MipsTargetMachine &TM) - : TargetLowering(TM, new MipsTargetObjectFile()), - Subtarget(&TM.getSubtarget<MipsSubtarget>()), - HasMips64(Subtarget->hasMips64()), IsN64(Subtarget->isABI_N64()), - IsO32(Subtarget->isABI_O32()) { +MipsTargetLowering::MipsTargetLowering(MipsTargetMachine &TM) + : TargetLowering(TM, new MipsTargetObjectFile()), + Subtarget(&TM.getSubtarget<MipsSubtarget>()) { // Mips does not have i1 type, so use i32 for // setcc operations results (slt, sgt, ...). setBooleanContents(ZeroOrOneBooleanContent); @@ -252,7 +250,7 @@ MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::FABS, MVT::f64, Custom); } - if (HasMips64) { + if (hasMips64()) { setOperationAction(ISD::GlobalAddress, MVT::i64, Custom); setOperationAction(ISD::BlockAddress, MVT::i64, Custom); setOperationAction(ISD::GlobalTLSAddress, MVT::i64, Custom); @@ -264,14 +262,14 @@ MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::FP_TO_SINT, MVT::i64, Custom); } - if (!HasMips64) { + if (!hasMips64()) { setOperationAction(ISD::SHL_PARTS, MVT::i32, Custom); setOperationAction(ISD::SRA_PARTS, MVT::i32, Custom); setOperationAction(ISD::SRL_PARTS, MVT::i32, Custom); } setOperationAction(ISD::ADD, MVT::i32, Custom); - if (HasMips64) + if (hasMips64()) setOperationAction(ISD::ADD, MVT::i64, Custom); setOperationAction(ISD::SDIV, MVT::i32, Expand); @@ -294,8 +292,13 @@ MipsTargetLowering(MipsTargetMachine &TM) 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); @@ -368,7 +371,7 @@ MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::BSWAP, MVT::i64, Expand); } - if (HasMips64) { + if (hasMips64()) { setLoadExtAction(ISD::SEXTLOAD, MVT::i32, Custom); setLoadExtAction(ISD::ZEXTLOAD, MVT::i32, Custom); setLoadExtAction(ISD::EXTLOAD, MVT::i32, Custom); @@ -384,14 +387,16 @@ MipsTargetLowering(MipsTargetMachine &TM) setTargetDAGCombine(ISD::OR); setTargetDAGCombine(ISD::ADD); - setMinFunctionAlignment(HasMips64 ? 3 : 2); + setMinFunctionAlignment(hasMips64() ? 3 : 2); - setStackPointerRegisterToSaveRestore(IsN64 ? Mips::SP_64 : Mips::SP); + setStackPointerRegisterToSaveRestore(isN64() ? Mips::SP_64 : Mips::SP); - setExceptionPointerRegister(IsN64 ? Mips::A0_64 : Mips::A0); - setExceptionSelectorRegister(IsN64 ? Mips::A1_64 : Mips::A1); + setExceptionPointerRegister(isN64() ? Mips::A0_64 : Mips::A0); + setExceptionSelectorRegister(isN64() ? Mips::A1_64 : Mips::A1); MaxStoresPerMemcpy = 16; + + isMicroMips = Subtarget->inMicroMipsMode(); } const MipsTargetLowering *MipsTargetLowering::create(MipsTargetMachine &TM) { @@ -535,19 +540,65 @@ 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); - SetCC = DAG.getSetCC(DL, SetCC.getValueType(), SetCC.getOperand(0), - SetCC.getOperand(1), ISD::getSetCCInverse(CC, 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); + + // 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, @@ -770,7 +821,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); @@ -885,8 +936,8 @@ MipsTargetLowering::emitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB, unsigned LL, SC, AND, NOR, ZERO, BEQ; if (Size == 4) { - LL = Mips::LL; - SC = Mips::SC; + LL = isMicroMips ? Mips::LL_MM : Mips::LL; + SC = isMicroMips ? Mips::SC_MM : Mips::SC; AND = Mips::AND; NOR = Mips::NOR; ZERO = Mips::ZERO; @@ -920,7 +971,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: @@ -1006,7 +1057,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); @@ -1128,8 +1179,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 +1212,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: @@ -1247,7 +1298,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); @@ -1365,7 +1416,7 @@ 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_) || isN64()) { // For PIC, the sequence is: // BRIND(load(Jumptable + index) + RelocBase) // RelocBase can be JumpTable, GOT or some sort of global base. @@ -1446,7 +1497,7 @@ 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_ && !isN64()) { const MipsTargetObjectFile &TLOF = (const MipsTargetObjectFile&)getObjFileLowering(); @@ -1465,15 +1516,15 @@ SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op, } if (GV->hasInternalLinkage() || (GV->hasLocalLinkage() && !isa<Function>(GV))) - return getAddrLocal(N, Ty, DAG, HasMips64); + return getAddrLocal(N, Ty, DAG, isN32() || isN64()); if (LargeGOT) return getAddrGlobalLargeGOT(N, Ty, DAG, MipsII::MO_GOT_HI16, MipsII::MO_GOT_LO16, DAG.getEntryNode(), MachinePointerInfo::getGOT()); - return getAddrGlobal(N, Ty, DAG, - HasMips64 ? MipsII::MO_GOT_DISP : MipsII::MO_GOT16, + return getAddrGlobal(N, Ty, DAG, (isN32() || isN64()) ? MipsII::MO_GOT_DISP + : MipsII::MO_GOT16, DAG.getEntryNode(), MachinePointerInfo::getGOT()); } @@ -1482,10 +1533,10 @@ 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_ && !isN64()) return getAddrNonPIC(N, Ty, DAG); - return getAddrLocal(N, Ty, DAG, HasMips64); + return getAddrLocal(N, Ty, DAG, isN32() || isN64()); } SDValue MipsTargetLowering:: @@ -1575,10 +1626,10 @@ 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_ && !isN64()) return getAddrNonPIC(N, Ty, DAG); - return getAddrLocal(N, Ty, DAG, HasMips64); + return getAddrLocal(N, Ty, DAG, isN32() || isN64()); } SDValue MipsTargetLowering:: @@ -1596,10 +1647,10 @@ 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_ && !isN64()) return getAddrNonPIC(N, Ty, DAG); - return getAddrLocal(N, Ty, DAG, HasMips64); + return getAddrLocal(N, Ty, DAG, isN32() || isN64()); } SDValue MipsTargetLowering::lowerVASTART(SDValue Op, SelectionDAG &DAG) const { @@ -1790,12 +1841,15 @@ lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { EVT VT = Op.getValueType(); SDLoc DL(Op); SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, - IsN64 ? Mips::FP_64 : Mips::FP, VT); + isN64() ? 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 +1857,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 = isN64() ? Mips::RA_64 : Mips::RA; MFI->setReturnAddressIsTaken(true); // Return RA, which contains the return address. Mark it an implicit live-in. @@ -1825,12 +1879,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 = isN64() ? MVT::i64 : MVT::i32; // Store stack offset in V1, store jump target in V0. Glue CopyToReg and // EH_RETURN nodes, so that instructions are emitted back-to-back. - unsigned OffsetReg = IsN64 ? Mips::V1_64 : Mips::V1; - unsigned AddrReg = IsN64 ? Mips::V0_64 : Mips::V0; + unsigned OffsetReg = isN64() ? Mips::V1_64 : Mips::V1; + unsigned AddrReg = isN64() ? Mips::V0_64 : Mips::V0; Chain = DAG.getCopyToReg(Chain, DL, OffsetReg, Offset, SDValue()); Chain = DAG.getCopyToReg(Chain, DL, AddrReg, Handler, Chain.getValue(1)); return DAG.getNode(MipsISD::EH_RETURN, DL, MVT::Other, Chain, @@ -2254,8 +2308,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 = isN64() ? Mips::GP_64 : Mips::GP; + EVT Ty = isN64() ? MVT::i64 : MVT::i32; RegsToPass.push_back(std::make_pair(GPReg, getGlobalReg(CLI.DAG, Ty))); } @@ -2285,7 +2339,7 @@ getOpndList(SmallVectorImpl<SDValue> &Ops, 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,7 +2378,7 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, getTargetMachine(), ArgLocs, *DAG.getContext()); MipsCC::SpecialCallingConvType SpecialCallingConv = getSpecialCallingConv(Callee); - MipsCC MipsCCInfo(CallConv, IsO32, Subtarget->isFP64bit(), CCInfo, + MipsCC MipsCCInfo(CallConv, isO32(), Subtarget->isFP64bit(), CCInfo, SpecialCallingConv); MipsCCInfo.analyzeCallOperands(Outs, IsVarArg, @@ -2353,9 +2407,8 @@ 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, isN64() ? Mips::SP_64 : Mips::SP, getPointerTy()); // With EABI is it possible to have 16 args on registers. std::deque< std::pair<unsigned, SDValue> > RegsToPass; @@ -2442,7 +2495,8 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, // 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 = (isN64() || IsPIC); // true if calls are translated to + // jalr $25 bool GlobalOrExternal = false, InternalLinkage = false; SDValue CalleeLo; EVT Ty = Callee.getValueType(); @@ -2453,7 +2507,7 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, InternalLinkage = Val->hasInternalLinkage(); if (InternalLinkage) - Callee = getAddrLocal(G, Ty, DAG, HasMips64); + Callee = getAddrLocal(G, Ty, DAG, isN32() || isN64()); else if (LargeGOT) Callee = getAddrGlobalLargeGOT(G, Ty, DAG, MipsII::MO_CALL_HI16, MipsII::MO_CALL_LO16, Chain, @@ -2469,7 +2523,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 (!isN64() && !IsPIC) // !N64 && static Callee = DAG.getTargetExternalSymbol(Sym, getPointerTy(), MipsII::MO_NO_FLAG); else if (LargeGOT) @@ -2492,7 +2546,7 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, if (IsTailCall) return DAG.getNode(MipsISD::TailCall, DL, MVT::Other, &Ops[0], Ops.size()); - Chain = DAG.getNode(MipsISD::JmpLink, DL, NodeTys, &Ops[0], Ops.size()); + Chain = DAG.getNode(MipsISD::JmpLink, DL, NodeTys, &Ops[0], Ops.size()); SDValue InFlag = Chain.getValue(1); // Create the CALLSEQ_END node. @@ -2520,7 +2574,7 @@ 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, isO32(), Subtarget->isFP64bit(), CCInfo); MipsCCInfo.analyzeCallResult(Ins, Subtarget->mipsSEUsesSoftFloat(), CallNode, RetTy); @@ -2567,7 +2621,7 @@ 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, isO32(), Subtarget->isFP64bit(), CCInfo); Function::const_arg_iterator FuncArg = DAG.getMachineFunction().getFunction()->arg_begin(); bool UseSoftFloat = Subtarget->mipsSEUsesSoftFloat(); @@ -2629,7 +2683,7 @@ 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 (isO32() && RegVT == MVT::i32 && ValVT == MVT::f64) { unsigned Reg2 = addLiveIn(DAG.getMachineFunction(), getNextIntArgReg(ArgReg), RC); SDValue ArgValue2 = DAG.getCopyFromReg(Chain, DL, Reg2, RegVT); @@ -2665,8 +2719,8 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, if (DAG.getMachineFunction().getFunction()->hasStructRetAttr()) { unsigned Reg = MipsFI->getSRetReturnReg(); if (!Reg) { - Reg = MF.getRegInfo(). - createVirtualRegister(getRegClassFor(IsN64 ? MVT::i64 : MVT::i32)); + Reg = MF.getRegInfo().createVirtualRegister( + getRegClassFor(isN64() ? MVT::i64 : MVT::i32)); MipsFI->setSRetReturnReg(Reg); } SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), DL, Reg, InVals[0]); @@ -2716,7 +2770,7 @@ 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, isO32(), Subtarget->isFP64bit(), CCInfo); // Analyze return values. MipsCCInfo.analyzeReturn(Outs, Subtarget->mipsSEUsesSoftFloat(), @@ -2752,7 +2806,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 = isN64() ? Mips::V0_64 : Mips::V0; Chain = DAG.getCopyToReg(Chain, DL, V0, Val, Flag); Flag = Chain.getValue(1); @@ -2973,9 +3027,9 @@ getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const return std::make_pair(0U, &Mips::CPU16RegsRegClass); return std::make_pair(0U, &Mips::GPR32RegClass); } - if (VT == MVT::i64 && !HasMips64) + if (VT == MVT::i64 && !isGP64bit()) return std::make_pair(0U, &Mips::GPR32RegClass); - if (VT == MVT::i64 && HasMips64) + if (VT == MVT::i64 && isGP64bit()) return std::make_pair(0U, &Mips::GPR64RegClass); // This will generate an error message return std::make_pair(0u, static_cast<const TargetRegisterClass*>(0)); @@ -3162,7 +3216,7 @@ bool MipsTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const { } unsigned MipsTargetLowering::getJumpTableEncoding() const { - if (IsN64) + if (isN64()) return MachineJumpTableInfo::EK_GPRel64BlockAddress; return TargetLowering::getJumpTableEncoding(); @@ -3216,7 +3270,7 @@ MipsTargetLowering::MipsCC::SpecialCallingConvType 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; } } diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h index 65f68f0..35dd396 100644 --- a/lib/Target/Mips/MipsISelLowering.h +++ b/lib/Target/Mips/MipsISelLowering.h @@ -15,9 +15,9 @@ #ifndef MipsISELLOWERING_H #define MipsISELLOWERING_H +#include "MCTargetDesc/MipsBaseInfo.h" #include "Mips.h" #include "MipsSubtarget.h" -#include "MCTargetDesc/MipsBaseInfo.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/IR/Function.h" @@ -184,6 +184,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, @@ -209,6 +212,7 @@ namespace llvm { class MipsFunctionInfo; class MipsTargetLowering : public TargetLowering { + bool isMicroMips; public: explicit MipsTargetLowering(MipsTargetMachine &TM); @@ -254,17 +258,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); @@ -428,7 +432,11 @@ namespace llvm { // Subtarget Info const MipsSubtarget *Subtarget; - bool HasMips64, IsN64, IsO32; + bool hasMips64() const { return Subtarget->hasMips64(); } + bool isGP64bit() const { return Subtarget->isGP64bit(); } + bool isO32() const { return Subtarget->isABI_O32(); } + bool isN32() const { return Subtarget->isABI_N32(); } + bool isN64() const { return Subtarget->isABI_N64(); } private: // Create a TargetGlobalAddress node. diff --git a/lib/Target/Mips/MipsInstrFPU.td b/lib/Target/Mips/MipsInstrFPU.td index 9f7ce9a..4b5a73e 100644 --- a/lib/Target/Mips/MipsInstrFPU.td +++ b/lib/Target/Mips/MipsInstrFPU.td @@ -93,15 +93,16 @@ 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>, + def _D32 : MMRel, ADDS_FT<opstr, AFGR64Opnd, Itin, IsComm, OpNode>, Requires<[NotFP64bit, HasStdEnc]>; - def _D64 : ADDS_FT<opstr, FGR64Opnd, Itin, IsComm, OpNode>, + def _D64 : ADDS_FT<opstr, FGR64Opnd, Itin, + IsComm, OpNode>, Requires<[IsFP64bit, HasStdEnc]> { string DecoderNamespace = "Mips64"; } @@ -110,12 +111,12 @@ 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>, + def _D32 : MMRel, ABSS_FT<opstr, AFGR64Opnd, AFGR64Opnd, Itin, OpNode>, Requires<[NotFP64bit, HasStdEnc]>; def _D64 : ABSS_FT<opstr, FGR64Opnd, FGR64Opnd, Itin, OpNode>, Requires<[IsFP64bit, HasStdEnc]> { @@ -124,7 +125,7 @@ multiclass ABSS_M<string opstr, InstrItinClass Itin, } multiclass ROUND_M<string opstr, InstrItinClass Itin> { - def _D32 : ABSS_FT<opstr, FGR32Opnd, AFGR64Opnd, Itin>, + def _D32 : MMRel, ABSS_FT<opstr, FGR32Opnd, AFGR64Opnd, Itin>, Requires<[NotFP64bit, HasStdEnc]>; def _D64 : ABSS_FT<opstr, FGR32Opnd, FGR64Opnd, Itin>, Requires<[IsFP64bit, HasStdEnc]> { @@ -135,17 +136,17 @@ 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 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 +154,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 +163,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 +186,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 +207,133 @@ 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>; -} - -defm S : C_COND_M<"s", FGR32Opnd, 16>; -defm D32 : C_COND_M<"d", AFGR64Opnd, 17>, - Requires<[NotFP64bit, HasStdEnc]>; +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, II_C_CC_S>; +defm D32 : C_COND_M<"d", AFGR64Opnd, 17, II_C_CC_D>, + Requires<[NotFP64bit, HasStdEnc]>; 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>, + Requires<[IsFP64bit, HasStdEnc]>; //===----------------------------------------------------------------------===// // Floating Point Instructions //===----------------------------------------------------------------------===// -def ROUND_W_S : ABSS_FT<"round.w.s", FGR32Opnd, FGR32Opnd, IIFcvt>, +def ROUND_W_S : MMRel, ABSS_FT<"round.w.s", FGR32Opnd, FGR32Opnd, II_ROUND>, ABSS_FM<0xc, 16>; -def TRUNC_W_S : ABSS_FT<"trunc.w.s", FGR32Opnd, FGR32Opnd, IIFcvt>, +def TRUNC_W_S : MMRel, ABSS_FT<"trunc.w.s", FGR32Opnd, FGR32Opnd, II_TRUNC>, ABSS_FM<0xd, 16>; -def CEIL_W_S : ABSS_FT<"ceil.w.s", FGR32Opnd, FGR32Opnd, IIFcvt>, +def CEIL_W_S : MMRel, ABSS_FT<"ceil.w.s", FGR32Opnd, FGR32Opnd, II_CEIL>, ABSS_FM<0xe, 16>; -def FLOOR_W_S : ABSS_FT<"floor.w.s", FGR32Opnd, FGR32Opnd, IIFcvt>, +def FLOOR_W_S : MMRel, ABSS_FT<"floor.w.s", FGR32Opnd, FGR32Opnd, II_FLOOR>, ABSS_FM<0xf, 16>; -def CVT_W_S : ABSS_FT<"cvt.w.s", FGR32Opnd, FGR32Opnd, IIFcvt>, +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>; +defm TRUNC_W : ROUND_M<"trunc.w.d", II_TRUNC>, ABSS_FM<0xd, 17>; +defm CEIL_W : ROUND_M<"ceil.w.d", II_CEIL>, ABSS_FM<0xe, 17>; +defm FLOOR_W : ROUND_M<"floor.w.d", II_FLOOR>, ABSS_FM<0xf, 17>; +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>, + def ROUND_L_S : ABSS_FT<"round.l.s", FGR64Opnd, FGR32Opnd, II_ROUND>, ABSS_FM<0x8, 16>; - def ROUND_L_D64 : ABSS_FT<"round.l.d", FGR64Opnd, FGR64Opnd, IIFcvt>, + def ROUND_L_D64 : ABSS_FT<"round.l.d", FGR64Opnd, FGR64Opnd, II_ROUND>, ABSS_FM<0x8, 17>; - def TRUNC_L_S : ABSS_FT<"trunc.l.s", FGR64Opnd, FGR32Opnd, IIFcvt>, + def TRUNC_L_S : ABSS_FT<"trunc.l.s", FGR64Opnd, FGR32Opnd, II_TRUNC>, ABSS_FM<0x9, 16>; - def TRUNC_L_D64 : ABSS_FT<"trunc.l.d", FGR64Opnd, FGR64Opnd, IIFcvt>, + def TRUNC_L_D64 : ABSS_FT<"trunc.l.d", FGR64Opnd, FGR64Opnd, II_TRUNC>, ABSS_FM<0x9, 17>; - def CEIL_L_S : ABSS_FT<"ceil.l.s", FGR64Opnd, FGR32Opnd, IIFcvt>, + def CEIL_L_S : ABSS_FT<"ceil.l.s", FGR64Opnd, FGR32Opnd, II_CEIL>, ABSS_FM<0xa, 16>; - def CEIL_L_D64 : ABSS_FT<"ceil.l.d", FGR64Opnd, FGR64Opnd, IIFcvt>, + def CEIL_L_D64 : ABSS_FT<"ceil.l.d", FGR64Opnd, FGR64Opnd, II_CEIL>, ABSS_FM<0xa, 17>; - def FLOOR_L_S : ABSS_FT<"floor.l.s", FGR64Opnd, FGR32Opnd, IIFcvt>, + def FLOOR_L_S : ABSS_FT<"floor.l.s", FGR64Opnd, FGR32Opnd, II_FLOOR>, ABSS_FM<0xb, 16>; - def FLOOR_L_D64 : ABSS_FT<"floor.l.d", FGR64Opnd, FGR64Opnd, IIFcvt>, + def FLOOR_L_D64 : ABSS_FT<"floor.l.d", FGR64Opnd, FGR64Opnd, II_FLOOR>, ABSS_FM<0xb, 17>; } -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>, +def CVT_L_S : MMRel, ABSS_FT<"cvt.l.s", FGR64Opnd, FGR32Opnd, II_CVT>, ABSS_FM<0x25, 16>; -def CVT_L_D64: ABSS_FT<"cvt.l.d", FGR64Opnd, FGR64Opnd, IIFcvt>, +def CVT_L_D64: MMRel, ABSS_FT<"cvt.l.d", FGR64Opnd, FGR64Opnd, II_CVT>, ABSS_FM<0x25, 17>; let Predicates = [NotFP64bit, HasStdEnc] in { - def CVT_S_D32 : ABSS_FT<"cvt.s.d", FGR32Opnd, AFGR64Opnd, IIFcvt>, + def CVT_S_D32 : MMRel, ABSS_FT<"cvt.s.d", FGR32Opnd, AFGR64Opnd, II_CVT>, ABSS_FM<0x20, 17>; - def CVT_D32_W : ABSS_FT<"cvt.d.w", AFGR64Opnd, FGR32Opnd, IIFcvt>, + def CVT_D32_W : MMRel, ABSS_FT<"cvt.d.w", AFGR64Opnd, FGR32Opnd, II_CVT>, ABSS_FM<0x21, 20>; - def CVT_D32_S : ABSS_FT<"cvt.d.s", AFGR64Opnd, FGR32Opnd, IIFcvt>, + def CVT_D32_S : MMRel, ABSS_FT<"cvt.d.s", AFGR64Opnd, FGR32Opnd, II_CVT>, ABSS_FM<0x21, 16>; } let Predicates = [IsFP64bit, HasStdEnc], DecoderNamespace = "Mips64" in { - def CVT_S_D64 : ABSS_FT<"cvt.s.d", FGR32Opnd, FGR64Opnd, IIFcvt>, + def CVT_S_D64 : ABSS_FT<"cvt.s.d", FGR32Opnd, FGR64Opnd, II_CVT>, ABSS_FM<0x20, 17>; - def CVT_S_L : ABSS_FT<"cvt.s.l", FGR32Opnd, FGR64Opnd, IIFcvt>, + def CVT_S_L : ABSS_FT<"cvt.s.l", FGR32Opnd, FGR64Opnd, II_CVT>, ABSS_FM<0x20, 21>; - def CVT_D64_W : ABSS_FT<"cvt.d.w", FGR64Opnd, FGR32Opnd, IIFcvt>, + def CVT_D64_W : ABSS_FT<"cvt.d.w", FGR64Opnd, FGR32Opnd, II_CVT>, ABSS_FM<0x21, 20>; - def CVT_D64_S : ABSS_FT<"cvt.d.s", FGR64Opnd, FGR32Opnd, IIFcvt>, + def CVT_D64_S : ABSS_FT<"cvt.d.s", FGR64Opnd, FGR32Opnd, II_CVT>, ABSS_FM<0x21, 16>; - def CVT_D64_L : ABSS_FT<"cvt.d.l", FGR64Opnd, FGR64Opnd, IIFcvt>, + def CVT_D64_L : ABSS_FT<"cvt.d.l", FGR64Opnd, FGR64Opnd, II_CVT>, ABSS_FM<0x21, 21>; } let isPseudo = 1, isCodeGenOnly = 1 in { - def PseudoCVT_S_W : ABSS_FT<"", FGR32Opnd, GPR32Opnd, IIFcvt>; - def PseudoCVT_D32_W : ABSS_FT<"", AFGR64Opnd, GPR32Opnd, IIFcvt>; - def PseudoCVT_S_L : ABSS_FT<"", FGR64Opnd, GPR64Opnd, IIFcvt>; - def PseudoCVT_D64_W : ABSS_FT<"", FGR64Opnd, GPR32Opnd, IIFcvt>; - def PseudoCVT_D64_L : ABSS_FT<"", FGR64Opnd, GPR64Opnd, IIFcvt>; + 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>, + def FABS_S : MMRel, ABSS_FT<"abs.s", FGR32Opnd, FGR32Opnd, II_ABS, fabs>, ABSS_FM<0x5, 16>; - def FNEG_S : ABSS_FT<"neg.s", FGR32Opnd, FGR32Opnd, IIFcvt, fneg>, + def FNEG_S : MMRel, ABSS_FT<"neg.s", FGR32Opnd, FGR32Opnd, II_NEG, 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>; + 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>; +defm FSQRT : ABSS_M<"sqrt.d", II_SQRT_D, fsqrt>, ABSS_FM<0x4, 17>; // The odd-numbered registers are only referenced when doing loads, // stores, and moves between floating-point and integer registers. @@ -332,44 +341,44 @@ 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>, +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 : MMRel, MFC1_FT<"mfhc1", GPR32Opnd, FGRH32Opnd, II_MFHC1>, MFC1_FM<3>; -def MTHC1 : MTC1_FT<"mthc1", FGRH32Opnd, GPR32Opnd, IIFmoveC1>, +def MTHC1 : MMRel, MTC1_FT<"mthc1", FGRH32Opnd, GPR32Opnd, II_MTHC1>, MFC1_FM<7>; -def DMFC1 : MFC1_FT<"dmfc1", GPR64Opnd, FGR64Opnd, IIFmoveC1, +def DMFC1 : MFC1_FT<"dmfc1", GPR64Opnd, FGR64Opnd, II_DMFC1, bitconvert>, MFC1_FM<1>; -def DMTC1 : MTC1_FT<"dmtc1", FGR64Opnd, GPR64Opnd, IIFmoveC1, +def DMTC1 : MTC1_FT<"dmtc1", FGR64Opnd, GPR64Opnd, II_DMTC1, bitconvert>, MFC1_FM<5>; -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>, +def FMOV_D32 : MMRel, ABSS_FT<"mov.d", AFGR64Opnd, AFGR64Opnd, II_MOV_D>, ABSS_FM<0x6, 17>, Requires<[NotFP64bit, HasStdEnc]>; -def FMOV_D64 : ABSS_FT<"mov.d", FGR64Opnd, FGR64Opnd, IIFmove>, +def FMOV_D64 : ABSS_FT<"mov.d", FGR64Opnd, FGR64Opnd, II_MOV_D>, ABSS_FM<0x6, 17>, Requires<[IsFP64bit, HasStdEnc]> { let DecoderNamespace = "Mips64"; } /// Floating Point Memory Instructions let Predicates = [HasStdEnc] in { - def LWC1 : LW_FT<"lwc1", FGR32Opnd, IIFLoad, load>, LW_FM<0x31>; - def SWC1 : SW_FT<"swc1", FGR32Opnd, IIFStore, store>, LW_FM<0x39>; + 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>; + def LDC164 : LW_FT<"ldc1", FGR64Opnd, II_LDC1, load>, LW_FM<0x35>; + def SDC164 : SW_FT<"sdc1", FGR64Opnd, II_SDC1, store>, LW_FM<0x3d>; } let Predicates = [NotFP64bit, HasStdEnc] in { - def LDC1 : LW_FT<"ldc1", AFGR64Opnd, IIFLoad, load>, LW_FM<0x35>; - def SDC1 : SW_FT<"sdc1", AFGR64Opnd, IIFStore, store>, LW_FM<0x3d>; + def LDC1 : MMRel, LW_FT<"ldc1", AFGR64Opnd, II_LDC1, load>, LW_FM<0x35>; + def SDC1 : MMRel, SW_FT<"sdc1", AFGR64Opnd, II_SDC1, store>, LW_FM<0x3d>; } /// Cop2 Memory Instructions @@ -381,87 +390,90 @@ let Predicates = [HasStdEnc] in { } // 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 Predicates = [HasFPIdx, HasStdEnc, IsNotNaCl] in { + def LWXC1 : MMRel, LWXC1_FT<"lwxc1", FGR32Opnd, II_LWXC1, load>, LWXC1_FM<0>; + def SWXC1 : MMRel, SWXC1_FT<"swxc1", FGR32Opnd, II_SWXC1, store>, SWXC1_FM<8>; } -let Predicates = [HasFPIdx, NotFP64bit, HasStdEnc] in { - def LDXC1 : LWXC1_FT<"ldxc1", AFGR64Opnd, IIFLoad, load>, LWXC1_FM<1>; - def SDXC1 : SWXC1_FT<"sdxc1", AFGR64Opnd, IIFStore, store>, SWXC1_FM<9>; +let Predicates = [HasFPIdx, NotFP64bit, HasStdEnc, NotInMicroMips, + IsNotNaCl] in { + def LDXC1 : LWXC1_FT<"ldxc1", AFGR64Opnd, II_LDXC1, load>, LWXC1_FM<1>; + def SDXC1 : SWXC1_FT<"sdxc1", AFGR64Opnd, II_SDXC1, store>, SWXC1_FM<9>; } let Predicates = [HasFPIdx, IsFP64bit, HasStdEnc], DecoderNamespace="Mips64" in { - def LDXC164 : LWXC1_FT<"ldxc1", FGR64Opnd, IIFLoad, load>, LWXC1_FM<1>; - def SDXC164 : SWXC1_FT<"sdxc1", FGR64Opnd, IIFStore, store>, SWXC1_FM<9>; + def LDXC164 : LWXC1_FT<"ldxc1", FGR64Opnd, II_LDXC1, load>, LWXC1_FM<1>; + def SDXC164 : SWXC1_FT<"sdxc1", FGR64Opnd, II_SDXC1, store>, SWXC1_FM<9>; } // Load/store doubleword indexed unaligned. -let Predicates = [NotFP64bit, HasStdEnc] in { - def LUXC1 : LWXC1_FT<"luxc1", AFGR64Opnd, IIFLoad>, LWXC1_FM<0x5>; - def SUXC1 : SWXC1_FT<"suxc1", AFGR64Opnd, IIFStore>, SWXC1_FM<0xd>; +let Predicates = [NotFP64bit, HasStdEnc, IsNotNaCl] in { + def LUXC1 : MMRel, LWXC1_FT<"luxc1", AFGR64Opnd, II_LUXC1>, LWXC1_FM<0x5>; + def SUXC1 : MMRel, SWXC1_FT<"suxc1", AFGR64Opnd, II_SUXC1>, SWXC1_FM<0xd>; } let Predicates = [IsFP64bit, HasStdEnc], DecoderNamespace="Mips64" in { - def LUXC164 : LWXC1_FT<"luxc1", FGR64Opnd, IIFLoad>, LWXC1_FM<0x5>; - def SUXC164 : SWXC1_FT<"suxc1", FGR64Opnd, IIFStore>, SWXC1_FM<0xd>; + def LUXC164 : LWXC1_FT<"luxc1", FGR64Opnd, II_LUXC1>, LWXC1_FM<0x5>; + def SUXC164 : SWXC1_FT<"suxc1", FGR64Opnd, II_SUXC1>, SWXC1_FM<0xd>; } /// 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>, + def MADD_S : MMRel, MADDS_FT<"madd.s", FGR32Opnd, II_MADD_S, fadd>, MADDS_FM<4, 0>; - def MSUB_S : MADDS_FT<"msub.s", FGR32Opnd, IIFmulSingle, fsub>, + def MSUB_S : MMRel, MADDS_FT<"msub.s", FGR32Opnd, II_MSUB_S, fsub>, MADDS_FM<5, 0>; } let Predicates = [HasMips32r2, NoNaNsFPMath, HasStdEnc] in { - def NMADD_S : NMADDS_FT<"nmadd.s", FGR32Opnd, IIFmulSingle, fadd>, + def NMADD_S : MMRel, NMADDS_FT<"nmadd.s", FGR32Opnd, II_NMADD_S, fadd>, MADDS_FM<6, 0>; - def NMSUB_S : NMADDS_FT<"nmsub.s", FGR32Opnd, IIFmulSingle, fsub>, + def NMSUB_S : MMRel, NMADDS_FT<"nmsub.s", FGR32Opnd, II_NMSUB_S, fsub>, MADDS_FM<7, 0>; } let Predicates = [HasMips32r2, NotFP64bit, HasStdEnc] in { - def MADD_D32 : MADDS_FT<"madd.d", AFGR64Opnd, IIFmulDouble, fadd>, + def MADD_D32 : MMRel, MADDS_FT<"madd.d", AFGR64Opnd, II_MADD_D, fadd>, MADDS_FM<4, 1>; - def MSUB_D32 : MADDS_FT<"msub.d", AFGR64Opnd, IIFmulDouble, fsub>, + def MSUB_D32 : MMRel, MADDS_FT<"msub.d", AFGR64Opnd, II_MSUB_D, fsub>, MADDS_FM<5, 1>; } let Predicates = [HasMips32r2, NotFP64bit, NoNaNsFPMath, HasStdEnc] in { - def NMADD_D32 : NMADDS_FT<"nmadd.d", AFGR64Opnd, IIFmulDouble, fadd>, + def NMADD_D32 : MMRel, NMADDS_FT<"nmadd.d", AFGR64Opnd, II_NMADD_D, fadd>, MADDS_FM<6, 1>; - def NMSUB_D32 : NMADDS_FT<"nmsub.d", AFGR64Opnd, IIFmulDouble, fsub>, + def NMSUB_D32 : MMRel, NMADDS_FT<"nmsub.d", AFGR64Opnd, II_NMSUB_D, fsub>, MADDS_FM<7, 1>; } let Predicates = [HasMips32r2, IsFP64bit, HasStdEnc], isCodeGenOnly=1 in { - def MADD_D64 : MADDS_FT<"madd.d", FGR64Opnd, IIFmulDouble, fadd>, + def MADD_D64 : MADDS_FT<"madd.d", FGR64Opnd, II_MADD_D, fadd>, MADDS_FM<4, 1>; - def MSUB_D64 : MADDS_FT<"msub.d", FGR64Opnd, IIFmulDouble, fsub>, + def MSUB_D64 : MADDS_FT<"msub.d", FGR64Opnd, II_MSUB_D, fsub>, MADDS_FM<5, 1>; } let Predicates = [HasMips32r2, IsFP64bit, NoNaNsFPMath, HasStdEnc], isCodeGenOnly=1 in { - def NMADD_D64 : NMADDS_FT<"nmadd.d", FGR64Opnd, IIFmulDouble, fadd>, + def NMADD_D64 : NMADDS_FT<"nmadd.d", FGR64Opnd, II_NMADD_D, fadd>, MADDS_FM<6, 1>; - def NMSUB_D64 : NMADDS_FT<"nmsub.d", FGR64Opnd, IIFmulDouble, fsub>, + def NMSUB_D64 : NMADDS_FT<"nmsub.d", FGR64Opnd, II_NMSUB_D, fsub>, MADDS_FM<7, 1>; } @@ -473,8 +485,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>; +def BC1T : MMRel, BC1F_FT<"bc1t", brtarget, IIBranch, MIPS_BRANCH_T>, + BC1F_FM<0, 1>; //===----------------------------------------------------------------------===// // Floating Point Flag Conditions @@ -499,11 +513,11 @@ 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>, +def FCMP_S32 : MMRel, CEQS_FT<"s", FGR32, II_C_CC_S, MipsFPCmp>, CEQS_FM<16>; +def FCMP_D32 : MMRel, CEQS_FT<"d", AFGR64, II_C_CC_D, MipsFPCmp>, CEQS_FM<17>, Requires<[NotFP64bit, HasStdEnc]>; let DecoderNamespace = "Mips64" in -def FCMP_D64 : CEQS_FT<"d", FGR64, IIFcmp, MipsFPCmp>, CEQS_FM<17>, +def FCMP_D64 : CEQS_FT<"d", FGR64, II_C_CC_D, MipsFPCmp>, CEQS_FM<17>, Requires<[IsFP64bit, HasStdEnc]>; //===----------------------------------------------------------------------===// diff --git a/lib/Target/Mips/MipsInstrFormats.td b/lib/Target/Mips/MipsInstrFormats.td index 737a018..e4405ab 100644 --- a/lib/Target/Mips/MipsInstrFormats.td +++ b/lib/Target/Mips/MipsInstrFormats.td @@ -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,77 @@ 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; +} + //===----------------------------------------------------------------------===// // 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 +562,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 +577,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 +591,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 +635,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 +650,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 +664,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 +689,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 +706,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 +721,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 +736,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 +750,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 +770,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 +802,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 +818,14 @@ 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 +} diff --git a/lib/Target/Mips/MipsInstrInfo.td b/lib/Target/Mips/MipsInstrInfo.td index ebdbaa4..07c37d8 100644 --- a/lib/Target/Mips/MipsInstrInfo.td +++ b/lib/Target/Mips/MipsInstrInfo.td @@ -168,10 +168,10 @@ def HasMips64r2 : Predicate<"Subtarget.hasMips64r2()">, AssemblerPredicate<"FeatureMips64r2">; def IsN64 : Predicate<"Subtarget.isABI_N64()">, AssemblerPredicate<"FeatureN64">; -def NotN64 : Predicate<"!Subtarget.isABI_N64()">, - AssemblerPredicate<"!FeatureN64">; def InMips16Mode : Predicate<"Subtarget.inMips16Mode()">, AssemblerPredicate<"FeatureMips16">; +def HasCnMips : Predicate<"Subtarget.hasCnMips()">, + AssemblerPredicate<"FeatureCnMips">; def RelocStatic : Predicate<"TM.getRelocationModel() == Reloc::Static">, AssemblerPredicate<"FeatureMips32">; def RelocPIC : Predicate<"TM.getRelocationModel() == Reloc::PIC_">, @@ -187,6 +187,7 @@ def NotInMicroMips : Predicate<"!Subtarget.inMicroMipsMode()">, AssemblerPredicate<"!FeatureMicroMips">; def IsLE : Predicate<"Subtarget.isLittle()">; def IsBE : Predicate<"!Subtarget.isLittle()">; +def IsNotNaCl : Predicate<"!Subtarget.isTargetNaCl()">; class MipsPat<dag pattern, dag result> : Pat<pattern, result> { let Predicates = [HasStdEnc]; @@ -235,19 +236,31 @@ 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 simm10 : Operand<i32>; + def simm16 : Operand<i32> { let DecoderMethod= "DecodeSimm16"; } @@ -265,6 +278,11 @@ def simm16_64 : Operand<i64> { let DecoderMethod = "DecodeSimm16"; } +// Zero +def uimmz : Operand<i32> { + let PrintMethod = "printUnsignedImm"; +} + // Unsigned Operand def uimm5 : Operand<i32> { let PrintMethod = "printUnsignedImm"; @@ -292,18 +310,11 @@ def MipsInvertedImmoperand : AsmOperandClass { let ParserMethod = "parseInvNum"; } -def PtrRegAsmOperand : AsmOperandClass { - let Name = "PtrReg"; - let ParserMethod = "parsePtrReg"; -} - - def InvertedImOperand : Operand<i32> { let ParserMatchClass = MipsInvertedImmoperand; } -// Address operand -def mem : Operand<iPTR> { +class mem_generic : Operand<iPTR> { let PrintMethod = "printMemOperand"; let MIOperandInfo = (ops ptr_rc, simm16); let EncoderMethod = "getMemEncoding"; @@ -311,6 +322,15 @@ 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_ea : Operand<iPTR> { let PrintMethod = "printMemOperandEA"; let MIOperandInfo = (ops ptr_rc, simm16); @@ -321,7 +341,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 +369,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 +423,8 @@ def addrRegReg : def addrDefault : ComplexPattern<iPTR, 2, "selectAddrDefault", [frameindex]>; +def addrimm10 : ComplexPattern<iPTR, 2, "selectIntAddrMSA", [frameindex]>; + //===----------------------------------------------------------------------===// // Instructions specific format //===----------------------------------------------------------------------===// @@ -413,6 +438,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 +455,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 +467,30 @@ 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>; -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 +561,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, @@ -603,7 +631,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 +639,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 +664,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 +726,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 +747,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 +770,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,19 +779,19 @@ 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>, + [(set RO:$rd, (ctlz RO:$rs))], II_CLZ, FrmR, opstr>, Requires<[HasBitCount, HasStdEnc]>; class CountLeading1<string opstr, RegisterOperand RO>: InstSE<(outs RO:$rd), (ins RO:$rs), !strconcat(opstr, "\t$rd, $rs"), - [(set RO:$rd, (ctlz (not RO:$rs)))], IIArith, FrmR, opstr>, + [(set RO:$rd, (ctlz (not RO:$rs)))], II_CLO, FrmR, opstr>, Requires<[HasBitCount, HasStdEnc]>; - // 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> { + [(set RO:$rd, (sext_inreg RO:$rt, vt))], itin, FrmR, opstr> { let Predicates = [HasSEInReg, HasStdEnc]; } @@ -767,7 +806,7 @@ class SubwordSwap<string opstr, RegisterOperand RO>: // 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, @@ -884,7 +923,7 @@ 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>; @@ -892,80 +931,82 @@ 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>, +def MUL : MMRel, ArithLogicR<"mul", GPR32Opnd, 1, II_MUL, mul>, ADD_FM<0x1c, 2>; def ADD : MMRel, ArithLogicR<"add", GPR32Opnd>, ADD_FM<0, 0x20>; def SUB : MMRel, ArithLogicR<"sub", GPR32Opnd>, ADD_FM<0, 0x22>; def SLT : MMRel, SetCC_R<"slt", setlt, GPR32Opnd>, ADD_FM<0, 0x2a>; def SLTu : MMRel, SetCC_R<"sltu", setult, GPR32Opnd>, ADD_FM<0, 0x2b>; -def AND : MMRel, ArithLogicR<"and", GPR32Opnd, 1, IILogic, and>, +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>, + def ROTR : MMRel, shift_rotate_imm<"rotr", uimm5, GPR32Opnd, II_ROTR, rotr, + immZExt5>, SRA_FM<2, 1>; + def ROTRV : MMRel, shift_rotate_reg<"rotrv", GPR32Opnd, II_ROTRV, rotr>, SRLV_FM<6, 1>; } /// Load and Store Instructions /// aligned -def LB : Load<"lb", GPR32Opnd, sextloadi8, IILoad>, MMRel, LW_FM<0x20>; -def LBu : Load<"lbu", GPR32Opnd, zextloadi8, IILoad, addrDefault>, MMRel, +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>; +def LWL : LoadLeftRight<"lwl", MipsLWL, GPR32Opnd, II_LWL>, LW_FM<0x22>; +def LWR : LoadLeftRight<"lwr", MipsLWR, GPR32Opnd, II_LWR>, LW_FM<0x26>; +def SWL : StoreLeftRight<"swl", MipsSWL, GPR32Opnd, II_SWL>, LW_FM<0x2a>; +def SWR : StoreLeftRight<"swr", MipsSWR, GPR32Opnd, II_SWR>, LW_FM<0x2e>; } -def SYNC : SYNC_FT, SYNC_FM; +def SYNC : MMRel, SYNC_FT<"sync">, SYNC_FM; def TEQ : MMRel, TEQ_FT<"teq", GPR32Opnd>, TEQ_FM<0x34>; def TGE : MMRel, TEQ_FT<"tge", GPR32Opnd>, TEQ_FM<0x30>; def TGEU : MMRel, TEQ_FT<"tgeu", GPR32Opnd>, TEQ_FM<0x31>; @@ -980,21 +1021,23 @@ def TLTI : MMRel, TEQI_FT<"tlti", GPR32Opnd>, TEQI_FM<0xa>; def TTLTIU : MMRel, TEQI_FT<"tltiu", GPR32Opnd>, TEQI_FM<0xb>; def TNEI : MMRel, TEQI_FT<"tnei", GPR32Opnd>, TEQI_FM<0xe>; -def BREAK : BRK_FT<"break">, BRK_FM<0xd>; -def SYSCALL : SYS_FT<"syscall">, SYS_FM<0xc>; +def BREAK : MMRel, BRK_FT<"break">, BRK_FM<0xd>; +def SYSCALL : MMRel, SYS_FT<"syscall">, SYS_FM<0xc>; def TRAP : TrapBase<BREAK>; -def ERET : ER_FT<"eret">, ER_FM<0x18>; -def DERET : ER_FT<"deret">, ER_FM<0x1f>; +def ERET : MMRel, ER_FT<"eret">, ER_FM<0x18>; +def DERET : MMRel, ER_FT<"deret">, ER_FM<0x1f>; -def EI : DEI_FT<"ei", GPR32Opnd>, EI_FM<1>; -def DI : DEI_FT<"di", GPR32Opnd>, EI_FM<0>; +def EI : MMRel, DEI_FT<"ei", GPR32Opnd>, EI_FM<1>; +def DI : MMRel, DEI_FT<"di", GPR32Opnd>, EI_FM<0>; -def WAIT : WAIT_FT<"wait">; +let Predicates = [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>; +} /// Jump and Branch Instructions def J : MMRel, JumpFJ<jmptarget, "j", br, bb, "j">, FJ<2>, @@ -1013,15 +1056,16 @@ 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; +let Predicates = [NotInMicroMips, HasStdEnc] in { +def JALR : JumpLinkReg<"jalr", GPR32Opnd>, JALR_FM; def JALRPseudo : JumpLinkRegPseudo<GPR32Opnd, JALR, RA>; +} +def JALX : JumpLink<"jalx", calltarget>, FJ<0x1D>; def BGEZAL : MMRel, BGEZAL_FT<"bgezal", brtarget, GPR32Opnd>, BGEZAL_FM<0x11>; def BLTZAL : MMRel, BGEZAL_FT<"bltzal", brtarget, GPR32Opnd>, BGEZAL_FM<0x10>; def BAL_BR : BAL_BR_Pseudo<BGEZAL>; -def TAILCALL : MMRel, JumpFJ<calltarget, "j", MipsTailCall, imm, "tcall">, - FJ<2>, IsTailCall; -def TAILCALL_R : MMRel, JumpFR<"tcallr", GPR32Opnd, MipsTailCall>, MTLO_FM<8>, - IsTailCall; +def TAILCALL : TailCall<J>; +def TAILCALL_R : TailCallReg<GPR32Opnd, JR>; def RET : MMRel, RetBase<"ret", GPR32Opnd>, MTLO_FM<8>; @@ -1047,23 +1091,25 @@ let Uses = [V0, V1], isTerminator = 1, isReturn = 1, isBarrier = 1 in { } /// Multiply and Divide Instructions. -def MULT : MMRel, Mult<"mult", IIImult, GPR32Opnd, [HI0, LO0]>, +def MULT : MMRel, Mult<"mult", II_MULT, GPR32Opnd, [HI0, LO0]>, MULT_FM<0, 0x18>; -def MULTu : MMRel, Mult<"multu", IIImult, GPR32Opnd, [HI0, LO0]>, +def MULTu : MMRel, Mult<"multu", II_MULTU, GPR32Opnd, [HI0, LO0]>, MULT_FM<0, 0x19>; -def SDIV : MMRel, Div<"div", IIIdiv, GPR32Opnd, [HI0, LO0]>, +def SDIV : MMRel, Div<"div", II_DIV, GPR32Opnd, [HI0, LO0]>, MULT_FM<0, 0x1a>; -def UDIV : MMRel, Div<"divu", IIIdiv, GPR32Opnd, [HI0, LO0]>, +def UDIV : MMRel, Div<"divu", II_DIVU, GPR32Opnd, [HI0, LO0]>, MULT_FM<0, 0x1b>; def MTHI : MMRel, MoveToLOHI<"mthi", GPR32Opnd, [HI0]>, MTLO_FM<0x11>; def MTLO : MMRel, MoveToLOHI<"mtlo", GPR32Opnd, [LO0]>, MTLO_FM<0x13>; +let Predicates = [NotInMicroMips] in { def MFHI : MMRel, MoveFromLOHI<"mfhi", GPR32Opnd, AC0>, MFLO_FM<0x10>; def MFLO : MMRel, MoveFromLOHI<"mflo", GPR32Opnd, AC0>, MFLO_FM<0x12>; +} /// Sign Ext In Register Instructions. -def SEB : MMRel, SignExtInReg<"seb", i8, GPR32Opnd>, SEB_FM<0x10, 0x20>; -def SEH : MMRel, SignExtInReg<"seh", i16, GPR32Opnd>, SEB_FM<0x18, 0x20>; +def SEB : MMRel, SignExtInReg<"seb", i8, GPR32Opnd, II_SEB>, SEB_FM<0x10, 0x20>; +def SEH : MMRel, SignExtInReg<"seh", i16, GPR32Opnd, II_SEH>, SEB_FM<0x18, 0x20>; /// Count Leading def CLZ : MMRel, CountLeading0<"clz", GPR32Opnd>, CLO_FM<0x20>; @@ -1079,29 +1125,29 @@ 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>; +def MADDU : MMRel, MArithR<"maddu", II_MADDU, 1>, MULT_FM<0x1c, 1>; +def MSUB : MMRel, MArithR<"msub", II_MSUB>, MULT_FM<0x1c, 4>; +def MSUBU : MMRel, MArithR<"msubu", II_MSUBU>, MULT_FM<0x1c, 5>; let Predicates = [HasStdEnc, NotDSP] in { -def PseudoMULT : MultDivPseudo<MULT, ACC64, GPR32Opnd, MipsMult, IIImult>; -def PseudoMULTu : MultDivPseudo<MULTu, ACC64, GPR32Opnd, MipsMultu, IIImult>; +def PseudoMULT : MultDivPseudo<MULT, ACC64, GPR32Opnd, MipsMult, II_MULT>; +def PseudoMULTu : MultDivPseudo<MULTu, ACC64, GPR32Opnd, MipsMultu, II_MULTU>; def PseudoMFHI : PseudoMFLOHI<GPR32, ACC64, MipsMFHI>; def PseudoMFLO : PseudoMFLOHI<GPR32, ACC64, MipsMFLO>; def PseudoMTLOHI : PseudoMTLOHI<ACC64, GPR32>; -def PseudoMADD : MAddSubPseudo<MADD, MipsMAdd>; -def PseudoMADDU : MAddSubPseudo<MADDU, MipsMAddu>; -def PseudoMSUB : MAddSubPseudo<MSUB, MipsMSub>; -def PseudoMSUBU : MAddSubPseudo<MSUBU, MipsMSubu>; +def PseudoMADD : MAddSubPseudo<MADD, MipsMAdd, II_MADD>; +def PseudoMADDU : MAddSubPseudo<MADDU, MipsMAddu, II_MADDU>; +def PseudoMSUB : MAddSubPseudo<MSUB, MipsMSub, II_MSUB>; +def PseudoMSUBU : MAddSubPseudo<MSUBU, MipsMSubu, II_MSUBU>; } -def PseudoSDIV : MultDivPseudo<SDIV, ACC64, GPR32Opnd, MipsDivRem, IIIdiv, +def PseudoSDIV : MultDivPseudo<SDIV, ACC64, GPR32Opnd, MipsDivRem, II_DIV, 0, 1, 1>; -def PseudoUDIV : MultDivPseudo<UDIV, ACC64, GPR32Opnd, MipsDivRemU, IIIdiv, +def PseudoUDIV : MultDivPseudo<UDIV, ACC64, GPR32Opnd, MipsDivRemU, II_DIVU, 0, 1, 1>; def RDHWR : ReadHardware<GPR32Opnd, HWRegsOpnd>, RDHWR_FM; @@ -1115,12 +1161,18 @@ def MTC0 : MFC3OP<"mtc0", GPR32Opnd>, MFC3OP_FM<0x10, 4>; def MFC2 : MFC3OP<"mfc2", GPR32Opnd>, MFC3OP_FM<0x12, 0>; def MTC2 : MFC3OP<"mtc2", GPR32Opnd>, MFC3OP_FM<0x12, 4>; +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>, Requires<[HasMips32r2]>; + //===----------------------------------------------------------------------===// // Instruction aliases //===----------------------------------------------------------------------===// def : InstAlias<"move $dst, $src", (ADDu GPR32Opnd:$dst, GPR32Opnd:$src,ZERO), 1>, - Requires<[NotMips64]>; + Requires<[NotMips64, NotInMicroMips]>; def : InstAlias<"bal $offset", (BGEZAL ZERO, brtarget:$offset), 0>; def : InstAlias<"addu $rs, $rt, $imm", (ADDiu GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), 0>; @@ -1129,7 +1181,9 @@ def : InstAlias<"add $rs, $rt, $imm", def : InstAlias<"and $rs, $rt, $imm", (ANDi GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), 0>; def : InstAlias<"j $rs", (JR GPR32Opnd:$rs), 0>; +let Predicates = [NotInMicroMips] in { 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", @@ -1419,3 +1473,4 @@ include "MipsMSAInstrInfo.td" // Micromips include "MicroMipsInstrFormats.td" include "MicroMipsInstrInfo.td" +include "MicroMipsInstrFPU.td" diff --git a/lib/Target/Mips/MipsLongBranch.cpp b/lib/Target/Mips/MipsLongBranch.cpp index 2efe578..2b6a874 100644 --- a/lib/Target/Mips/MipsLongBranch.cpp +++ b/lib/Target/Mips/MipsLongBranch.cpp @@ -134,7 +134,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 +154,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()); } diff --git a/lib/Target/Mips/MipsMCInstLower.cpp b/lib/Target/Mips/MipsMCInstLower.cpp index b6dfadc..7c9a9ed 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; diff --git a/lib/Target/Mips/MipsMSAInstrFormats.td b/lib/Target/Mips/MipsMSAInstrFormats.td index 875dc0b..6bd0366 100644 --- a/lib/Target/Mips/MipsMSAInstrFormats.td +++ b/lib/Target/Mips/MipsMSAInstrFormats.td @@ -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 82c51a6..5722c6c 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>; @@ -69,7 +73,7 @@ def uimm2 : Operand<i32> { // as the encoded value should be subtracted by one. def uimm2LSAAsmOperand : AsmOperandClass { let Name = "LSAImm"; - let ParserMethod = "parseLSAImm"; + let ParserMethod = "ParseLSAImm"; let RenderMethod = "addImmOperands"; } @@ -94,8 +98,6 @@ def uimm8 : Operand<i32> { def simm5 : Operand<i32>; -def simm10 : Operand<i32>; - def vsplat_uimm1 : Operand<vAny> { let PrintMethod = "printUnsignedImm8"; } @@ -137,6 +139,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 +148,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 +157,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 +249,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 +631,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 +743,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 +871,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 +889,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 +1243,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 +1287,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 +1328,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 +1372,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 +1415,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 +1438,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 +1453,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,8 +1498,8 @@ 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"; @@ -1490,11 +1509,12 @@ 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 +1545,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 +1755,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 +1776,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 +1792,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 +1912,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 +1921,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 +2083,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 +2122,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 +2297,26 @@ 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_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 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 +2336,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 +2547,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 +2646,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 +2859,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 +2950,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 +3067,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,14 +3197,19 @@ 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; @@ -3164,6 +3225,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 +3526,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 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 : 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), 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 +3557,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>; diff --git a/lib/Target/Mips/MipsMachineFunction.h b/lib/Target/Mips/MipsMachineFunction.h index 43bf682..3e14c8c 100644 --- a/lib/Target/Mips/MipsMachineFunction.h +++ b/lib/Target/Mips/MipsMachineFunction.h @@ -14,16 +14,19 @@ #ifndef MIPS_MACHINE_FUNCTION_INFO_H #define MIPS_MACHINE_FUNCTION_INFO_H +#include "Mips16HardFloatInfo.h" #include "MipsSubtarget.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/ValueMap.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/IR/GlobalValue.h" +#include "llvm/IR/ValueMap.h" #include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetMachine.h" +#include <map> +#include <string> #include <utility> namespace llvm { @@ -50,10 +53,9 @@ 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) {} ~MipsFunctionInfo(); @@ -92,6 +94,12 @@ public: /// representing a GOT entry for a global function. MachinePointerInfo callPtrInfo(const GlobalValue *Val); + void setSaveS2() { SaveS2 = true; } + bool hasSaveS2() const { return SaveS2; } + + std::map<const char *, const llvm::Mips16HardFloatInfo::FuncSignature *> + StubsNeeded; + private: virtual void anchor(); @@ -126,6 +134,9 @@ private: /// Frame objects for spilling eh data registers. int EhDataRegFI[4]; + // saveS2 + bool SaveS2; + /// MipsCallEntry maps. StringMap<const MipsCallEntry *> ExternalCallEntries; ValueMap<const GlobalValue *, const MipsCallEntry *> GlobalCallEntries; diff --git a/lib/Target/Mips/MipsOptimizePICCall.cpp b/lib/Target/Mips/MipsOptimizePICCall.cpp new file mode 100644 index 0000000..db270f3 --- /dev/null +++ b/lib/Target/Mips/MipsOptimizePICCall.cpp @@ -0,0 +1,297 @@ +//===--------- 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. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "optimize-mips-pic-call" + +#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; + +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 std::pair<unsigned, unsigned> CntRegP; +typedef RecyclingAllocator<BumpPtrAllocator, + ScopedHashTableVal<const Value *, CntRegP> > +AllocatorTy; +typedef ScopedHashTable<const Value *, CntRegP, DenseMapInfo<const Value *>, + 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) {} + + virtual const char *getPassName() const { return "Mips OptimizePICCall"; } + + bool runOnMachineFunction(MachineFunction &F); + + void getAnalysisUsage(AnalysisUsage &AU) const { + 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, + const Value *&Val) const; + + /// \brief Return the number of instructions that dominate the current + /// instruction and load the function address from object Entry. + unsigned getCount(const Value *Entry); + + /// \brief Return the destination virtual register of the last instruction + /// that loads from object Entry. + unsigned getReg(const Value *Entry); + + /// \brief Update ScopedHT. + void incCntAndSetReg(const Value *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 0; + + MachineOperand &MO = MI.getOperand(0); + + if (!MO.isReg() || !MO.isUse() || + !TargetRegisterInfo::isVirtualRegister(MO.getReg())) + return 0; + + 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(0); +} + +MBBInfo::MBBInfo(MachineDomTreeNode *N) : Node(N), HTScope(0) {} + +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; + const Value *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, + const Value *&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 = 0; + 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(); + return true; +} + +unsigned OptimizePICCall::getCount(const Value *Entry) { + return ScopedHT.lookup(Entry).first; +} + +unsigned OptimizePICCall::getReg(const Value *Entry) { + unsigned Reg = ScopedHT.lookup(Entry).second; + assert(Reg); + return Reg; +} + +void OptimizePICCall::incCntAndSetReg(const Value *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/MipsRegisterInfo.cpp b/lib/Target/Mips/MipsRegisterInfo.cpp index 3105b02..d7fc93b 100644 --- a/lib/Target/Mips/MipsRegisterInfo.cpp +++ b/lib/Target/Mips/MipsRegisterInfo.cpp @@ -24,9 +24,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" @@ -133,6 +133,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 +186,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. diff --git a/lib/Target/Mips/MipsRegisterInfo.td b/lib/Target/Mips/MipsRegisterInfo.td index 3173d09..834e6c5 100644 --- a/lib/Target/Mips/MipsRegisterInfo.td +++ b/lib/Target/Mips/MipsRegisterInfo.td @@ -209,7 +209,8 @@ let Namespace = "Mips" in { 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 +246,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">; + } //===----------------------------------------------------------------------===// @@ -355,7 +365,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 +387,77 @@ def DSPCC : RegisterClass<"Mips", [v4i8, v2i16], 32, (add DSPCCond)>; def COP2 : RegisterClass<"Mips", [i32], 32, (sequence "COP2%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 +477,11 @@ 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 HWRegsOpnd : RegisterOperand<HWRegs> { @@ -528,22 +525,22 @@ def COP2Opnd : RegisterOperand<COP2> { } 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 33ed4b3..0343a47 100644 --- a/lib/Target/Mips/MipsSEFrameLowering.cpp +++ b/lib/Target/Mips/MipsSEFrameLowering.cpp @@ -299,11 +299,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 +314,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 +330,21 @@ 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 { // 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,13 +362,13 @@ 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); } } @@ -376,11 +378,10 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF) const { BuildMI(MBB, MBBI, dl, TII.get(ADDu), FP).addReg(SP).addReg(ZERO); // emit ".cfi_def_cfa_register $fp" - MCSymbol *SetFPLabel = MMI.getContext().CreateTempSymbol(); - BuildMI(MBB, MBBI, dl, - TII.get(TargetOpcode::PROLOG_LABEL)).addSym(SetFPLabel); - MMI.addFrameInst(MCCFIInstruction::createDefCfaRegister( - SetFPLabel, MRI->getDwarfRegNum(FP, true))); + 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/MipsSEISelDAGToDAG.cpp b/lib/Target/Mips/MipsSEISelDAGToDAG.cpp index 737660e..5b20a6c 100644 --- a/lib/Target/Mips/MipsSEISelDAGToDAG.cpp +++ b/lib/Target/Mips/MipsSEISelDAGToDAG.cpp @@ -13,8 +13,8 @@ #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,11 +24,11 @@ #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" @@ -104,7 +104,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; @@ -248,18 +248,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 +306,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 +361,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,6 +390,17 @@ 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: @@ -630,7 +657,7 @@ 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); diff --git a/lib/Target/Mips/MipsSEISelDAGToDAG.h b/lib/Target/Mips/MipsSEISelDAGToDAG.h index dc52064..ba84a6d 100644 --- a/lib/Target/Mips/MipsSEISelDAGToDAG.h +++ b/lib/Target/Mips/MipsSEISelDAGToDAG.h @@ -40,6 +40,10 @@ private: SDNode *selectAddESubE(unsigned MOp, SDValue InFlag, SDValue CmpLHS, SDLoc DL, SDNode *Node) const; + bool selectAddrFrameIndex(SDValue Addr, SDValue &Base, SDValue &Offset) const; + bool selectAddrFrameIndexOffset(SDValue Addr, SDValue &Base, SDValue &Offset, + unsigned OffsetBits) const; + virtual bool selectAddrRegImm(SDValue Addr, SDValue &Base, SDValue &Offset) const; @@ -52,12 +56,18 @@ private: virtual bool selectIntAddr(SDValue Addr, SDValue &Base, SDValue &Offset) const; + virtual bool selectAddrRegImm10(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + virtual bool selectAddrRegImm12(SDValue Addr, SDValue &Base, SDValue &Offset) const; virtual bool selectIntAddrMM(SDValue Addr, SDValue &Base, SDValue &Offset) const; + virtual bool selectIntAddrMSA(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + /// \brief Select constant vector splats. virtual bool selectVSplat(SDNode *N, APInt &Imm) const; /// \brief Select constant vector splats whose value fits in a given integer. diff --git a/lib/Target/Mips/MipsSEISelLowering.cpp b/lib/Target/Mips/MipsSEISelLowering.cpp index 809adc0..0dac0b7 100644 --- a/lib/Target/Mips/MipsSEISelLowering.cpp +++ b/lib/Target/Mips/MipsSEISelLowering.cpp @@ -38,7 +38,7 @@ MipsSETargetLowering::MipsSETargetLowering(MipsTargetMachine &TM) // Set up the register classes addRegisterClass(MVT::i32, &Mips::GPR32RegClass); - if (HasMips64) + if (isGP64bit()) addRegisterClass(MVT::i64, &Mips::GPR64RegClass); if (Subtarget->hasDSP() || Subtarget->hasMSA()) { @@ -117,10 +117,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 (hasMips64()) + setOperationAction(ISD::MUL, MVT::i64, Custom); + + if (hasMips64()) { setOperationAction(ISD::MULHS, MVT::i64, Custom); setOperationAction(ISD::MULHU, MVT::i64, Custom); - setOperationAction(ISD::MUL, MVT::i64, Custom); } setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::i64, Custom); @@ -244,7 +248,9 @@ 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; switch (SVT) { @@ -675,7 +681,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(); @@ -1077,14 +1083,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); } @@ -1464,25 +1463,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), @@ -1525,13 +1526,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: @@ -1623,25 +1626,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 (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 (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: @@ -1798,12 +1810,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, @@ -2553,7 +2573,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 +2643,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 +2653,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 +2708,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 +2718,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 +2777,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); } @@ -2817,7 +2844,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; @@ -2850,7 +2878,8 @@ 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; diff --git a/lib/Target/Mips/MipsSEISelLowering.h b/lib/Target/Mips/MipsSEISelLowering.h index c5210d9..079fbf6 100644 --- a/lib/Target/Mips/MipsSEISelLowering.h +++ b/lib/Target/Mips/MipsSEISelLowering.h @@ -30,7 +30,8 @@ namespace llvm { void addMSAFloatType(MVT::SimpleValueType Ty, const TargetRegisterClass *RC); - virtual bool allowsUnalignedMemoryAccesses(EVT VT, bool *Fast) const; + virtual bool allowsUnalignedMemoryAccesses(EVT VT, unsigned AS = 0, + bool *Fast = 0) const override; virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const; diff --git a/lib/Target/Mips/MipsSEInstrInfo.cpp b/lib/Target/Mips/MipsSEInstrInfo.cpp index 02931a3..094ee29 100644 --- a/lib/Target/Mips/MipsSEInstrInfo.cpp +++ b/lib/Target/Mips/MipsSEInstrInfo.cpp @@ -84,19 +84,25 @@ void MipsSEInstrInfo::copyPhysReg(MachineBasicBlock &MBB, unsigned DestReg, unsigned SrcReg, bool KillSrc) const { unsigned Opc = 0, ZeroReg = 0; + bool isMicroMips = TM.getSubtarget<MipsSubtarget>().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,6 +265,8 @@ loadRegFromStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, bool MipsSEInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { MachineBasicBlock &MBB = *MI->getParent(); + bool isMicroMips = TM.getSubtarget<MipsSubtarget>().inMicroMipsMode(); + unsigned Opc; switch(MI->getDesc().getOpcode()) { default: @@ -267,10 +275,12 @@ bool MipsSEInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { expandRetRA(MBB, MI, Mips::RET); 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); @@ -481,7 +491,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 +516,21 @@ 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 + if (SubIdx == Mips::sub_hi && FP64) { + // FIXME: The .addReg(SrcReg, RegState::Implicit) 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. + // 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(Mips::MFHC1), DstReg).addReg(SubReg).addReg( + SrcReg, RegState::Implicit); + } else BuildMI(MBB, I, dl, get(Mips::MFC1), DstReg).addReg(SubReg); } @@ -530,10 +553,22 @@ void MipsSEInstrInfo::expandBuildPairF64(MachineBasicBlock &MBB, BuildMI(MBB, I, dl, Mtc1Tdd, TRI.getSubReg(DstReg, Mips::sub_lo)) .addReg(LoReg); - if (FP64) + if (FP64) { + // FIXME: The .addReg(DstReg, RegState::Implicit) 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(Mips::MTHC1), TRI.getSubReg(DstReg, Mips::sub_hi)) - .addReg(HiReg); - else + .addReg(HiReg) + .addReg(DstReg, RegState::Implicit); + } else BuildMI(MBB, I, dl, Mtc1Tdd, TRI.getSubReg(DstReg, Mips::sub_hi)) .addReg(HiReg); } diff --git a/lib/Target/Mips/MipsSERegisterInfo.cpp b/lib/Target/Mips/MipsSERegisterInfo.cpp index 2d44084..2ac082f 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" @@ -62,21 +61,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 +151,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; - - 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 + // 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 < 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; diff --git a/lib/Target/Mips/MipsSchedule.td b/lib/Target/Mips/MipsSchedule.td index 2779064..ea98199 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/MipsSubtarget.cpp b/lib/Target/Mips/MipsSubtarget.cpp index 0a81072..143b945 100644 --- a/lib/Target/Mips/MipsSubtarget.cpp +++ b/lib/Target/Mips/MipsSubtarget.cpp @@ -14,10 +14,10 @@ #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" @@ -55,9 +55,23 @@ 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 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 CPU; +} void MipsSubtarget::anchor() { } @@ -67,32 +81,44 @@ MipsSubtarget::MipsSubtarget(const std::string &TT, const std::string &CPU, 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), + HasCnMips(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) + RM(_RM), OverrideMode(NoOverride), TM(_TM), TargetTriple(TT) { std::string CPUName = CPU; - if (CPUName.empty()) - CPUName = "mips32"; + CPUName = selectMipsCPU(TT, CPUName); // Parse features string. ParseSubtargetFeatures(CPUName, FS); + if (InMips16Mode && !TM->Options.UseSoftFloat) { + // 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). + TM->Options.UseSoftFloat = true; + TM->Options.FloatABIType = FloatABI::Soft; + InMips16HardFloat = true; + } + PreviousInMips16Mode = InMips16Mode; // Initialize scheduling itinerary for the specified CPU. InstrItins = getInstrItineraryForCPU(CPUName); - // Set MipsABI if it hasn't been set yet. - if (MipsABI == UnknownABI) - MipsABI = hasMips64() ? N64 : O32; + // 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()) @@ -117,8 +143,8 @@ MipsSubtarget::enablePostRAScheduler(CodeGenOpt::Level OptLevel, RegClassVector &CriticalPathRCs) const { Mode = TargetSubtargetInfo::ANTIDEP_NONE; CriticalPathRCs.clear(); - CriticalPathRCs.push_back(hasMips64() ? - &Mips::GPR64RegClass : &Mips::GPR32RegClass); + CriticalPathRCs.push_back(isGP64bit() ? &Mips::GPR64RegClass + : &Mips::GPR32RegClass); return OptLevel >= CodeGenOpt::Aggressive; } diff --git a/lib/Target/Mips/MipsSubtarget.h b/lib/Target/Mips/MipsSubtarget.h index 6b2ab12..2166b93 100644 --- a/lib/Target/Mips/MipsSubtarget.h +++ b/lib/Target/Mips/MipsSubtarget.h @@ -14,11 +14,9 @@ #ifndef MIPSSUBTARGET_H #define MIPSSUBTARGET_H -#include "MCTargetDesc/MipsReginfo.h" #include "llvm/MC/MCInstrItineraries.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Target/TargetSubtargetInfo.h" - #include <string> #define GET_SUBTARGETINFO_HEADER @@ -39,10 +37,7 @@ public: }; protected: - - enum MipsArchEnum { - Mips32, Mips32r2, Mips64, Mips64r2 - }; + enum MipsArchEnum { Mips32, Mips32r2, Mips4, Mips64, Mips64r2 }; // Mips architecture version MipsArchEnum MipsArchVersion; @@ -67,6 +62,9 @@ protected: // 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; @@ -118,9 +116,6 @@ protected: InstrItineraryData InstrItins; - // The instance to the register info section object - MipsReginfo MRI; - // Relocation Model Reloc::Model RM; @@ -130,6 +125,7 @@ protected: MipsTargetMachine *TM; + Triple TargetTriple; public: virtual bool enablePostRAScheduler(CodeGenOpt::Level OptLevel, AntiDepBreakMode& Mode, @@ -158,6 +154,8 @@ public: bool hasMips64() const { return MipsArchVersion >= Mips64; } bool hasMips64r2() const { return MipsArchVersion == Mips64r2; } + bool hasCnMips() const { return HasCnMips; } + bool isLittle() const { return IsLittle; } bool isFP64bit() const { return IsFP64bit; } bool isNotFP64bit() const { return !IsFP64bit; } @@ -212,6 +210,9 @@ public: bool os16() const { return Os16;}; + bool isTargetNaCl() const { return TargetTriple.isOSNaCl(); } + bool isNotTargetNaCl() const { return !TargetTriple.isOSNaCl(); } + // 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 // @@ -219,9 +220,6 @@ static bool useConstantIslands(); unsigned stackAlignment() const { return hasMips64() ? 16 : 8; } - // Grab MipsRegInfo object - const MipsReginfo &getMReginfo() const { return MRI; } - // Grab relocation model Reloc::Model getRelocationModel() const {return RM;} diff --git a/lib/Target/Mips/MipsTargetMachine.cpp b/lib/Target/Mips/MipsTargetMachine.cpp index 5046c1b..e9053c8 100644 --- a/lib/Target/Mips/MipsTargetMachine.cpp +++ b/lib/Target/Mips/MipsTargetMachine.cpp @@ -13,25 +13,25 @@ #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; @@ -45,8 +45,36 @@ extern "C" void LLVMInitializeMipsTarget() { RegisterTargetMachine<MipselTargetMachine> B(TheMips64elTarget); } -// DataLayout --> Big-endian, 32-bit pointer/ABI/alignment -// The stack is always 8 byte aligned +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; +} + // 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 @@ -60,15 +88,7 @@ MipsTargetMachine(const Target &T, StringRef TT, 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")), + DL(computeDataLayout(Subtarget)), InstrInfo(MipsInstrInfo::create(*this)), FrameLowering(MipsFrameLowering::create(*this, Subtarget)), TLInfo(MipsTargetLowering::create(*this)), TSInfo(*this), @@ -153,7 +173,11 @@ public: virtual void addIRPasses(); virtual bool addInstSelector(); + virtual void addMachineSSAOptimization(); virtual bool addPreEmitPass(); + + virtual bool addPreRegAlloc(); + }; } // namespace @@ -182,6 +206,20 @@ bool MipsPassConfig::addInstSelector() { 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()) { DEBUG(errs() << "No "); diff --git a/lib/Target/Mips/MipsTargetObjectFile.cpp b/lib/Target/Mips/MipsTargetObjectFile.cpp index 4c748c5..13f9408 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 c0e9140..2bf5a75 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 96966fd..5f4b74b 100644 --- a/lib/Target/Mips/MipsTargetStreamer.h +++ b/lib/Target/Mips/MipsTargetStreamer.h @@ -18,8 +18,33 @@ class MipsTargetStreamer : public MCTargetStreamer { virtual void anchor(); public: - virtual void emitMipsHackELFFlags(unsigned Flags) = 0; - virtual void emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val) = 0; + MipsTargetStreamer(MCStreamer &S); + virtual void emitDirectiveSetMicroMips() = 0; + virtual void emitDirectiveSetNoMicroMips() = 0; + virtual void emitDirectiveSetMips16() = 0; + virtual void emitDirectiveSetNoMips16() = 0; + + virtual void emitDirectiveSetReorder() = 0; + virtual void emitDirectiveSetNoReorder() = 0; + virtual void emitDirectiveSetMacro() = 0; + virtual void emitDirectiveSetNoMacro() = 0; + virtual void emitDirectiveSetAt() = 0; + virtual void emitDirectiveSetNoAt() = 0; + virtual void emitDirectiveEnd(StringRef Name) = 0; + + virtual void emitDirectiveEnt(const MCSymbol &Symbol) = 0; + virtual void emitDirectiveAbiCalls() = 0; + virtual void emitDirectiveOptionPic0() = 0; + virtual void emitDirectiveOptionPic2() = 0; + virtual void emitFrame(unsigned StackReg, unsigned StackSize, + unsigned ReturnReg) = 0; + virtual void emitMask(unsigned CPUBitmask, int CPUTopSavedRegOff) = 0; + virtual void emitFMask(unsigned FPUBitmask, int FPUTopSavedRegOff) = 0; + + virtual void emitDirectiveSetMips32R2() = 0; + virtual void emitDirectiveSetMips64() = 0; + virtual void emitDirectiveSetMips64R2() = 0; + virtual void emitDirectiveSetDsp() = 0; }; // This part is for ascii assembly output @@ -27,18 +52,76 @@ 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); + 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 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(); }; // 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); + + virtual void emitLabel(MCSymbol *Symbol) override; + virtual void emitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; + void finish() override; + + 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 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(); }; } - #endif diff --git a/lib/Target/Mips/TargetInfo/Android.mk b/lib/Target/Mips/TargetInfo/Android.mk index 8db12d3..173d05b 100644 --- a/lib/Target/Mips/TargetInfo/Android.mk +++ b/lib/Target/Mips/TargetInfo/Android.mk @@ -28,6 +28,7 @@ include $(BUILD_HOST_STATIC_LIBRARY) # For the device # ===================================================== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) include $(CLEAR_VARS) include $(CLEAR_TBLGEN_VARS) @@ -43,3 +44,4 @@ LOCAL_C_INCLUDES += $(LOCAL_PATH)/.. include $(LLVM_DEVICE_BUILD_MK) include $(LLVM_TBLGEN_RULES_MK) include $(BUILD_STATIC_LIBRARY) +endif
\ No newline at end of file diff --git a/lib/Target/Mips/TargetInfo/CMakeLists.txt b/lib/Target/Mips/TargetInfo/CMakeLists.txt index 4172d00..3347a99 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 2d42568..6235bfc 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 |