diff options
Diffstat (limited to 'contrib/llvm/lib/Target/Mips')
118 files changed, 61751 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp new file mode 100644 index 0000000..d4e061f --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -0,0 +1,6204 @@ +//===-- MipsAsmParser.cpp - Parse Mips assembly to MCInst instructions ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/MipsABIInfo.h" +#include "MCTargetDesc/MipsMCExpr.h" +#include "MCTargetDesc/MipsMCTargetDesc.h" +#include "MipsRegisterInfo.h" +#include "MipsTargetObjectFile.h" +#include "MipsTargetStreamer.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/SmallVector.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/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +#include <memory> + +using namespace llvm; + +#define DEBUG_TYPE "mips-asm-parser" + +namespace llvm { +class MCInstrInfo; +} + +namespace { +class MipsAssemblerOptions { +public: + MipsAssemblerOptions(const FeatureBitset &Features_) : + ATReg(1), Reorder(true), Macro(true), Features(Features_) {} + + MipsAssemblerOptions(const MipsAssemblerOptions *Opts) { + ATReg = Opts->getATRegIndex(); + Reorder = Opts->isReorder(); + Macro = Opts->isMacro(); + Features = Opts->getFeatures(); + } + + unsigned getATRegIndex() const { return ATReg; } + bool setATRegIndex(unsigned Reg) { + if (Reg > 31) + return false; + + ATReg = Reg; + return true; + } + + bool isReorder() const { return Reorder; } + void setReorder() { Reorder = true; } + void setNoReorder() { Reorder = false; } + + bool isMacro() const { return Macro; } + void setMacro() { Macro = true; } + void setNoMacro() { Macro = false; } + + const FeatureBitset &getFeatures() const { return Features; } + void setFeatures(const FeatureBitset &Features_) { Features = Features_; } + + // Set of features that are either architecture features or referenced + // by them (e.g.: FeatureNaN2008 implied by FeatureMips32r6). + // The full table can be found in MipsGenSubtargetInfo.inc (MipsFeatureKV[]). + // The reason we need this mask is explained in the selectArch function. + // FIXME: Ideally we would like TableGen to generate this information. + static const FeatureBitset AllArchRelatedMask; + +private: + unsigned ATReg; + bool Reorder; + bool Macro; + FeatureBitset Features; +}; +} + +const FeatureBitset MipsAssemblerOptions::AllArchRelatedMask = { + Mips::FeatureMips1, Mips::FeatureMips2, Mips::FeatureMips3, + Mips::FeatureMips3_32, Mips::FeatureMips3_32r2, Mips::FeatureMips4, + Mips::FeatureMips4_32, Mips::FeatureMips4_32r2, Mips::FeatureMips5, + Mips::FeatureMips5_32r2, Mips::FeatureMips32, Mips::FeatureMips32r2, + Mips::FeatureMips32r3, Mips::FeatureMips32r5, Mips::FeatureMips32r6, + Mips::FeatureMips64, Mips::FeatureMips64r2, Mips::FeatureMips64r3, + Mips::FeatureMips64r5, Mips::FeatureMips64r6, Mips::FeatureCnMips, + Mips::FeatureFP64Bit, Mips::FeatureGP64Bit, Mips::FeatureNaN2008 +}; + +namespace { +class MipsAsmParser : public MCTargetAsmParser { + MipsTargetStreamer &getTargetStreamer() { + MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer(); + return static_cast<MipsTargetStreamer &>(TS); + } + + MipsABIInfo ABI; + SmallVector<std::unique_ptr<MipsAssemblerOptions>, 2> AssemblerOptions; + MCSymbol *CurrentFn; // Pointer to the function being parsed. It may be a + // nullptr, which indicates that no function is currently + // selected. This usually happens after an '.end func' + // directive. + bool IsLittleEndian; + bool IsPicEnabled; + bool IsCpRestoreSet; + int CpRestoreOffset; + unsigned CpSaveLocation; + /// If true, then CpSaveLocation is a register, otherwise it's an offset. + bool CpSaveLocationIsRegister; + + // Print a warning along with its fix-it message at the given range. + void printWarningWithFixIt(const Twine &Msg, const Twine &FixMsg, + SMRange Range, bool ShowColors = true); + +#define GET_ASSEMBLER_HEADER +#include "MipsGenAsmMatcher.inc" + + unsigned checkTargetMatchPredicate(MCInst &Inst) override; + + bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, MCStreamer &Out, + uint64_t &ErrorInfo, + bool MatchingInlineAsm) override; + + /// Parse a register as used in CFI directives + bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; + + bool parseParenSuffix(StringRef Name, OperandVector &Operands); + + bool parseBracketSuffix(StringRef Name, OperandVector &Operands); + + bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) override; + + bool ParseDirective(AsmToken DirectiveID) override; + + OperandMatchResultTy parseMemOperand(OperandVector &Operands); + OperandMatchResultTy + matchAnyRegisterNameWithoutDollar(OperandVector &Operands, + StringRef Identifier, SMLoc S); + OperandMatchResultTy matchAnyRegisterWithoutDollar(OperandVector &Operands, + SMLoc S); + OperandMatchResultTy parseAnyRegister(OperandVector &Operands); + OperandMatchResultTy parseImm(OperandVector &Operands); + OperandMatchResultTy parseJumpTarget(OperandVector &Operands); + OperandMatchResultTy parseInvNum(OperandVector &Operands); + OperandMatchResultTy parseLSAImm(OperandVector &Operands); + OperandMatchResultTy parseRegisterPair(OperandVector &Operands); + OperandMatchResultTy parseMovePRegPair(OperandVector &Operands); + OperandMatchResultTy parseRegisterList(OperandVector &Operands); + + bool searchSymbolAlias(OperandVector &Operands); + + bool parseOperand(OperandVector &, StringRef Mnemonic); + + enum MacroExpanderResultTy { + MER_NotAMacro, + MER_Success, + MER_Fail, + }; + + // Expands assembly pseudo instructions. + MacroExpanderResultTy + tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + bool expandJalWithRegs(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + bool loadImmediate(int64_t ImmValue, unsigned DstReg, unsigned SrcReg, + bool Is32BitImm, bool IsAddress, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + bool loadAndAddSymbolAddress(const MCExpr *SymExpr, unsigned DstReg, + unsigned SrcReg, bool Is32BitSym, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + bool expandLoadImm(MCInst &Inst, bool Is32BitImm, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + bool expandLoadAddress(unsigned DstReg, unsigned BaseReg, + const MCOperand &Offset, bool Is32BitAddress, + SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); + + bool expandUncondBranchMMPseudo(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + void expandMemInst(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions, bool isLoad, + bool isImmOpnd); + + bool expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + bool expandAliasImmediate(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + bool expandBranchImm(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + bool expandCondBranches(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + bool expandDiv(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions, const bool IsMips64, + const bool Signed); + + bool expandUlh(MCInst &Inst, bool Signed, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + bool expandUlw(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + bool expandRotation(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + bool expandRotationImm(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + bool expandDRotation(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + bool expandDRotationImm(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + void createNop(bool hasShortDelaySlot, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + void createAddu(unsigned DstReg, unsigned SrcReg, unsigned TrgReg, + bool Is64Bit, SmallVectorImpl<MCInst> &Instructions); + + void createCpRestoreMemOp(bool IsLoad, int StackOffset, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + bool reportParseError(Twine ErrorMsg); + bool reportParseError(SMLoc Loc, Twine ErrorMsg); + + bool parseMemOffset(const MCExpr *&Res, bool isParenExpr); + bool parseRelocOperand(const MCExpr *&Res); + + const MCExpr *evaluateRelocExpr(const MCExpr *Expr, StringRef RelocStr); + + bool isEvaluated(const MCExpr *Expr); + bool parseSetMips0Directive(); + bool parseSetArchDirective(); + bool parseSetFeature(uint64_t Feature); + bool isPicAndNotNxxAbi(); // Used by .cpload, .cprestore, and .cpsetup. + bool parseDirectiveCpLoad(SMLoc Loc); + bool parseDirectiveCpRestore(SMLoc Loc); + bool parseDirectiveCPSetup(); + bool parseDirectiveCPReturn(); + bool parseDirectiveNaN(); + bool parseDirectiveSet(); + bool parseDirectiveOption(); + bool parseInsnDirective(); + + bool parseSetAtDirective(); + bool parseSetNoAtDirective(); + bool parseSetMacroDirective(); + bool parseSetNoMacroDirective(); + bool parseSetMsaDirective(); + bool parseSetNoMsaDirective(); + bool parseSetNoDspDirective(); + bool parseSetReorderDirective(); + bool parseSetNoReorderDirective(); + bool parseSetMips16Directive(); + bool parseSetNoMips16Directive(); + bool parseSetFpDirective(); + bool parseSetOddSPRegDirective(); + bool parseSetNoOddSPRegDirective(); + bool parseSetPopDirective(); + bool parseSetPushDirective(); + bool parseSetSoftFloatDirective(); + bool parseSetHardFloatDirective(); + + bool parseSetAssignment(); + + bool parseDataDirective(unsigned Size, SMLoc L); + bool parseDirectiveGpWord(); + bool parseDirectiveGpDWord(); + bool parseDirectiveModule(); + bool parseDirectiveModuleFP(); + bool parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI, + StringRef Directive); + + bool parseInternalDirectiveReallowModule(); + + MCSymbolRefExpr::VariantKind getVariantKind(StringRef Symbol); + + bool eatComma(StringRef ErrorStr); + + int matchCPURegisterName(StringRef Symbol); + + int matchHWRegsRegisterName(StringRef Symbol); + + int matchRegisterByNumber(unsigned RegNum, unsigned RegClass); + + int matchFPURegisterName(StringRef Name); + + int matchFCCRegisterName(StringRef Name); + + int matchACRegisterName(StringRef Name); + + int matchMSA128RegisterName(StringRef Name); + + int matchMSA128CtrlRegisterName(StringRef Name); + + unsigned getReg(int RC, int RegNo); + + unsigned getGPR(int RegNo); + + /// Returns the internal register number for the current AT. Also checks if + /// the current AT is unavailable (set to $0) and gives an error if it is. + /// This should be used in pseudo-instruction expansions which need AT. + unsigned getATReg(SMLoc Loc); + + bool processInstruction(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + // Helper function that checks if the value of a vector index is within the + // boundaries of accepted values for each RegisterKind + // Example: INSERT.B $w0[n], $1 => 16 > n >= 0 + bool validateMSAIndex(int Val, int RegKind); + + // Selects a new architecture by updating the FeatureBits with the necessary + // info including implied dependencies. + // Internally, it clears all the feature bits related to *any* architecture + // and selects the new one using the ToggleFeature functionality of the + // MCSubtargetInfo object that handles implied dependencies. The reason we + // clear all the arch related bits manually is because ToggleFeature only + // clears the features that imply the feature being cleared and not the + // features implied by the feature being cleared. This is easier to see + // with an example: + // -------------------------------------------------- + // | Feature | Implies | + // | -------------------------------------------------| + // | FeatureMips1 | None | + // | FeatureMips2 | FeatureMips1 | + // | FeatureMips3 | FeatureMips2 | FeatureMipsGP64 | + // | FeatureMips4 | FeatureMips3 | + // | ... | | + // -------------------------------------------------- + // + // Setting Mips3 is equivalent to set: (FeatureMips3 | FeatureMips2 | + // FeatureMipsGP64 | FeatureMips1) + // Clearing Mips3 is equivalent to clear (FeatureMips3 | FeatureMips4). + void selectArch(StringRef ArchFeature) { + MCSubtargetInfo &STI = copySTI(); + FeatureBitset FeatureBits = STI.getFeatureBits(); + FeatureBits &= ~MipsAssemblerOptions::AllArchRelatedMask; + STI.setFeatureBits(FeatureBits); + setAvailableFeatures( + ComputeAvailableFeatures(STI.ToggleFeature(ArchFeature))); + AssemblerOptions.back()->setFeatures(STI.getFeatureBits()); + } + + void setFeatureBits(uint64_t Feature, StringRef FeatureString) { + if (!(getSTI().getFeatureBits()[Feature])) { + MCSubtargetInfo &STI = copySTI(); + setAvailableFeatures( + ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); + AssemblerOptions.back()->setFeatures(STI.getFeatureBits()); + } + } + + void clearFeatureBits(uint64_t Feature, StringRef FeatureString) { + if (getSTI().getFeatureBits()[Feature]) { + MCSubtargetInfo &STI = copySTI(); + setAvailableFeatures( + ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); + AssemblerOptions.back()->setFeatures(STI.getFeatureBits()); + } + } + + void setModuleFeatureBits(uint64_t Feature, StringRef FeatureString) { + setFeatureBits(Feature, FeatureString); + AssemblerOptions.front()->setFeatures(getSTI().getFeatureBits()); + } + + void clearModuleFeatureBits(uint64_t Feature, StringRef FeatureString) { + clearFeatureBits(Feature, FeatureString); + AssemblerOptions.front()->setFeatures(getSTI().getFeatureBits()); + } + +public: + enum MipsMatchResultTy { + Match_RequiresDifferentSrcAndDst = FIRST_TARGET_MATCH_RESULT_TY, +#define GET_OPERAND_DIAGNOSTIC_TYPES +#include "MipsGenAsmMatcher.inc" +#undef GET_OPERAND_DIAGNOSTIC_TYPES + }; + + MipsAsmParser(const MCSubtargetInfo &sti, MCAsmParser &parser, + const MCInstrInfo &MII, const MCTargetOptions &Options) + : MCTargetAsmParser(Options, sti), + ABI(MipsABIInfo::computeTargetABI(Triple(sti.getTargetTriple()), + sti.getCPU(), Options)) { + MCAsmParserExtension::Initialize(parser); + + parser.addAliasForDirective(".asciiz", ".asciz"); + + // Initialize the set of available features. + setAvailableFeatures(ComputeAvailableFeatures(getSTI().getFeatureBits())); + + // Remember the initial assembler options. The user can not modify these. + AssemblerOptions.push_back( + llvm::make_unique<MipsAssemblerOptions>(getSTI().getFeatureBits())); + + // Create an assembler options environment for the user to modify. + AssemblerOptions.push_back( + llvm::make_unique<MipsAssemblerOptions>(getSTI().getFeatureBits())); + + getTargetStreamer().updateABIInfo(*this); + + if (!isABI_O32() && !useOddSPReg() != 0) + report_fatal_error("-mno-odd-spreg requires the O32 ABI"); + + CurrentFn = nullptr; + + IsPicEnabled = + (getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_); + + IsCpRestoreSet = false; + CpRestoreOffset = -1; + + Triple TheTriple(sti.getTargetTriple()); + if ((TheTriple.getArch() == Triple::mips) || + (TheTriple.getArch() == Triple::mips64)) + IsLittleEndian = false; + else + IsLittleEndian = true; + } + + /// True if all of $fcc0 - $fcc7 exist for the current ISA. + bool hasEightFccRegisters() const { return hasMips4() || hasMips32(); } + + bool isGP64bit() const { + return getSTI().getFeatureBits()[Mips::FeatureGP64Bit]; + } + bool isFP64bit() const { + return getSTI().getFeatureBits()[Mips::FeatureFP64Bit]; + } + const MipsABIInfo &getABI() const { return ABI; } + bool isABI_N32() const { return ABI.IsN32(); } + bool isABI_N64() const { return ABI.IsN64(); } + bool isABI_O32() const { return ABI.IsO32(); } + bool isABI_FPXX() const { + return getSTI().getFeatureBits()[Mips::FeatureFPXX]; + } + + bool useOddSPReg() const { + return !(getSTI().getFeatureBits()[Mips::FeatureNoOddSPReg]); + } + + bool inMicroMipsMode() const { + return getSTI().getFeatureBits()[Mips::FeatureMicroMips]; + } + bool hasMips1() const { + return getSTI().getFeatureBits()[Mips::FeatureMips1]; + } + bool hasMips2() const { + return getSTI().getFeatureBits()[Mips::FeatureMips2]; + } + bool hasMips3() const { + return getSTI().getFeatureBits()[Mips::FeatureMips3]; + } + bool hasMips4() const { + return getSTI().getFeatureBits()[Mips::FeatureMips4]; + } + bool hasMips5() const { + return getSTI().getFeatureBits()[Mips::FeatureMips5]; + } + bool hasMips32() const { + return getSTI().getFeatureBits()[Mips::FeatureMips32]; + } + bool hasMips64() const { + return getSTI().getFeatureBits()[Mips::FeatureMips64]; + } + bool hasMips32r2() const { + return getSTI().getFeatureBits()[Mips::FeatureMips32r2]; + } + bool hasMips64r2() const { + return getSTI().getFeatureBits()[Mips::FeatureMips64r2]; + } + bool hasMips32r3() const { + return (getSTI().getFeatureBits()[Mips::FeatureMips32r3]); + } + bool hasMips64r3() const { + return (getSTI().getFeatureBits()[Mips::FeatureMips64r3]); + } + bool hasMips32r5() const { + return (getSTI().getFeatureBits()[Mips::FeatureMips32r5]); + } + bool hasMips64r5() const { + return (getSTI().getFeatureBits()[Mips::FeatureMips64r5]); + } + bool hasMips32r6() const { + return getSTI().getFeatureBits()[Mips::FeatureMips32r6]; + } + bool hasMips64r6() const { + return getSTI().getFeatureBits()[Mips::FeatureMips64r6]; + } + + bool hasDSP() const { + return getSTI().getFeatureBits()[Mips::FeatureDSP]; + } + bool hasDSPR2() const { + return getSTI().getFeatureBits()[Mips::FeatureDSPR2]; + } + bool hasDSPR3() const { + return getSTI().getFeatureBits()[Mips::FeatureDSPR3]; + } + bool hasMSA() const { + return getSTI().getFeatureBits()[Mips::FeatureMSA]; + } + bool hasCnMips() const { + return (getSTI().getFeatureBits()[Mips::FeatureCnMips]); + } + + bool inPicMode() { + return IsPicEnabled; + } + + bool inMips16Mode() const { + return getSTI().getFeatureBits()[Mips::FeatureMips16]; + } + + bool useTraps() const { + return getSTI().getFeatureBits()[Mips::FeatureUseTCCInDIV]; + } + + bool useSoftFloat() const { + return getSTI().getFeatureBits()[Mips::FeatureSoftFloat]; + } + + /// Warn if RegIndex is the same as the current AT. + void warnIfRegIndexIsAT(unsigned RegIndex, SMLoc Loc); + + void warnIfNoMacro(SMLoc Loc); + + bool isLittle() const { return IsLittleEndian; } +}; +} + +namespace { + +/// MipsOperand - Instances of this class represent a parsed Mips machine +/// instruction. +class MipsOperand : public MCParsedAsmOperand { +public: + /// Broad categories of register classes + /// The exact class is finalized by the render method. + enum RegKind { + RegKind_GPR = 1, /// GPR32 and GPR64 (depending on isGP64bit()) + RegKind_FGR = 2, /// FGR32, FGR64, AFGR64 (depending on context and + /// isFP64bit()) + RegKind_FCC = 4, /// FCC + RegKind_MSA128 = 8, /// MSA128[BHWD] (makes no difference which) + RegKind_MSACtrl = 16, /// MSA control registers + RegKind_COP2 = 32, /// COP2 + RegKind_ACC = 64, /// HI32DSP, LO32DSP, and ACC64DSP (depending on + /// context). + RegKind_CCR = 128, /// CCR + RegKind_HWRegs = 256, /// HWRegs + RegKind_COP3 = 512, /// COP3 + RegKind_COP0 = 1024, /// COP0 + /// Potentially any (e.g. $1) + RegKind_Numeric = RegKind_GPR | RegKind_FGR | RegKind_FCC | RegKind_MSA128 | + RegKind_MSACtrl | RegKind_COP2 | RegKind_ACC | + RegKind_CCR | RegKind_HWRegs | RegKind_COP3 | RegKind_COP0 + }; + +private: + enum KindTy { + 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 + k_RegList, /// A physical register list + k_RegPair /// A pair of physical register + } Kind; + +public: + MipsOperand(KindTy K, MipsAsmParser &Parser) + : MCParsedAsmOperand(), Kind(K), AsmParser(Parser) {} + +private: + /// For diagnostics, and checking the assembler temporary + MipsAsmParser &AsmParser; + + struct Token { + const char *Data; + unsigned Length; + }; + + struct 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 { + const MCExpr *Val; + }; + + struct MemOp { + MipsOperand *Base; + const MCExpr *Off; + }; + + struct RegListOp { + SmallVector<unsigned, 10> *List; + }; + + union { + struct Token Tok; + struct PhysRegOp PhysReg; + struct RegIdxOp RegIdx; + struct ImmOp Imm; + struct MemOp Mem; + struct RegListOp RegList; + }; + + SMLoc StartLoc, EndLoc; + + /// Internal constructor for register kinds + static std::unique_ptr<MipsOperand> CreateReg(unsigned Index, RegKind RegKind, + const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + auto Op = make_unique<MipsOperand>(k_RegisterIndex, Parser); + Op->RegIdx.Index = Index; + Op->RegIdx.RegInfo = RegInfo; + Op->RegIdx.Kind = RegKind; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + +public: + /// 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.warnIfRegIndexIsAT(RegIdx.Index, StartLoc); + unsigned ClassID = Mips::GPR32RegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to GPR32 and return the real register for the current + /// target. + unsigned getGPRMM16Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_GPR) && "Invalid access!"); + unsigned ClassID = Mips::GPR32RegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// 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 COP0 and return the real register for the + /// current target. + unsigned getCOP0Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_COP0) && "Invalid access!"); + unsigned ClassID = Mips::COP0RegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to COP2 and return the real register for the + /// current target. + unsigned getCOP2Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_COP2) && "Invalid access!"); + unsigned ClassID = Mips::COP2RegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to COP3 and return the real register for the + /// current target. + unsigned getCOP3Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_COP3) && "Invalid access!"); + unsigned ClassID = Mips::COP3RegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to ACC64DSP and return the real register for the + /// current target. + unsigned getACC64DSPReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_ACC) && "Invalid access!"); + unsigned ClassID = Mips::ACC64DSPRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to HI32DSP and return the real register for the + /// current target. + unsigned getHI32DSPReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_ACC) && "Invalid access!"); + unsigned ClassID = Mips::HI32DSPRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to LO32DSP and return the real register for the + /// current target. + unsigned getLO32DSPReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_ACC) && "Invalid access!"); + unsigned ClassID = Mips::LO32DSPRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to CCR and return the real register for the + /// current target. + unsigned getCCRReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_CCR) && "Invalid access!"); + unsigned ClassID = Mips::CCRRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to HWRegs and return the real register for the + /// current target. + unsigned getHWRegsReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_HWRegs) && "Invalid access!"); + unsigned ClassID = Mips::HWRegsRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + +public: + void addExpr(MCInst &Inst, const MCExpr *Expr) const { + // Add as immediate when possible. Null MCExpr = 0. + if (!Expr) + Inst.addOperand(MCOperand::createImm(0)); + else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr)) + Inst.addOperand(MCOperand::createImm(CE->getValue())); + else + Inst.addOperand(MCOperand::createExpr(Expr)); + } + + void addRegOperands(MCInst &Inst, unsigned N) const { + 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())); + } + + void addGPRMM16AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getGPRMM16Reg())); + } + + void addGPRMM16AsmRegZeroOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getGPRMM16Reg())); + } + + void addGPRMM16AsmRegMovePOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getGPRMM16Reg())); + } + + /// Render the operand to an MCInst as a GPR64 + /// Asserts if the wrong number of operands are requested, or the operand + /// is not a k_RegisterIndex compatible with RegKind_GPR + void addGPR64AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getGPR64Reg())); + } + + void addAFGR64AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getAFGR64Reg())); + } + + void addFGR64AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getFGR64Reg())); + } + + void addFGR32AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getFGR32Reg())); + // FIXME: We ought to do this for -integrated-as without -via-file-asm too. + if (!AsmParser.useOddSPReg() && RegIdx.Index & 1) + AsmParser.Error(StartLoc, "-mno-odd-spreg prohibits the use of odd FPU " + "registers"); + } + + void addFGRH32AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getFGRH32Reg())); + } + + void addFCCAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getFCCReg())); + } + + void addMSA128AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getMSA128Reg())); + } + + void addMSACtrlAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getMSACtrlReg())); + } + + void addCOP0AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getCOP0Reg())); + } + + void addCOP2AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getCOP2Reg())); + } + + void addCOP3AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getCOP3Reg())); + } + + void addACC64DSPAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getACC64DSPReg())); + } + + void addHI32DSPAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getHI32DSPReg())); + } + + void addLO32DSPAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getLO32DSPReg())); + } + + void addCCRAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getCCRReg())); + } + + void addHWRegsAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getHWRegsReg())); + } + + template <unsigned Bits, int Offset = 0, int AdjustOffset = 0> + void addConstantUImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + uint64_t Imm = getConstantImm() - Offset; + Imm &= (1 << Bits) - 1; + Imm += Offset; + Imm += AdjustOffset; + Inst.addOperand(MCOperand::createImm(Imm)); + } + + void addImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCExpr *Expr = getImm(); + addExpr(Inst, Expr); + } + + void addMemOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + + Inst.addOperand(MCOperand::createReg(AsmParser.getABI().ArePtrs64bit() + ? getMemBase()->getGPR64Reg() + : getMemBase()->getGPR32Reg())); + + const MCExpr *Expr = getMemOff(); + addExpr(Inst, Expr); + } + + void addMicroMipsMemOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + + Inst.addOperand(MCOperand::createReg(getMemBase()->getGPRMM16Reg())); + + const MCExpr *Expr = getMemOff(); + addExpr(Inst, Expr); + } + + void addRegListOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + + for (auto RegNo : getRegList()) + Inst.addOperand(MCOperand::createReg(RegNo)); + } + + void addRegPairOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + unsigned RegNo = getRegPair(); + Inst.addOperand(MCOperand::createReg(RegNo++)); + Inst.addOperand(MCOperand::createReg(RegNo)); + } + + void addMovePRegPairOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + for (auto RegNo : getRegList()) + Inst.addOperand(MCOperand::createReg(RegNo)); + } + + bool isReg() const override { + // As a special case until we sort out the definition of div/divu, pretend + // that $0/$zero are k_PhysRegister so that MCK_ZERO works correctly. + if (isGPRAsmReg() && RegIdx.Index == 0) + return true; + + return Kind == k_PhysRegister; + } + bool isRegIdx() const { return Kind == k_RegisterIndex; } + bool isImm() const override { return Kind == k_Immediate; } + bool isConstantImm() const { + return isImm() && isa<MCConstantExpr>(getImm()); + } + bool isConstantImmz() const { + return isConstantImm() && getConstantImm() == 0; + } + template <unsigned Bits, int Offset = 0> bool isConstantUImm() const { + return isConstantImm() && isUInt<Bits>(getConstantImm() - Offset); + } + template <unsigned Bits> bool isConstantSImm() const { + return isConstantImm() && isInt<Bits>(getConstantImm()); + } + bool isToken() const override { + // Note: It's not possible to pretend that other operand kinds are tokens. + // The matcher emitter checks tokens first. + return Kind == k_Token; + } + bool isMem() const override { return Kind == k_Memory; } + bool isConstantMemOff() const { + return isMem() && isa<MCConstantExpr>(getMemOff()); + } + template <unsigned Bits> bool isMemWithSimmOffset() const { + return isMem() && isConstantMemOff() && isInt<Bits>(getConstantMemOff()) + && getMemBase()->isGPRAsmReg(); + } + template <unsigned Bits> bool isMemWithSimmOffsetGPR() const { + return isMem() && isConstantMemOff() && isInt<Bits>(getConstantMemOff()) && + getMemBase()->isGPRAsmReg(); + } + bool isMemWithGRPMM16Base() const { + return isMem() && getMemBase()->isMM16AsmReg(); + } + template <unsigned Bits> bool isMemWithUimmOffsetSP() const { + return isMem() && isConstantMemOff() && isUInt<Bits>(getConstantMemOff()) + && getMemBase()->isRegIdx() && (getMemBase()->getGPR32Reg() == Mips::SP); + } + template <unsigned Bits> bool isMemWithUimmWordAlignedOffsetSP() const { + return isMem() && isConstantMemOff() && isUInt<Bits>(getConstantMemOff()) + && (getConstantMemOff() % 4 == 0) && getMemBase()->isRegIdx() + && (getMemBase()->getGPR32Reg() == Mips::SP); + } + template <unsigned Bits, unsigned ShiftLeftAmount> + bool isScaledUImm() const { + return isConstantImm() && + isShiftedUInt<Bits, ShiftLeftAmount>(getConstantImm()); + } + bool isRegList16() const { + if (!isRegList()) + return false; + + int Size = RegList.List->size(); + if (Size < 2 || Size > 5) + return false; + + unsigned R0 = RegList.List->front(); + unsigned R1 = RegList.List->back(); + if (!((R0 == Mips::S0 && R1 == Mips::RA) || + (R0 == Mips::S0_64 && R1 == Mips::RA_64))) + return false; + + int PrevReg = *RegList.List->begin(); + for (int i = 1; i < Size - 1; i++) { + int Reg = (*(RegList.List))[i]; + if ( Reg != PrevReg + 1) + return false; + PrevReg = Reg; + } + + return true; + } + bool isInvNum() const { return Kind == k_Immediate; } + bool isLSAImm() const { + if (!isConstantImm()) + return false; + int64_t Val = getConstantImm(); + return 1 <= Val && Val <= 4; + } + bool isRegList() const { return Kind == k_RegList; } + bool isMovePRegPair() const { + if (Kind != k_RegList || RegList.List->size() != 2) + return false; + + unsigned R0 = RegList.List->front(); + unsigned R1 = RegList.List->back(); + + if ((R0 == Mips::A1 && R1 == Mips::A2) || + (R0 == Mips::A1 && R1 == Mips::A3) || + (R0 == Mips::A2 && R1 == Mips::A3) || + (R0 == Mips::A0 && R1 == Mips::S5) || + (R0 == Mips::A0 && R1 == Mips::S6) || + (R0 == Mips::A0 && R1 == Mips::A1) || + (R0 == Mips::A0 && R1 == Mips::A2) || + (R0 == Mips::A0 && R1 == Mips::A3)) + return true; + + return false; + } + + StringRef getToken() const { + assert(Kind == k_Token && "Invalid access!"); + return StringRef(Tok.Data, Tok.Length); + } + bool isRegPair() const { return Kind == k_RegPair; } + + unsigned getReg() const override { + // As a special case until we sort out the definition of div/divu, pretend + // that $0/$zero are k_PhysRegister so that MCK_ZERO works correctly. + if (Kind == k_RegisterIndex && RegIdx.Index == 0 && + RegIdx.Kind & RegKind_GPR) + return getGPR32Reg(); // FIXME: GPR64 too + + assert(Kind == k_PhysRegister && "Invalid access!"); + return PhysReg.Num; + } + + const MCExpr *getImm() const { + assert((Kind == k_Immediate) && "Invalid access!"); + return Imm.Val; + } + + 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; + } + + const MCExpr *getMemOff() const { + assert((Kind == k_Memory) && "Invalid access!"); + return Mem.Off; + } + + int64_t getConstantMemOff() const { + return static_cast<const MCConstantExpr *>(getMemOff())->getValue(); + } + + const SmallVectorImpl<unsigned> &getRegList() const { + assert((Kind == k_RegList) && "Invalid access!"); + return *(RegList.List); + } + + unsigned getRegPair() const { + assert((Kind == k_RegPair) && "Invalid access!"); + return RegIdx.Index; + } + + static std::unique_ptr<MipsOperand> CreateToken(StringRef Str, SMLoc S, + MipsAsmParser &Parser) { + auto Op = make_unique<MipsOperand>(k_Token, Parser); + Op->Tok.Data = Str.data(); + Op->Tok.Length = Str.size(); + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + + /// Create a numeric register (e.g. $1). The exact register remains + /// unresolved until an instruction successfully matches + static std::unique_ptr<MipsOperand> + createNumericReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + DEBUG(dbgs() << "createNumericReg(" << Index << ", ...)\n"); + return CreateReg(Index, RegKind_Numeric, RegInfo, S, E, Parser); + } + + /// Create a register that is definitely a GPR. + /// This is typically only used for named registers such as $gp. + static std::unique_ptr<MipsOperand> + createGPRReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_GPR, RegInfo, S, E, Parser); + } + + /// Create a register that is definitely a FGR. + /// This is typically only used for named registers such as $f0. + static std::unique_ptr<MipsOperand> + createFGRReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_FGR, RegInfo, S, E, Parser); + } + + /// Create a register that is definitely a HWReg. + /// This is typically only used for named registers such as $hwr_cpunum. + static std::unique_ptr<MipsOperand> + createHWRegsReg(unsigned Index, const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_HWRegs, RegInfo, S, E, Parser); + } + + /// Create a register that is definitely an FCC. + /// This is typically only used for named registers such as $fcc0. + static std::unique_ptr<MipsOperand> + createFCCReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_FCC, RegInfo, S, E, Parser); + } + + /// Create a register that is definitely an ACC. + /// This is typically only used for named registers such as $ac0. + static std::unique_ptr<MipsOperand> + createACCReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_ACC, RegInfo, S, E, Parser); + } + + /// Create a register that is definitely an MSA128. + /// This is typically only used for named registers such as $w0. + static std::unique_ptr<MipsOperand> + createMSA128Reg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_MSA128, RegInfo, S, E, Parser); + } + + /// Create a register that is definitely an MSACtrl. + /// This is typically only used for named registers such as $msaaccess. + static std::unique_ptr<MipsOperand> + createMSACtrlReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_MSACtrl, RegInfo, S, E, Parser); + } + + static std::unique_ptr<MipsOperand> + CreateImm(const MCExpr *Val, SMLoc S, SMLoc E, MipsAsmParser &Parser) { + auto Op = make_unique<MipsOperand>(k_Immediate, Parser); + Op->Imm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static std::unique_ptr<MipsOperand> + CreateMem(std::unique_ptr<MipsOperand> Base, const MCExpr *Off, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + auto Op = make_unique<MipsOperand>(k_Memory, Parser); + Op->Mem.Base = Base.release(); + Op->Mem.Off = Off; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static std::unique_ptr<MipsOperand> + CreateRegList(SmallVectorImpl<unsigned> &Regs, SMLoc StartLoc, SMLoc EndLoc, + MipsAsmParser &Parser) { + assert (Regs.size() > 0 && "Empty list not allowed"); + + auto Op = make_unique<MipsOperand>(k_RegList, Parser); + Op->RegList.List = new SmallVector<unsigned, 10>(Regs.begin(), Regs.end()); + Op->StartLoc = StartLoc; + Op->EndLoc = EndLoc; + return Op; + } + + static std::unique_ptr<MipsOperand> + CreateRegPair(unsigned RegNo, SMLoc S, SMLoc E, MipsAsmParser &Parser) { + auto Op = make_unique<MipsOperand>(k_RegPair, Parser); + Op->RegIdx.Index = RegNo; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + bool isGPRAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index <= 31; + } + bool isMM16AsmReg() const { + if (!(isRegIdx() && RegIdx.Kind)) + return false; + return ((RegIdx.Index >= 2 && RegIdx.Index <= 7) + || RegIdx.Index == 16 || RegIdx.Index == 17); + } + bool isMM16AsmRegZero() const { + if (!(isRegIdx() && RegIdx.Kind)) + return false; + return (RegIdx.Index == 0 || + (RegIdx.Index >= 2 && RegIdx.Index <= 7) || + RegIdx.Index == 17); + } + bool isMM16AsmRegMoveP() const { + if (!(isRegIdx() && RegIdx.Kind)) + return false; + return (RegIdx.Index == 0 || (RegIdx.Index >= 2 && RegIdx.Index <= 3) || + (RegIdx.Index >= 16 && RegIdx.Index <= 20)); + } + bool isFGRAsmReg() const { + // AFGR64 is $0-$15 but we handle this in getAFGR64() + return isRegIdx() && RegIdx.Kind & RegKind_FGR && RegIdx.Index <= 31; + } + bool isHWRegsAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_HWRegs && RegIdx.Index <= 31; + } + bool isCCRAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_CCR && RegIdx.Index <= 31; + } + bool isFCCAsmReg() const { + if (!(isRegIdx() && RegIdx.Kind & RegKind_FCC)) + return false; + if (!AsmParser.hasEightFccRegisters()) + return RegIdx.Index == 0; + return RegIdx.Index <= 7; + } + bool isACCAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_ACC && RegIdx.Index <= 3; + } + bool isCOP0AsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_COP0 && RegIdx.Index <= 31; + } + bool isCOP2AsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_COP2 && RegIdx.Index <= 31; + } + bool isCOP3AsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_COP3 && RegIdx.Index <= 31; + } + bool isMSA128AsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_MSA128 && RegIdx.Index <= 31; + } + bool isMSACtrlAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_MSACtrl && RegIdx.Index <= 7; + } + + /// getStartLoc - Get the location of the first token of this operand. + SMLoc getStartLoc() const override { return StartLoc; } + /// getEndLoc - Get the location of the last token of this operand. + SMLoc getEndLoc() const override { return EndLoc; } + + virtual ~MipsOperand() { + switch (Kind) { + case k_Immediate: + break; + case k_Memory: + delete Mem.Base; + break; + case k_RegList: + delete RegList.List; + case k_PhysRegister: + case k_RegisterIndex: + case k_Token: + case k_RegPair: + break; + } + } + + void print(raw_ostream &OS) const override { + switch (Kind) { + case k_Immediate: + OS << "Imm<"; + OS << *Imm.Val; + OS << ">"; + break; + case k_Memory: + OS << "Mem<"; + Mem.Base->print(OS); + OS << ", "; + OS << *Mem.Off; + 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; + case k_RegList: + OS << "RegList< "; + for (auto Reg : (*RegList.List)) + OS << Reg << " "; + OS << ">"; + break; + case k_RegPair: + OS << "RegPair<" << RegIdx.Index << "," << RegIdx.Index + 1 << ">"; + break; + } + } +}; // class MipsOperand +} // namespace + +namespace llvm { +extern const MCInstrDesc MipsInsts[]; +} +static const MCInstrDesc &getInstDesc(unsigned Opcode) { + return MipsInsts[Opcode]; +} + +static bool hasShortDelaySlot(unsigned Opcode) { + switch (Opcode) { + case Mips::JALS_MM: + case Mips::JALRS_MM: + case Mips::JALRS16_MM: + case Mips::BGEZALS_MM: + case Mips::BLTZALS_MM: + return true; + default: + return false; + } +} + +static const MCSymbol *getSingleMCSymbol(const MCExpr *Expr) { + if (const MCSymbolRefExpr *SRExpr = dyn_cast<MCSymbolRefExpr>(Expr)) { + return &SRExpr->getSymbol(); + } + + if (const MCBinaryExpr *BExpr = dyn_cast<MCBinaryExpr>(Expr)) { + const MCSymbol *LHSSym = getSingleMCSymbol(BExpr->getLHS()); + const MCSymbol *RHSSym = getSingleMCSymbol(BExpr->getRHS()); + + if (LHSSym) + return LHSSym; + + if (RHSSym) + return RHSSym; + + return nullptr; + } + + if (const MCUnaryExpr *UExpr = dyn_cast<MCUnaryExpr>(Expr)) + return getSingleMCSymbol(UExpr->getSubExpr()); + + return nullptr; +} + +static unsigned countMCSymbolRefExpr(const MCExpr *Expr) { + if (isa<MCSymbolRefExpr>(Expr)) + return 1; + + if (const MCBinaryExpr *BExpr = dyn_cast<MCBinaryExpr>(Expr)) + return countMCSymbolRefExpr(BExpr->getLHS()) + + countMCSymbolRefExpr(BExpr->getRHS()); + + if (const MCUnaryExpr *UExpr = dyn_cast<MCUnaryExpr>(Expr)) + return countMCSymbolRefExpr(UExpr->getSubExpr()); + + return 0; +} + +namespace { +void emitRX(unsigned Opcode, unsigned Reg0, MCOperand Op1, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + MCInst tmpInst; + tmpInst.setOpcode(Opcode); + tmpInst.addOperand(MCOperand::createReg(Reg0)); + tmpInst.addOperand(Op1); + tmpInst.setLoc(IDLoc); + Instructions.push_back(tmpInst); +} + +void emitRI(unsigned Opcode, unsigned Reg0, int32_t Imm, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + emitRX(Opcode, Reg0, MCOperand::createImm(Imm), IDLoc, Instructions); +} + +void emitRR(unsigned Opcode, unsigned Reg0, unsigned Reg1, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + emitRX(Opcode, Reg0, MCOperand::createReg(Reg1), IDLoc, Instructions); +} + +void emitII(unsigned Opcode, int16_t Imm1, int16_t Imm2, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + MCInst tmpInst; + tmpInst.setOpcode(Opcode); + tmpInst.addOperand(MCOperand::createImm(Imm1)); + tmpInst.addOperand(MCOperand::createImm(Imm2)); + tmpInst.setLoc(IDLoc); + Instructions.push_back(tmpInst); +} + +void emitR(unsigned Opcode, unsigned Reg0, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + MCInst tmpInst; + tmpInst.setOpcode(Opcode); + tmpInst.addOperand(MCOperand::createReg(Reg0)); + tmpInst.setLoc(IDLoc); + Instructions.push_back(tmpInst); +} + +void emitRRX(unsigned Opcode, unsigned Reg0, unsigned Reg1, MCOperand Op2, + SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { + MCInst tmpInst; + tmpInst.setOpcode(Opcode); + tmpInst.addOperand(MCOperand::createReg(Reg0)); + tmpInst.addOperand(MCOperand::createReg(Reg1)); + tmpInst.addOperand(Op2); + tmpInst.setLoc(IDLoc); + Instructions.push_back(tmpInst); +} + +void emitRRR(unsigned Opcode, unsigned Reg0, unsigned Reg1, unsigned Reg2, + SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { + emitRRX(Opcode, Reg0, Reg1, MCOperand::createReg(Reg2), IDLoc, + Instructions); +} + +void emitRRI(unsigned Opcode, unsigned Reg0, unsigned Reg1, int16_t Imm, + SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { + emitRRX(Opcode, Reg0, Reg1, MCOperand::createImm(Imm), IDLoc, + Instructions); +} + +void emitAppropriateDSLL(unsigned DstReg, unsigned SrcReg, int16_t ShiftAmount, + SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { + if (ShiftAmount >= 32) { + emitRRI(Mips::DSLL32, DstReg, SrcReg, ShiftAmount - 32, IDLoc, + Instructions); + return; + } + + emitRRI(Mips::DSLL, DstReg, SrcReg, ShiftAmount, IDLoc, Instructions); +} +} // end anonymous namespace. + +bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode()); + bool ExpandedJalSym = false; + + Inst.setLoc(IDLoc); + + if (MCID.isBranch() || MCID.isCall()) { + const unsigned Opcode = Inst.getOpcode(); + MCOperand Offset; + + switch (Opcode) { + default: + break; + case Mips::BBIT0: + case Mips::BBIT032: + case Mips::BBIT1: + case Mips::BBIT132: + assert(hasCnMips() && "instruction only valid for octeon cpus"); + // Fall through + + case Mips::BEQ: + case Mips::BNE: + case Mips::BEQ_MM: + case Mips::BNE_MM: + assert(MCID.getNumOperands() == 3 && "unexpected number of operands"); + Offset = Inst.getOperand(2); + if (!Offset.isImm()) + break; // We'll deal with this situation later on when applying fixups. + if (!isIntN(inMicroMipsMode() ? 17 : 18, Offset.getImm())) + return Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), + 1LL << (inMicroMipsMode() ? 1 : 2))) + return Error(IDLoc, "branch to misaligned address"); + break; + case Mips::BGEZ: + case Mips::BGTZ: + case Mips::BLEZ: + case Mips::BLTZ: + case Mips::BGEZAL: + case Mips::BLTZAL: + case Mips::BC1F: + case Mips::BC1T: + case Mips::BGEZ_MM: + case Mips::BGTZ_MM: + case Mips::BLEZ_MM: + case Mips::BLTZ_MM: + case Mips::BGEZAL_MM: + case Mips::BLTZAL_MM: + case Mips::BC1F_MM: + case Mips::BC1T_MM: + assert(MCID.getNumOperands() == 2 && "unexpected number of operands"); + Offset = Inst.getOperand(1); + if (!Offset.isImm()) + break; // We'll deal with this situation later on when applying fixups. + if (!isIntN(inMicroMipsMode() ? 17 : 18, Offset.getImm())) + return Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), + 1LL << (inMicroMipsMode() ? 1 : 2))) + return Error(IDLoc, "branch to misaligned address"); + break; + case Mips::BEQZ16_MM: + case Mips::BEQZC16_MMR6: + case Mips::BNEZ16_MM: + case Mips::BNEZC16_MMR6: + 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 (!isInt<8>(Offset.getImm())) + return Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), 2LL)) + return Error(IDLoc, "branch to misaligned address"); + break; + } + } + + // SSNOP is deprecated on MIPS32r6/MIPS64r6 + // We still accept it but it is a normal nop. + if (hasMips32r6() && Inst.getOpcode() == Mips::SSNOP) { + std::string ISA = hasMips64r6() ? "MIPS64r6" : "MIPS32r6"; + Warning(IDLoc, "ssnop is deprecated for " + ISA + " and is equivalent to a " + "nop instruction"); + } + + if (hasCnMips()) { + const unsigned Opcode = Inst.getOpcode(); + MCOperand Opnd; + int Imm; + + switch (Opcode) { + default: + break; + + case Mips::BBIT0: + case Mips::BBIT032: + case Mips::BBIT1: + case Mips::BBIT132: + assert(MCID.getNumOperands() == 3 && "unexpected number of operands"); + // The offset is handled above + Opnd = Inst.getOperand(1); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + Imm = Opnd.getImm(); + if (Imm < 0 || Imm > (Opcode == Mips::BBIT0 || + Opcode == Mips::BBIT1 ? 63 : 31)) + return Error(IDLoc, "immediate operand value out of range"); + if (Imm > 31) { + Inst.setOpcode(Opcode == Mips::BBIT0 ? Mips::BBIT032 + : Mips::BBIT132); + Inst.getOperand(1).setImm(Imm - 32); + } + break; + + case Mips::SEQi: + case Mips::SNEi: + assert(MCID.getNumOperands() == 3 && "unexpected number of operands"); + Opnd = Inst.getOperand(2); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + Imm = Opnd.getImm(); + if (!isInt<10>(Imm)) + return Error(IDLoc, "immediate operand value out of range"); + break; + } + } + + // This expansion is not in a function called by tryExpandInstruction() + // because the pseudo-instruction doesn't have a distinct opcode. + if ((Inst.getOpcode() == Mips::JAL || Inst.getOpcode() == Mips::JAL_MM) && + inPicMode()) { + warnIfNoMacro(IDLoc); + + const MCExpr *JalExpr = Inst.getOperand(0).getExpr(); + + // We can do this expansion if there's only 1 symbol in the argument + // expression. + if (countMCSymbolRefExpr(JalExpr) > 1) + return Error(IDLoc, "jal doesn't support multiple symbols in PIC mode"); + + // FIXME: This is checking the expression can be handled by the later stages + // of the assembler. We ought to leave it to those later stages but + // we can't do that until we stop evaluateRelocExpr() rewriting the + // expressions into non-equivalent forms. + const MCSymbol *JalSym = getSingleMCSymbol(JalExpr); + + // FIXME: Add support for label+offset operands (currently causes an error). + // FIXME: Add support for forward-declared local symbols. + // FIXME: Add expansion for when the LargeGOT option is enabled. + if (JalSym->isInSection() || JalSym->isTemporary()) { + if (isABI_O32()) { + // If it's a local symbol and the O32 ABI is being used, we expand to: + // lw $25, 0($gp) + // R_(MICRO)MIPS_GOT16 label + // addiu $25, $25, 0 + // R_(MICRO)MIPS_LO16 label + // jalr $25 + const MCExpr *Got16RelocExpr = evaluateRelocExpr(JalExpr, "got"); + const MCExpr *Lo16RelocExpr = evaluateRelocExpr(JalExpr, "lo"); + + emitRRX(Mips::LW, Mips::T9, Mips::GP, + MCOperand::createExpr(Got16RelocExpr), IDLoc, Instructions); + emitRRX(Mips::ADDiu, Mips::T9, Mips::T9, + MCOperand::createExpr(Lo16RelocExpr), IDLoc, Instructions); + } else if (isABI_N32() || isABI_N64()) { + // If it's a local symbol and the N32/N64 ABIs are being used, + // we expand to: + // lw/ld $25, 0($gp) + // R_(MICRO)MIPS_GOT_DISP label + // jalr $25 + const MCExpr *GotDispRelocExpr = evaluateRelocExpr(JalExpr, "got_disp"); + + emitRRX(ABI.ArePtrs64bit() ? Mips::LD : Mips::LW, Mips::T9, Mips::GP, + MCOperand::createExpr(GotDispRelocExpr), IDLoc, Instructions); + } + } else { + // If it's an external/weak symbol, we expand to: + // lw/ld $25, 0($gp) + // R_(MICRO)MIPS_CALL16 label + // jalr $25 + const MCExpr *Call16RelocExpr = evaluateRelocExpr(JalExpr, "call16"); + + emitRRX(ABI.ArePtrs64bit() ? Mips::LD : Mips::LW, Mips::T9, Mips::GP, + MCOperand::createExpr(Call16RelocExpr), IDLoc, Instructions); + } + + MCInst JalrInst; + if (IsCpRestoreSet && inMicroMipsMode()) + JalrInst.setOpcode(Mips::JALRS_MM); + else + JalrInst.setOpcode(inMicroMipsMode() ? Mips::JALR_MM : Mips::JALR); + JalrInst.addOperand(MCOperand::createReg(Mips::RA)); + JalrInst.addOperand(MCOperand::createReg(Mips::T9)); + + // FIXME: Add an R_(MICRO)MIPS_JALR relocation after the JALR. + // This relocation is supposed to be an optimization hint for the linker + // and is not necessary for correctness. + + Inst = JalrInst; + ExpandedJalSym = true; + } + + if (MCID.mayLoad() || MCID.mayStore()) { + // Check the offset of memory operand, if it is a symbol + // reference or immediate we may have to expand instructions. + for (unsigned i = 0; i < MCID.getNumOperands(); i++) { + const MCOperandInfo &OpInfo = MCID.OpInfo[i]; + if ((OpInfo.OperandType == MCOI::OPERAND_MEMORY) || + (OpInfo.OperandType == MCOI::OPERAND_UNKNOWN)) { + MCOperand &Op = Inst.getOperand(i); + if (Op.isImm()) { + int MemOffset = Op.getImm(); + if (MemOffset < -32768 || MemOffset > 32767) { + // Offset can't exceed 16bit value. + expandMemInst(Inst, IDLoc, Instructions, MCID.mayLoad(), true); + return false; + } + } else if (Op.isExpr()) { + const MCExpr *Expr = Op.getExpr(); + if (Expr->getKind() == MCExpr::SymbolRef) { + const MCSymbolRefExpr *SR = + static_cast<const MCSymbolRefExpr *>(Expr); + if (SR->getKind() == MCSymbolRefExpr::VK_None) { + // Expand symbol. + expandMemInst(Inst, IDLoc, Instructions, MCID.mayLoad(), false); + return false; + } + } else if (!isEvaluated(Expr)) { + expandMemInst(Inst, IDLoc, Instructions, MCID.mayLoad(), false); + return false; + } + } + } + } // for + } // if load/store + + if (inMicroMipsMode()) { + if (MCID.mayLoad()) { + // Try to create 16-bit GP relative load instruction. + for (unsigned i = 0; i < MCID.getNumOperands(); i++) { + const MCOperandInfo &OpInfo = MCID.OpInfo[i]; + if ((OpInfo.OperandType == MCOI::OPERAND_MEMORY) || + (OpInfo.OperandType == MCOI::OPERAND_UNKNOWN)) { + MCOperand &Op = Inst.getOperand(i); + if (Op.isImm()) { + int MemOffset = Op.getImm(); + MCOperand &DstReg = Inst.getOperand(0); + MCOperand &BaseReg = Inst.getOperand(1); + if (isInt<9>(MemOffset) && (MemOffset % 4 == 0) && + getContext().getRegisterInfo()->getRegClass( + Mips::GPRMM16RegClassID).contains(DstReg.getReg()) && + (BaseReg.getReg() == Mips::GP || + BaseReg.getReg() == Mips::GP_64)) { + + emitRRI(Mips::LWGP_MM, DstReg.getReg(), Mips::GP, MemOffset, + IDLoc, Instructions); + return false; + } + } + } + } // for + } // if load + + // TODO: Handle this with the AsmOperandClass.PredicateMethod. + + MCOperand Opnd; + int Imm; + + switch (Inst.getOpcode()) { + default: + break; + case Mips::ADDIUS5_MM: + Opnd = Inst.getOperand(2); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + Imm = Opnd.getImm(); + if (Imm < -8 || Imm > 7) + return Error(IDLoc, "immediate operand value out of range"); + break; + case Mips::ADDIUSP_MM: + Opnd = Inst.getOperand(0); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + Imm = Opnd.getImm(); + if (Imm < -1032 || Imm > 1028 || (Imm < 8 && Imm > -12) || + Imm % 4 != 0) + return Error(IDLoc, "immediate operand value out of range"); + break; + case Mips::SLL16_MM: + case Mips::SRL16_MM: + Opnd = Inst.getOperand(2); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + Imm = Opnd.getImm(); + if (Imm < 1 || Imm > 8) + return Error(IDLoc, "immediate operand value out of range"); + break; + case Mips::LI16_MM: + Opnd = Inst.getOperand(1); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + Imm = Opnd.getImm(); + if (Imm < -1 || Imm > 126) + return Error(IDLoc, "immediate operand value out of range"); + break; + case Mips::ADDIUR2_MM: + Opnd = Inst.getOperand(2); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + Imm = Opnd.getImm(); + if (!(Imm == 1 || Imm == -1 || + ((Imm % 4 == 0) && Imm < 28 && Imm > 0))) + return Error(IDLoc, "immediate operand value out of range"); + break; + case Mips::ADDIUR1SP_MM: + Opnd = Inst.getOperand(1); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + Imm = Opnd.getImm(); + if (OffsetToAlignment(Imm, 4LL)) + return Error(IDLoc, "misaligned immediate operand value"); + if (Imm < 0 || Imm > 255) + return Error(IDLoc, "immediate operand value out of range"); + break; + case Mips::ANDI16_MM: + Opnd = Inst.getOperand(2); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + Imm = Opnd.getImm(); + if (!(Imm == 128 || (Imm >= 1 && Imm <= 4) || Imm == 7 || Imm == 8 || + Imm == 15 || Imm == 16 || Imm == 31 || Imm == 32 || Imm == 63 || + Imm == 64 || Imm == 255 || Imm == 32768 || Imm == 65535)) + return Error(IDLoc, "immediate operand value out of range"); + break; + case Mips::LBU16_MM: + Opnd = Inst.getOperand(2); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + Imm = Opnd.getImm(); + if (Imm < -1 || Imm > 14) + return Error(IDLoc, "immediate operand value out of range"); + break; + case Mips::TEQ_MM: + case Mips::TGE_MM: + case Mips::TGEU_MM: + case Mips::TLT_MM: + case Mips::TLTU_MM: + case Mips::TNE_MM: + case Mips::SB16_MM: + case Mips::SB16_MMR6: + Opnd = Inst.getOperand(2); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + Imm = Opnd.getImm(); + if (Imm < 0 || Imm > 15) + return Error(IDLoc, "immediate operand value out of range"); + break; + case Mips::LHU16_MM: + case Mips::SH16_MM: + case Mips::SH16_MMR6: + Opnd = Inst.getOperand(2); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + Imm = Opnd.getImm(); + if (Imm < 0 || Imm > 30 || (Imm % 2 != 0)) + return Error(IDLoc, "immediate operand value out of range"); + break; + case Mips::LW16_MM: + case Mips::SW16_MM: + case Mips::SW16_MMR6: + Opnd = Inst.getOperand(2); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + Imm = Opnd.getImm(); + if (Imm < 0 || Imm > 60 || (Imm % 4 != 0)) + return Error(IDLoc, "immediate operand value out of range"); + break; + case Mips::ADDIUPC_MM: + MCOperand Opnd = Inst.getOperand(1); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + int Imm = Opnd.getImm(); + if ((Imm % 4 != 0) || !isInt<25>(Imm)) + return Error(IDLoc, "immediate operand value out of range"); + break; + } + } + + MacroExpanderResultTy ExpandResult = + tryExpandInstruction(Inst, IDLoc, Instructions); + switch (ExpandResult) { + case MER_NotAMacro: + Instructions.push_back(Inst); + break; + case MER_Success: + break; + case MER_Fail: + return true; + } + + // If this instruction has a delay slot and .set reorder is active, + // emit a NOP after it. + if (MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder()) + createNop(hasShortDelaySlot(Inst.getOpcode()), IDLoc, Instructions); + + if ((Inst.getOpcode() == Mips::JalOneReg || + Inst.getOpcode() == Mips::JalTwoReg || ExpandedJalSym) && + isPicAndNotNxxAbi()) { + if (IsCpRestoreSet) { + // We need a NOP between the JALR and the LW: + // If .set reorder has been used, we've already emitted a NOP. + // If .set noreorder has been used, we need to emit a NOP at this point. + if (!AssemblerOptions.back()->isReorder()) + createNop(hasShortDelaySlot(Inst.getOpcode()), IDLoc, Instructions); + + // Load the $gp from the stack. + SmallVector<MCInst, 3> LoadInsts; + createCpRestoreMemOp(true /*IsLoad*/, CpRestoreOffset /*StackOffset*/, + IDLoc, LoadInsts); + + for (const MCInst &Inst : LoadInsts) + Instructions.push_back(Inst); + + } else + Warning(IDLoc, "no .cprestore used in PIC mode"); + } + + return false; +} + +MipsAsmParser::MacroExpanderResultTy +MipsAsmParser::tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + switch (Inst.getOpcode()) { + default: + return MER_NotAMacro; + case Mips::LoadImm32: + return expandLoadImm(Inst, true, IDLoc, Instructions) ? MER_Fail + : MER_Success; + case Mips::LoadImm64: + return expandLoadImm(Inst, false, IDLoc, Instructions) ? MER_Fail + : MER_Success; + case Mips::LoadAddrImm32: + case Mips::LoadAddrImm64: + assert(Inst.getOperand(0).isReg() && "expected register operand kind"); + assert((Inst.getOperand(1).isImm() || Inst.getOperand(1).isExpr()) && + "expected immediate operand kind"); + + return expandLoadAddress(Inst.getOperand(0).getReg(), Mips::NoRegister, + Inst.getOperand(1), + Inst.getOpcode() == Mips::LoadAddrImm32, IDLoc, + Instructions) + ? MER_Fail + : MER_Success; + case Mips::LoadAddrReg32: + case Mips::LoadAddrReg64: + assert(Inst.getOperand(0).isReg() && "expected register operand kind"); + assert(Inst.getOperand(1).isReg() && "expected register operand kind"); + assert((Inst.getOperand(2).isImm() || Inst.getOperand(2).isExpr()) && + "expected immediate operand kind"); + + return expandLoadAddress(Inst.getOperand(0).getReg(), + Inst.getOperand(1).getReg(), Inst.getOperand(2), + Inst.getOpcode() == Mips::LoadAddrReg32, IDLoc, + Instructions) + ? MER_Fail + : MER_Success; + case Mips::B_MM_Pseudo: + case Mips::B_MMR6_Pseudo: + return expandUncondBranchMMPseudo(Inst, IDLoc, Instructions) ? MER_Fail + : MER_Success; + case Mips::SWM_MM: + case Mips::LWM_MM: + return expandLoadStoreMultiple(Inst, IDLoc, Instructions) ? MER_Fail + : MER_Success; + case Mips::JalOneReg: + case Mips::JalTwoReg: + return expandJalWithRegs(Inst, IDLoc, Instructions) ? MER_Fail + : MER_Success; + case Mips::BneImm: + case Mips::BeqImm: + return expandBranchImm(Inst, IDLoc, Instructions) ? MER_Fail : MER_Success; + case Mips::BLT: + case Mips::BLE: + case Mips::BGE: + case Mips::BGT: + case Mips::BLTU: + case Mips::BLEU: + case Mips::BGEU: + case Mips::BGTU: + case Mips::BLTL: + case Mips::BLEL: + case Mips::BGEL: + case Mips::BGTL: + case Mips::BLTUL: + case Mips::BLEUL: + case Mips::BGEUL: + case Mips::BGTUL: + case Mips::BLTImmMacro: + case Mips::BLEImmMacro: + case Mips::BGEImmMacro: + case Mips::BGTImmMacro: + case Mips::BLTUImmMacro: + case Mips::BLEUImmMacro: + case Mips::BGEUImmMacro: + case Mips::BGTUImmMacro: + case Mips::BLTLImmMacro: + case Mips::BLELImmMacro: + case Mips::BGELImmMacro: + case Mips::BGTLImmMacro: + case Mips::BLTULImmMacro: + case Mips::BLEULImmMacro: + case Mips::BGEULImmMacro: + case Mips::BGTULImmMacro: + return expandCondBranches(Inst, IDLoc, Instructions) ? MER_Fail + : MER_Success; + case Mips::SDivMacro: + return expandDiv(Inst, IDLoc, Instructions, false, true) ? MER_Fail + : MER_Success; + case Mips::DSDivMacro: + return expandDiv(Inst, IDLoc, Instructions, true, true) ? MER_Fail + : MER_Success; + case Mips::UDivMacro: + return expandDiv(Inst, IDLoc, Instructions, false, false) ? MER_Fail + : MER_Success; + case Mips::DUDivMacro: + return expandDiv(Inst, IDLoc, Instructions, true, false) ? MER_Fail + : MER_Success; + case Mips::Ulh: + return expandUlh(Inst, true, IDLoc, Instructions) ? MER_Fail : MER_Success; + case Mips::Ulhu: + return expandUlh(Inst, false, IDLoc, Instructions) ? MER_Fail : MER_Success; + case Mips::Ulw: + return expandUlw(Inst, IDLoc, Instructions) ? MER_Fail : MER_Success; + case Mips::NORImm: + return expandAliasImmediate(Inst, IDLoc, Instructions) ? MER_Fail + : MER_Success; + case Mips::ADDi: + case Mips::ADDiu: + case Mips::SLTi: + case Mips::SLTiu: + if ((Inst.getNumOperands() == 3) && Inst.getOperand(0).isReg() && + Inst.getOperand(1).isReg() && Inst.getOperand(2).isImm()) { + int64_t ImmValue = Inst.getOperand(2).getImm(); + if (isInt<16>(ImmValue)) + return MER_NotAMacro; + return expandAliasImmediate(Inst, IDLoc, Instructions) ? MER_Fail + : MER_Success; + } + return MER_NotAMacro; + case Mips::ANDi: + case Mips::ORi: + case Mips::XORi: + if ((Inst.getNumOperands() == 3) && Inst.getOperand(0).isReg() && + Inst.getOperand(1).isReg() && Inst.getOperand(2).isImm()) { + int64_t ImmValue = Inst.getOperand(2).getImm(); + if (isUInt<16>(ImmValue)) + return MER_NotAMacro; + return expandAliasImmediate(Inst, IDLoc, Instructions) ? MER_Fail + : MER_Success; + } + return MER_NotAMacro; + case Mips::ROL: + case Mips::ROR: + return expandRotation(Inst, IDLoc, Instructions) ? MER_Fail + : MER_Success; + case Mips::ROLImm: + case Mips::RORImm: + return expandRotationImm(Inst, IDLoc, Instructions) ? MER_Fail + : MER_Success; + case Mips::DROL: + case Mips::DROR: + return expandDRotation(Inst, IDLoc, Instructions) ? MER_Fail + : MER_Success; + case Mips::DROLImm: + case Mips::DRORImm: + return expandDRotationImm(Inst, IDLoc, Instructions) ? MER_Fail + : MER_Success; + } +} + +bool MipsAsmParser::expandJalWithRegs(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + // Create a JALR instruction which is going to replace the pseudo-JAL. + MCInst JalrInst; + JalrInst.setLoc(IDLoc); + const MCOperand FirstRegOp = Inst.getOperand(0); + const unsigned Opcode = Inst.getOpcode(); + + if (Opcode == Mips::JalOneReg) { + // jal $rs => jalr $rs + if (IsCpRestoreSet && inMicroMipsMode()) { + JalrInst.setOpcode(Mips::JALRS16_MM); + JalrInst.addOperand(FirstRegOp); + } else if (inMicroMipsMode()) { + JalrInst.setOpcode(hasMips32r6() ? Mips::JALRC16_MMR6 : Mips::JALR16_MM); + JalrInst.addOperand(FirstRegOp); + } else { + JalrInst.setOpcode(Mips::JALR); + JalrInst.addOperand(MCOperand::createReg(Mips::RA)); + JalrInst.addOperand(FirstRegOp); + } + } else if (Opcode == Mips::JalTwoReg) { + // jal $rd, $rs => jalr $rd, $rs + if (IsCpRestoreSet && inMicroMipsMode()) + JalrInst.setOpcode(Mips::JALRS_MM); + else + JalrInst.setOpcode(inMicroMipsMode() ? Mips::JALR_MM : Mips::JALR); + JalrInst.addOperand(FirstRegOp); + const MCOperand SecondRegOp = Inst.getOperand(1); + JalrInst.addOperand(SecondRegOp); + } + Instructions.push_back(JalrInst); + + // If .set reorder is active and branch instruction has a delay slot, + // emit a NOP after it. + const MCInstrDesc &MCID = getInstDesc(JalrInst.getOpcode()); + if (MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder()) { + createNop(hasShortDelaySlot(JalrInst.getOpcode()), IDLoc, Instructions); + } + + return false; +} + +/// Can the value be represented by a unsigned N-bit value and a shift left? +template <unsigned N> static bool isShiftedUIntAtAnyPosition(uint64_t x) { + unsigned BitNum = findFirstSet(x); + + return (x == x >> BitNum << BitNum) && isUInt<N>(x >> BitNum); +} + +/// Load (or add) an immediate into a register. +/// +/// @param ImmValue The immediate to load. +/// @param DstReg The register that will hold the immediate. +/// @param SrcReg A register to add to the immediate or Mips::NoRegister +/// for a simple initialization. +/// @param Is32BitImm Is ImmValue 32-bit or 64-bit? +/// @param IsAddress True if the immediate represents an address. False if it +/// is an integer. +/// @param IDLoc Location of the immediate in the source file. +/// @param Instructions The instructions emitted by this expansion. +bool MipsAsmParser::loadImmediate(int64_t ImmValue, unsigned DstReg, + unsigned SrcReg, bool Is32BitImm, + bool IsAddress, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + if (!Is32BitImm && !isGP64bit()) { + Error(IDLoc, "instruction requires a 64-bit architecture"); + return true; + } + + if (Is32BitImm) { + if (isInt<32>(ImmValue) || isUInt<32>(ImmValue)) { + // Sign extend up to 64-bit so that the predicates match the hardware + // behaviour. In particular, isInt<16>(0xffff8000) and similar should be + // true. + ImmValue = SignExtend64<32>(ImmValue); + } else { + Error(IDLoc, "instruction requires a 32-bit immediate"); + return true; + } + } + + unsigned ZeroReg = IsAddress ? ABI.GetNullPtr() : ABI.GetZeroReg(); + unsigned AdduOp = !Is32BitImm ? Mips::DADDu : Mips::ADDu; + + bool UseSrcReg = false; + if (SrcReg != Mips::NoRegister) + UseSrcReg = true; + + unsigned TmpReg = DstReg; + if (UseSrcReg && (DstReg == SrcReg)) { + // At this point we need AT to perform the expansions and we exit if it is + // not available. + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + TmpReg = ATReg; + } + + if (isInt<16>(ImmValue)) { + if (!UseSrcReg) + SrcReg = ZeroReg; + + // This doesn't quite follow the usual ABI expectations for N32 but matches + // traditional assembler behaviour. N32 would normally use addiu for both + // integers and addresses. + if (IsAddress && !Is32BitImm) { + emitRRI(Mips::DADDiu, DstReg, SrcReg, ImmValue, IDLoc, Instructions); + return false; + } + + emitRRI(Mips::ADDiu, DstReg, SrcReg, ImmValue, IDLoc, Instructions); + return false; + } + + if (isUInt<16>(ImmValue)) { + unsigned TmpReg = DstReg; + if (SrcReg == DstReg) { + TmpReg = getATReg(IDLoc); + if (!TmpReg) + return true; + } + + emitRRI(Mips::ORi, TmpReg, ZeroReg, ImmValue, IDLoc, Instructions); + if (UseSrcReg) + emitRRR(ABI.GetPtrAdduOp(), DstReg, TmpReg, SrcReg, IDLoc, Instructions); + return false; + } + + if (isInt<32>(ImmValue) || isUInt<32>(ImmValue)) { + warnIfNoMacro(IDLoc); + + uint16_t Bits31To16 = (ImmValue >> 16) & 0xffff; + uint16_t Bits15To0 = ImmValue & 0xffff; + + if (!Is32BitImm && !isInt<32>(ImmValue)) { + // Traditional behaviour seems to special case this particular value. It's + // not clear why other masks are handled differently. + if (ImmValue == 0xffffffff) { + emitRI(Mips::LUi, TmpReg, 0xffff, IDLoc, Instructions); + emitRRI(Mips::DSRL32, TmpReg, TmpReg, 0, IDLoc, Instructions); + if (UseSrcReg) + emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, Instructions); + return false; + } + + // Expand to an ORi instead of a LUi to avoid sign-extending into the + // upper 32 bits. + emitRRI(Mips::ORi, TmpReg, ZeroReg, Bits31To16, IDLoc, Instructions); + emitRRI(Mips::DSLL, TmpReg, TmpReg, 16, IDLoc, Instructions); + if (Bits15To0) + emitRRI(Mips::ORi, TmpReg, TmpReg, Bits15To0, IDLoc, Instructions); + if (UseSrcReg) + emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, Instructions); + return false; + } + + emitRI(Mips::LUi, TmpReg, Bits31To16, IDLoc, Instructions); + if (Bits15To0) + emitRRI(Mips::ORi, TmpReg, TmpReg, Bits15To0, IDLoc, Instructions); + if (UseSrcReg) + emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, Instructions); + return false; + } + + if (isShiftedUIntAtAnyPosition<16>(ImmValue)) { + if (Is32BitImm) { + Error(IDLoc, "instruction requires a 32-bit immediate"); + return true; + } + + // Traditionally, these immediates are shifted as little as possible and as + // such we align the most significant bit to bit 15 of our temporary. + unsigned FirstSet = findFirstSet((uint64_t)ImmValue); + unsigned LastSet = findLastSet((uint64_t)ImmValue); + unsigned ShiftAmount = FirstSet - (15 - (LastSet - FirstSet)); + uint16_t Bits = (ImmValue >> ShiftAmount) & 0xffff; + emitRRI(Mips::ORi, TmpReg, ZeroReg, Bits, IDLoc, Instructions); + emitRRI(Mips::DSLL, TmpReg, TmpReg, ShiftAmount, IDLoc, Instructions); + + if (UseSrcReg) + emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, Instructions); + + return false; + } + + warnIfNoMacro(IDLoc); + + // The remaining case is packed with a sequence of dsll and ori with zeros + // being omitted and any neighbouring dsll's being coalesced. + // The highest 32-bit's are equivalent to a 32-bit immediate load. + + // Load bits 32-63 of ImmValue into bits 0-31 of the temporary register. + if (loadImmediate(ImmValue >> 32, TmpReg, Mips::NoRegister, true, false, + IDLoc, Instructions)) + return false; + + // Shift and accumulate into the register. If a 16-bit chunk is zero, then + // skip it and defer the shift to the next chunk. + unsigned ShiftCarriedForwards = 16; + for (int BitNum = 16; BitNum >= 0; BitNum -= 16) { + uint16_t ImmChunk = (ImmValue >> BitNum) & 0xffff; + + if (ImmChunk != 0) { + emitAppropriateDSLL(TmpReg, TmpReg, ShiftCarriedForwards, IDLoc, + Instructions); + emitRRI(Mips::ORi, TmpReg, TmpReg, ImmChunk, IDLoc, Instructions); + ShiftCarriedForwards = 0; + } + + ShiftCarriedForwards += 16; + } + ShiftCarriedForwards -= 16; + + // Finish any remaining shifts left by trailing zeros. + if (ShiftCarriedForwards) + emitAppropriateDSLL(TmpReg, TmpReg, ShiftCarriedForwards, IDLoc, + Instructions); + + if (UseSrcReg) + emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, Instructions); + + return false; +} + +bool MipsAsmParser::expandLoadImm(MCInst &Inst, bool Is32BitImm, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + const MCOperand &ImmOp = Inst.getOperand(1); + assert(ImmOp.isImm() && "expected immediate operand kind"); + const MCOperand &DstRegOp = Inst.getOperand(0); + assert(DstRegOp.isReg() && "expected register operand kind"); + + if (loadImmediate(ImmOp.getImm(), DstRegOp.getReg(), Mips::NoRegister, + Is32BitImm, false, IDLoc, Instructions)) + return true; + + return false; +} + +bool MipsAsmParser::expandLoadAddress(unsigned DstReg, unsigned BaseReg, + const MCOperand &Offset, + bool Is32BitAddress, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + // la can't produce a usable address when addresses are 64-bit. + if (Is32BitAddress && ABI.ArePtrs64bit()) { + // FIXME: Demote this to a warning and continue as if we had 'dla' instead. + // We currently can't do this because we depend on the equality + // operator and N64 can end up with a GPR32/GPR64 mismatch. + Error(IDLoc, "la used to load 64-bit address"); + // Continue as if we had 'dla' instead. + Is32BitAddress = false; + } + + // dla requires 64-bit addresses. + if (!Is32BitAddress && !ABI.ArePtrs64bit()) { + Error(IDLoc, "instruction requires a 64-bit architecture"); + return true; + } + + if (!Offset.isImm()) + return loadAndAddSymbolAddress(Offset.getExpr(), DstReg, BaseReg, + Is32BitAddress, IDLoc, Instructions); + + return loadImmediate(Offset.getImm(), DstReg, BaseReg, Is32BitAddress, true, + IDLoc, Instructions); +} + +bool MipsAsmParser::loadAndAddSymbolAddress( + const MCExpr *SymExpr, unsigned DstReg, unsigned SrcReg, bool Is32BitSym, + SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { + warnIfNoMacro(IDLoc); + + const MCExpr *Symbol = cast<MCExpr>(SymExpr); + const MipsMCExpr *HiExpr = MipsMCExpr::create( + MCSymbolRefExpr::VK_Mips_ABS_HI, Symbol, getContext()); + const MipsMCExpr *LoExpr = MipsMCExpr::create( + MCSymbolRefExpr::VK_Mips_ABS_LO, Symbol, getContext()); + + bool UseSrcReg = SrcReg != Mips::NoRegister; + + // This is the 64-bit symbol address expansion. + if (ABI.ArePtrs64bit() && isGP64bit()) { + // We always need AT for the 64-bit expansion. + // If it is not available we exit. + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + + const MipsMCExpr *HighestExpr = MipsMCExpr::create( + MCSymbolRefExpr::VK_Mips_HIGHEST, Symbol, getContext()); + const MipsMCExpr *HigherExpr = MipsMCExpr::create( + MCSymbolRefExpr::VK_Mips_HIGHER, Symbol, getContext()); + + if (UseSrcReg && (DstReg == SrcReg)) { + // If $rs is the same as $rd: + // (d)la $rd, sym($rd) => lui $at, %highest(sym) + // daddiu $at, $at, %higher(sym) + // dsll $at, $at, 16 + // daddiu $at, $at, %hi(sym) + // dsll $at, $at, 16 + // daddiu $at, $at, %lo(sym) + // daddu $rd, $at, $rd + emitRX(Mips::LUi, ATReg, MCOperand::createExpr(HighestExpr), IDLoc, + Instructions); + emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(HigherExpr), + IDLoc, Instructions); + emitRRI(Mips::DSLL, ATReg, ATReg, 16, IDLoc, Instructions); + emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(HiExpr), IDLoc, + Instructions); + emitRRI(Mips::DSLL, ATReg, ATReg, 16, IDLoc, Instructions); + emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(LoExpr), IDLoc, + Instructions); + emitRRR(Mips::DADDu, DstReg, ATReg, SrcReg, IDLoc, Instructions); + + return false; + } + + // Otherwise, if the $rs is different from $rd or if $rs isn't specified: + // (d)la $rd, sym/sym($rs) => lui $rd, %highest(sym) + // lui $at, %hi(sym) + // daddiu $rd, $rd, %higher(sym) + // daddiu $at, $at, %lo(sym) + // dsll32 $rd, $rd, 0 + // daddu $rd, $rd, $at + // (daddu $rd, $rd, $rs) + emitRX(Mips::LUi, DstReg, MCOperand::createExpr(HighestExpr), IDLoc, + Instructions); + emitRX(Mips::LUi, ATReg, MCOperand::createExpr(HiExpr), IDLoc, + Instructions); + emitRRX(Mips::DADDiu, DstReg, DstReg, MCOperand::createExpr(HigherExpr), + IDLoc, Instructions); + emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(LoExpr), IDLoc, + Instructions); + emitRRI(Mips::DSLL32, DstReg, DstReg, 0, IDLoc, Instructions); + emitRRR(Mips::DADDu, DstReg, DstReg, ATReg, IDLoc, Instructions); + if (UseSrcReg) + emitRRR(Mips::DADDu, DstReg, DstReg, SrcReg, IDLoc, Instructions); + + return false; + } + + // And now, the 32-bit symbol address expansion: + // If $rs is the same as $rd: + // (d)la $rd, sym($rd) => lui $at, %hi(sym) + // ori $at, $at, %lo(sym) + // addu $rd, $at, $rd + // Otherwise, if the $rs is different from $rd or if $rs isn't specified: + // (d)la $rd, sym/sym($rs) => lui $rd, %hi(sym) + // ori $rd, $rd, %lo(sym) + // (addu $rd, $rd, $rs) + unsigned TmpReg = DstReg; + if (UseSrcReg && (DstReg == SrcReg)) { + // If $rs is the same as $rd, we need to use AT. + // If it is not available we exit. + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + TmpReg = ATReg; + } + + emitRX(Mips::LUi, TmpReg, MCOperand::createExpr(HiExpr), IDLoc, Instructions); + emitRRX(Mips::ADDiu, TmpReg, TmpReg, MCOperand::createExpr(LoExpr), IDLoc, + Instructions); + + if (UseSrcReg) + emitRRR(Mips::ADDu, DstReg, TmpReg, SrcReg, IDLoc, Instructions); + else + assert(DstReg == TmpReg); + + return false; +} + +bool MipsAsmParser::expandUncondBranchMMPseudo( + MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { + assert(getInstDesc(Inst.getOpcode()).getNumOperands() == 1 && + "unexpected number of operands"); + + MCOperand Offset = Inst.getOperand(0); + if (Offset.isExpr()) { + Inst.clear(); + Inst.setOpcode(Mips::BEQ_MM); + Inst.addOperand(MCOperand::createReg(Mips::ZERO)); + Inst.addOperand(MCOperand::createReg(Mips::ZERO)); + Inst.addOperand(MCOperand::createExpr(Offset.getExpr())); + } else { + assert(Offset.isImm() && "expected immediate operand kind"); + if (isInt<11>(Offset.getImm())) { + // If offset fits into 11 bits then this instruction becomes microMIPS + // 16-bit unconditional branch instruction. + if (inMicroMipsMode()) + Inst.setOpcode(hasMips32r6() ? Mips::BC16_MMR6 : Mips::B16_MM); + } else { + if (!isInt<17>(Offset.getImm())) + Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), 1LL << 1)) + Error(IDLoc, "branch to misaligned address"); + Inst.clear(); + Inst.setOpcode(Mips::BEQ_MM); + Inst.addOperand(MCOperand::createReg(Mips::ZERO)); + Inst.addOperand(MCOperand::createReg(Mips::ZERO)); + Inst.addOperand(MCOperand::createImm(Offset.getImm())); + } + } + Instructions.push_back(Inst); + + // If .set reorder is active and branch instruction has a delay slot, + // emit a NOP after it. + const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode()); + if (MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder()) + createNop(true, IDLoc, Instructions); + + return false; +} + +bool MipsAsmParser::expandBranchImm(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + const MCOperand &DstRegOp = Inst.getOperand(0); + assert(DstRegOp.isReg() && "expected register operand kind"); + + const MCOperand &ImmOp = Inst.getOperand(1); + assert(ImmOp.isImm() && "expected immediate operand kind"); + + const MCOperand &MemOffsetOp = Inst.getOperand(2); + assert(MemOffsetOp.isImm() && "expected immediate operand kind"); + + unsigned OpCode = 0; + switch(Inst.getOpcode()) { + case Mips::BneImm: + OpCode = Mips::BNE; + break; + case Mips::BeqImm: + OpCode = Mips::BEQ; + break; + default: + llvm_unreachable("Unknown immediate branch pseudo-instruction."); + break; + } + + int64_t ImmValue = ImmOp.getImm(); + if (ImmValue == 0) + emitRRX(OpCode, DstRegOp.getReg(), Mips::ZERO, MemOffsetOp, IDLoc, + Instructions); + else { + warnIfNoMacro(IDLoc); + + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + + if (loadImmediate(ImmValue, ATReg, Mips::NoRegister, !isGP64bit(), true, + IDLoc, Instructions)) + return true; + + emitRRX(OpCode, DstRegOp.getReg(), ATReg, MemOffsetOp, IDLoc, Instructions); + } + return false; +} + +void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions, + bool isLoad, bool isImmOpnd) { + unsigned ImmOffset, HiOffset, LoOffset; + const MCExpr *ExprOffset; + unsigned TmpRegNum; + // 1st operand is either the source or destination register. + assert(Inst.getOperand(0).isReg() && "expected register operand kind"); + unsigned RegOpNum = Inst.getOperand(0).getReg(); + // 2nd operand is the base register. + assert(Inst.getOperand(1).isReg() && "expected register operand kind"); + unsigned BaseRegNum = Inst.getOperand(1).getReg(); + // 3rd operand is either an immediate or expression. + if (isImmOpnd) { + assert(Inst.getOperand(2).isImm() && "expected immediate operand kind"); + ImmOffset = Inst.getOperand(2).getImm(); + LoOffset = ImmOffset & 0x0000ffff; + HiOffset = (ImmOffset & 0xffff0000) >> 16; + // If msb of LoOffset is 1(negative number) we must increment HiOffset. + if (LoOffset & 0x8000) + HiOffset++; + } else + ExprOffset = Inst.getOperand(2).getExpr(); + // These are some of the types of expansions we perform here: + // 1) lw $8, sym => lui $8, %hi(sym) + // lw $8, %lo(sym)($8) + // 2) lw $8, offset($9) => lui $8, %hi(offset) + // add $8, $8, $9 + // lw $8, %lo(offset)($9) + // 3) lw $8, offset($8) => lui $at, %hi(offset) + // add $at, $at, $8 + // lw $8, %lo(offset)($at) + // 4) sw $8, sym => lui $at, %hi(sym) + // sw $8, %lo(sym)($at) + // 5) sw $8, offset($8) => lui $at, %hi(offset) + // add $at, $at, $8 + // sw $8, %lo(offset)($at) + // 6) ldc1 $f0, sym => lui $at, %hi(sym) + // ldc1 $f0, %lo(sym)($at) + // + // For load instructions we can use the destination register as a temporary + // if base and dst are different (examples 1 and 2) and if the base register + // is general purpose otherwise we must use $at (example 6) and error if it's + // not available. For stores we must use $at (examples 4 and 5) because we + // must not clobber the source register setting up the offset. + const MCInstrDesc &Desc = getInstDesc(Inst.getOpcode()); + int16_t RegClassOp0 = Desc.OpInfo[0].RegClass; + unsigned RegClassIDOp0 = + getContext().getRegisterInfo()->getRegClass(RegClassOp0).getID(); + bool IsGPR = (RegClassIDOp0 == Mips::GPR32RegClassID) || + (RegClassIDOp0 == Mips::GPR64RegClassID); + if (isLoad && IsGPR && (BaseRegNum != RegOpNum)) + TmpRegNum = RegOpNum; + else { + // At this point we need AT to perform the expansions and we exit if it is + // not available. + TmpRegNum = getATReg(IDLoc); + if (!TmpRegNum) + return; + } + + emitRX(Mips::LUi, TmpRegNum, + isImmOpnd ? MCOperand::createImm(HiOffset) + : MCOperand::createExpr(evaluateRelocExpr(ExprOffset, "hi")), + IDLoc, Instructions); + // Add temp register to base. + if (BaseRegNum != Mips::ZERO) + emitRRR(Mips::ADDu, TmpRegNum, TmpRegNum, BaseRegNum, IDLoc, Instructions); + // And finally, create original instruction with low part + // of offset and new base. + emitRRX(Inst.getOpcode(), RegOpNum, TmpRegNum, + isImmOpnd + ? MCOperand::createImm(LoOffset) + : MCOperand::createExpr(evaluateRelocExpr(ExprOffset, "lo")), + IDLoc, Instructions); +} + +bool +MipsAsmParser::expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + unsigned OpNum = Inst.getNumOperands(); + unsigned Opcode = Inst.getOpcode(); + unsigned NewOpcode = Opcode == Mips::SWM_MM ? Mips::SWM32_MM : Mips::LWM32_MM; + + assert (Inst.getOperand(OpNum - 1).isImm() && + Inst.getOperand(OpNum - 2).isReg() && + Inst.getOperand(OpNum - 3).isReg() && "Invalid instruction operand."); + + if (OpNum < 8 && Inst.getOperand(OpNum - 1).getImm() <= 60 && + Inst.getOperand(OpNum - 1).getImm() >= 0 && + (Inst.getOperand(OpNum - 2).getReg() == Mips::SP || + Inst.getOperand(OpNum - 2).getReg() == Mips::SP_64) && + (Inst.getOperand(OpNum - 3).getReg() == Mips::RA || + Inst.getOperand(OpNum - 3).getReg() == Mips::RA_64)) { + // It can be implemented as SWM16 or LWM16 instruction. + if (inMicroMipsMode() && hasMips32r6()) + NewOpcode = Opcode == Mips::SWM_MM ? Mips::SWM16_MMR6 : Mips::LWM16_MMR6; + else + NewOpcode = Opcode == Mips::SWM_MM ? Mips::SWM16_MM : Mips::LWM16_MM; + } + + Inst.setOpcode(NewOpcode); + Instructions.push_back(Inst); + return false; +} + +bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + bool EmittedNoMacroWarning = false; + unsigned PseudoOpcode = Inst.getOpcode(); + unsigned SrcReg = Inst.getOperand(0).getReg(); + const MCOperand &TrgOp = Inst.getOperand(1); + const MCExpr *OffsetExpr = Inst.getOperand(2).getExpr(); + + unsigned ZeroSrcOpcode, ZeroTrgOpcode; + bool ReverseOrderSLT, IsUnsigned, IsLikely, AcceptsEquality; + + unsigned TrgReg; + if (TrgOp.isReg()) + TrgReg = TrgOp.getReg(); + else if (TrgOp.isImm()) { + warnIfNoMacro(IDLoc); + EmittedNoMacroWarning = true; + + TrgReg = getATReg(IDLoc); + if (!TrgReg) + return true; + + switch(PseudoOpcode) { + default: + llvm_unreachable("unknown opcode for branch pseudo-instruction"); + case Mips::BLTImmMacro: + PseudoOpcode = Mips::BLT; + break; + case Mips::BLEImmMacro: + PseudoOpcode = Mips::BLE; + break; + case Mips::BGEImmMacro: + PseudoOpcode = Mips::BGE; + break; + case Mips::BGTImmMacro: + PseudoOpcode = Mips::BGT; + break; + case Mips::BLTUImmMacro: + PseudoOpcode = Mips::BLTU; + break; + case Mips::BLEUImmMacro: + PseudoOpcode = Mips::BLEU; + break; + case Mips::BGEUImmMacro: + PseudoOpcode = Mips::BGEU; + break; + case Mips::BGTUImmMacro: + PseudoOpcode = Mips::BGTU; + break; + case Mips::BLTLImmMacro: + PseudoOpcode = Mips::BLTL; + break; + case Mips::BLELImmMacro: + PseudoOpcode = Mips::BLEL; + break; + case Mips::BGELImmMacro: + PseudoOpcode = Mips::BGEL; + break; + case Mips::BGTLImmMacro: + PseudoOpcode = Mips::BGTL; + break; + case Mips::BLTULImmMacro: + PseudoOpcode = Mips::BLTUL; + break; + case Mips::BLEULImmMacro: + PseudoOpcode = Mips::BLEUL; + break; + case Mips::BGEULImmMacro: + PseudoOpcode = Mips::BGEUL; + break; + case Mips::BGTULImmMacro: + PseudoOpcode = Mips::BGTUL; + break; + } + + if (loadImmediate(TrgOp.getImm(), TrgReg, Mips::NoRegister, !isGP64bit(), + false, IDLoc, Instructions)) + return true; + } + + switch (PseudoOpcode) { + case Mips::BLT: + case Mips::BLTU: + case Mips::BLTL: + case Mips::BLTUL: + AcceptsEquality = false; + ReverseOrderSLT = false; + IsUnsigned = ((PseudoOpcode == Mips::BLTU) || (PseudoOpcode == Mips::BLTUL)); + IsLikely = ((PseudoOpcode == Mips::BLTL) || (PseudoOpcode == Mips::BLTUL)); + ZeroSrcOpcode = Mips::BGTZ; + ZeroTrgOpcode = Mips::BLTZ; + break; + case Mips::BLE: + case Mips::BLEU: + case Mips::BLEL: + case Mips::BLEUL: + AcceptsEquality = true; + ReverseOrderSLT = true; + IsUnsigned = ((PseudoOpcode == Mips::BLEU) || (PseudoOpcode == Mips::BLEUL)); + IsLikely = ((PseudoOpcode == Mips::BLEL) || (PseudoOpcode == Mips::BLEUL)); + ZeroSrcOpcode = Mips::BGEZ; + ZeroTrgOpcode = Mips::BLEZ; + break; + case Mips::BGE: + case Mips::BGEU: + case Mips::BGEL: + case Mips::BGEUL: + AcceptsEquality = true; + ReverseOrderSLT = false; + IsUnsigned = ((PseudoOpcode == Mips::BGEU) || (PseudoOpcode == Mips::BGEUL)); + IsLikely = ((PseudoOpcode == Mips::BGEL) || (PseudoOpcode == Mips::BGEUL)); + ZeroSrcOpcode = Mips::BLEZ; + ZeroTrgOpcode = Mips::BGEZ; + break; + case Mips::BGT: + case Mips::BGTU: + case Mips::BGTL: + case Mips::BGTUL: + AcceptsEquality = false; + ReverseOrderSLT = true; + IsUnsigned = ((PseudoOpcode == Mips::BGTU) || (PseudoOpcode == Mips::BGTUL)); + IsLikely = ((PseudoOpcode == Mips::BGTL) || (PseudoOpcode == Mips::BGTUL)); + ZeroSrcOpcode = Mips::BLTZ; + ZeroTrgOpcode = Mips::BGTZ; + break; + default: + llvm_unreachable("unknown opcode for branch pseudo-instruction"); + } + + bool IsTrgRegZero = (TrgReg == Mips::ZERO); + bool IsSrcRegZero = (SrcReg == Mips::ZERO); + if (IsSrcRegZero && IsTrgRegZero) { + // FIXME: All of these Opcode-specific if's are needed for compatibility + // with GAS' behaviour. However, they may not generate the most efficient + // code in some circumstances. + if (PseudoOpcode == Mips::BLT) { + emitRX(Mips::BLTZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, + Instructions); + return false; + } + if (PseudoOpcode == Mips::BLE) { + emitRX(Mips::BLEZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, + Instructions); + Warning(IDLoc, "branch is always taken"); + return false; + } + if (PseudoOpcode == Mips::BGE) { + emitRX(Mips::BGEZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, + Instructions); + Warning(IDLoc, "branch is always taken"); + return false; + } + if (PseudoOpcode == Mips::BGT) { + emitRX(Mips::BGTZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, + Instructions); + return false; + } + if (PseudoOpcode == Mips::BGTU) { + emitRRX(Mips::BNE, Mips::ZERO, Mips::ZERO, + MCOperand::createExpr(OffsetExpr), IDLoc, Instructions); + return false; + } + if (AcceptsEquality) { + // If both registers are $0 and the pseudo-branch accepts equality, it + // will always be taken, so we emit an unconditional branch. + emitRRX(Mips::BEQ, Mips::ZERO, Mips::ZERO, + MCOperand::createExpr(OffsetExpr), IDLoc, Instructions); + Warning(IDLoc, "branch is always taken"); + return false; + } + // If both registers are $0 and the pseudo-branch does not accept + // equality, it will never be taken, so we don't have to emit anything. + return false; + } + if (IsSrcRegZero || IsTrgRegZero) { + if ((IsSrcRegZero && PseudoOpcode == Mips::BGTU) || + (IsTrgRegZero && PseudoOpcode == Mips::BLTU)) { + // If the $rs is $0 and the pseudo-branch is BGTU (0 > x) or + // if the $rt is $0 and the pseudo-branch is BLTU (x < 0), + // the pseudo-branch will never be taken, so we don't emit anything. + // This only applies to unsigned pseudo-branches. + return false; + } + if ((IsSrcRegZero && PseudoOpcode == Mips::BLEU) || + (IsTrgRegZero && PseudoOpcode == Mips::BGEU)) { + // If the $rs is $0 and the pseudo-branch is BLEU (0 <= x) or + // if the $rt is $0 and the pseudo-branch is BGEU (x >= 0), + // the pseudo-branch will always be taken, so we emit an unconditional + // branch. + // This only applies to unsigned pseudo-branches. + emitRRX(Mips::BEQ, Mips::ZERO, Mips::ZERO, + MCOperand::createExpr(OffsetExpr), IDLoc, Instructions); + Warning(IDLoc, "branch is always taken"); + return false; + } + if (IsUnsigned) { + // If the $rs is $0 and the pseudo-branch is BLTU (0 < x) or + // if the $rt is $0 and the pseudo-branch is BGTU (x > 0), + // the pseudo-branch will be taken only when the non-zero register is + // different from 0, so we emit a BNEZ. + // + // If the $rs is $0 and the pseudo-branch is BGEU (0 >= x) or + // if the $rt is $0 and the pseudo-branch is BLEU (x <= 0), + // the pseudo-branch will be taken only when the non-zero register is + // equal to 0, so we emit a BEQZ. + // + // Because only BLEU and BGEU branch on equality, we can use the + // AcceptsEquality variable to decide when to emit the BEQZ. + emitRRX(AcceptsEquality ? Mips::BEQ : Mips::BNE, + IsSrcRegZero ? TrgReg : SrcReg, Mips::ZERO, + MCOperand::createExpr(OffsetExpr), IDLoc, Instructions); + return false; + } + // If we have a signed pseudo-branch and one of the registers is $0, + // we can use an appropriate compare-to-zero branch. We select which one + // to use in the switch statement above. + emitRX(IsSrcRegZero ? ZeroSrcOpcode : ZeroTrgOpcode, + IsSrcRegZero ? TrgReg : SrcReg, MCOperand::createExpr(OffsetExpr), + IDLoc, Instructions); + return false; + } + + // If neither the SrcReg nor the TrgReg are $0, we need AT to perform the + // expansions. If it is not available, we return. + unsigned ATRegNum = getATReg(IDLoc); + if (!ATRegNum) + return true; + + if (!EmittedNoMacroWarning) + warnIfNoMacro(IDLoc); + + // SLT fits well with 2 of our 4 pseudo-branches: + // BLT, where $rs < $rt, translates into "slt $at, $rs, $rt" and + // BGT, where $rs > $rt, translates into "slt $at, $rt, $rs". + // If the result of the SLT is 1, we branch, and if it's 0, we don't. + // This is accomplished by using a BNEZ with the result of the SLT. + // + // The other 2 pseudo-branches are opposites of the above 2 (BGE with BLT + // and BLE with BGT), so we change the BNEZ into a a BEQZ. + // Because only BGE and BLE branch on equality, we can use the + // AcceptsEquality variable to decide when to emit the BEQZ. + // Note that the order of the SLT arguments doesn't change between + // opposites. + // + // The same applies to the unsigned variants, except that SLTu is used + // instead of SLT. + emitRRR(IsUnsigned ? Mips::SLTu : Mips::SLT, ATRegNum, + ReverseOrderSLT ? TrgReg : SrcReg, ReverseOrderSLT ? SrcReg : TrgReg, + IDLoc, Instructions); + + emitRRX(IsLikely ? (AcceptsEquality ? Mips::BEQL : Mips::BNEL) + : (AcceptsEquality ? Mips::BEQ : Mips::BNE), + ATRegNum, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, + Instructions); + return false; +} + +bool MipsAsmParser::expandDiv(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions, + const bool IsMips64, const bool Signed) { + if (hasMips32r6()) { + Error(IDLoc, "instruction not supported on mips32r6 or mips64r6"); + return false; + } + + warnIfNoMacro(IDLoc); + + const MCOperand &RsRegOp = Inst.getOperand(0); + assert(RsRegOp.isReg() && "expected register operand kind"); + unsigned RsReg = RsRegOp.getReg(); + + const MCOperand &RtRegOp = Inst.getOperand(1); + assert(RtRegOp.isReg() && "expected register operand kind"); + unsigned RtReg = RtRegOp.getReg(); + unsigned DivOp; + unsigned ZeroReg; + + if (IsMips64) { + DivOp = Signed ? Mips::DSDIV : Mips::DUDIV; + ZeroReg = Mips::ZERO_64; + } else { + DivOp = Signed ? Mips::SDIV : Mips::UDIV; + ZeroReg = Mips::ZERO; + } + + bool UseTraps = useTraps(); + + if (RsReg == Mips::ZERO || RsReg == Mips::ZERO_64) { + if (RtReg == Mips::ZERO || RtReg == Mips::ZERO_64) + Warning(IDLoc, "dividing zero by zero"); + if (IsMips64) { + if (Signed && (RtReg == Mips::ZERO || RtReg == Mips::ZERO_64)) { + if (UseTraps) { + emitRRI(Mips::TEQ, RtReg, ZeroReg, 0x7, IDLoc, Instructions); + return false; + } + + emitII(Mips::BREAK, 0x7, 0, IDLoc, Instructions); + return false; + } + } else { + emitRR(DivOp, RsReg, RtReg, IDLoc, Instructions); + return false; + } + } + + if (RtReg == Mips::ZERO || RtReg == Mips::ZERO_64) { + Warning(IDLoc, "division by zero"); + if (Signed) { + if (UseTraps) { + emitRRI(Mips::TEQ, RtReg, ZeroReg, 0x7, IDLoc, Instructions); + return false; + } + + emitII(Mips::BREAK, 0x7, 0, IDLoc, Instructions); + return false; + } + } + + // FIXME: The values for these two BranchTarget variables may be different in + // micromips. These magic numbers need to be removed. + unsigned BranchTargetNoTraps; + unsigned BranchTarget; + + if (UseTraps) { + BranchTarget = IsMips64 ? 12 : 8; + emitRRI(Mips::TEQ, RtReg, ZeroReg, 0x7, IDLoc, Instructions); + } else { + BranchTarget = IsMips64 ? 20 : 16; + BranchTargetNoTraps = 8; + // Branch to the li instruction. + emitRRI(Mips::BNE, RtReg, ZeroReg, BranchTargetNoTraps, IDLoc, + Instructions); + } + + emitRR(DivOp, RsReg, RtReg, IDLoc, Instructions); + + if (!UseTraps) + emitII(Mips::BREAK, 0x7, 0, IDLoc, Instructions); + + if (!Signed) { + emitR(Mips::MFLO, RsReg, IDLoc, Instructions); + return false; + } + + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + + emitRRI(Mips::ADDiu, ATReg, ZeroReg, -1, IDLoc, Instructions); + if (IsMips64) { + // Branch to the mflo instruction. + emitRRI(Mips::BNE, RtReg, ATReg, BranchTarget, IDLoc, Instructions); + emitRRI(Mips::ADDiu, ATReg, ZeroReg, 1, IDLoc, Instructions); + emitRRI(Mips::DSLL32, ATReg, ATReg, 0x1f, IDLoc, Instructions); + } else { + // Branch to the mflo instruction. + emitRRI(Mips::BNE, RtReg, ATReg, BranchTarget, IDLoc, Instructions); + emitRI(Mips::LUi, ATReg, (uint16_t)0x8000, IDLoc, Instructions); + } + + if (UseTraps) + emitRRI(Mips::TEQ, RsReg, ATReg, 0x6, IDLoc, Instructions); + else { + // Branch to the mflo instruction. + emitRRI(Mips::BNE, RsReg, ATReg, BranchTargetNoTraps, IDLoc, Instructions); + emitRRI(Mips::SLL, ZeroReg, ZeroReg, 0, IDLoc, Instructions); + emitII(Mips::BREAK, 0x6, 0, IDLoc, Instructions); + } + emitR(Mips::MFLO, RsReg, IDLoc, Instructions); + return false; +} + +bool MipsAsmParser::expandUlh(MCInst &Inst, bool Signed, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + if (hasMips32r6() || hasMips64r6()) { + Error(IDLoc, "instruction not supported on mips32r6 or mips64r6"); + return false; + } + + warnIfNoMacro(IDLoc); + + const MCOperand &DstRegOp = Inst.getOperand(0); + assert(DstRegOp.isReg() && "expected register operand kind"); + + const MCOperand &SrcRegOp = Inst.getOperand(1); + assert(SrcRegOp.isReg() && "expected register operand kind"); + + const MCOperand &OffsetImmOp = Inst.getOperand(2); + assert(OffsetImmOp.isImm() && "expected immediate operand kind"); + + unsigned DstReg = DstRegOp.getReg(); + unsigned SrcReg = SrcRegOp.getReg(); + int64_t OffsetValue = OffsetImmOp.getImm(); + + // NOTE: We always need AT for ULHU, as it is always used as the source + // register for one of the LBu's. + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + + // When the value of offset+1 does not fit in 16 bits, we have to load the + // offset in AT, (D)ADDu the original source register (if there was one), and + // then use AT as the source register for the 2 generated LBu's. + bool LoadedOffsetInAT = false; + if (!isInt<16>(OffsetValue + 1) || !isInt<16>(OffsetValue)) { + LoadedOffsetInAT = true; + + if (loadImmediate(OffsetValue, ATReg, Mips::NoRegister, !ABI.ArePtrs64bit(), + true, IDLoc, Instructions)) + return true; + + // NOTE: We do this (D)ADDu here instead of doing it in loadImmediate() + // because it will make our output more similar to GAS'. For example, + // generating an "ori $1, $zero, 32768" followed by an "addu $1, $1, $9", + // instead of just an "ori $1, $9, 32768". + // NOTE: If there is no source register specified in the ULHU, the parser + // will interpret it as $0. + if (SrcReg != Mips::ZERO && SrcReg != Mips::ZERO_64) + createAddu(ATReg, ATReg, SrcReg, ABI.ArePtrs64bit(), Instructions); + } + + unsigned FirstLbuDstReg = LoadedOffsetInAT ? DstReg : ATReg; + unsigned SecondLbuDstReg = LoadedOffsetInAT ? ATReg : DstReg; + unsigned LbuSrcReg = LoadedOffsetInAT ? ATReg : SrcReg; + + int64_t FirstLbuOffset = 0, SecondLbuOffset = 0; + if (isLittle()) { + FirstLbuOffset = LoadedOffsetInAT ? 1 : (OffsetValue + 1); + SecondLbuOffset = LoadedOffsetInAT ? 0 : OffsetValue; + } else { + FirstLbuOffset = LoadedOffsetInAT ? 0 : OffsetValue; + SecondLbuOffset = LoadedOffsetInAT ? 1 : (OffsetValue + 1); + } + + unsigned SllReg = LoadedOffsetInAT ? DstReg : ATReg; + + emitRRI(Signed ? Mips::LB : Mips::LBu, FirstLbuDstReg, LbuSrcReg, + FirstLbuOffset, IDLoc, Instructions); + + emitRRI(Mips::LBu, SecondLbuDstReg, LbuSrcReg, SecondLbuOffset, IDLoc, + Instructions); + + emitRRI(Mips::SLL, SllReg, SllReg, 8, IDLoc, Instructions); + + emitRRR(Mips::OR, DstReg, DstReg, ATReg, IDLoc, Instructions); + + return false; +} + +bool MipsAsmParser::expandUlw(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + if (hasMips32r6() || hasMips64r6()) { + Error(IDLoc, "instruction not supported on mips32r6 or mips64r6"); + return false; + } + + const MCOperand &DstRegOp = Inst.getOperand(0); + assert(DstRegOp.isReg() && "expected register operand kind"); + + const MCOperand &SrcRegOp = Inst.getOperand(1); + assert(SrcRegOp.isReg() && "expected register operand kind"); + + const MCOperand &OffsetImmOp = Inst.getOperand(2); + assert(OffsetImmOp.isImm() && "expected immediate operand kind"); + + unsigned SrcReg = SrcRegOp.getReg(); + int64_t OffsetValue = OffsetImmOp.getImm(); + unsigned ATReg = 0; + + // When the value of offset+3 does not fit in 16 bits, we have to load the + // offset in AT, (D)ADDu the original source register (if there was one), and + // then use AT as the source register for the generated LWL and LWR. + bool LoadedOffsetInAT = false; + if (!isInt<16>(OffsetValue + 3) || !isInt<16>(OffsetValue)) { + ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + LoadedOffsetInAT = true; + + warnIfNoMacro(IDLoc); + + if (loadImmediate(OffsetValue, ATReg, Mips::NoRegister, !ABI.ArePtrs64bit(), + true, IDLoc, Instructions)) + return true; + + // NOTE: We do this (D)ADDu here instead of doing it in loadImmediate() + // because it will make our output more similar to GAS'. For example, + // generating an "ori $1, $zero, 32768" followed by an "addu $1, $1, $9", + // instead of just an "ori $1, $9, 32768". + // NOTE: If there is no source register specified in the ULW, the parser + // will interpret it as $0. + if (SrcReg != Mips::ZERO && SrcReg != Mips::ZERO_64) + createAddu(ATReg, ATReg, SrcReg, ABI.ArePtrs64bit(), Instructions); + } + + unsigned FinalSrcReg = LoadedOffsetInAT ? ATReg : SrcReg; + int64_t LeftLoadOffset = 0, RightLoadOffset = 0; + if (isLittle()) { + LeftLoadOffset = LoadedOffsetInAT ? 3 : (OffsetValue + 3); + RightLoadOffset = LoadedOffsetInAT ? 0 : OffsetValue; + } else { + LeftLoadOffset = LoadedOffsetInAT ? 0 : OffsetValue; + RightLoadOffset = LoadedOffsetInAT ? 3 : (OffsetValue + 3); + } + + emitRRI(Mips::LWL, DstRegOp.getReg(), FinalSrcReg, LeftLoadOffset, IDLoc, + Instructions); + + emitRRI(Mips::LWR, DstRegOp.getReg(), FinalSrcReg, RightLoadOffset, IDLoc, + Instructions); + + return false; +} + +bool MipsAsmParser::expandAliasImmediate(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + + assert (Inst.getNumOperands() == 3 && "Invalid operand count"); + assert (Inst.getOperand(0).isReg() && + Inst.getOperand(1).isReg() && + Inst.getOperand(2).isImm() && "Invalid instruction operand."); + + unsigned ATReg = Mips::NoRegister; + unsigned FinalDstReg = Mips::NoRegister; + unsigned DstReg = Inst.getOperand(0).getReg(); + unsigned SrcReg = Inst.getOperand(1).getReg(); + int64_t ImmValue = Inst.getOperand(2).getImm(); + + bool Is32Bit = isInt<32>(ImmValue) || isUInt<32>(ImmValue); + + unsigned FinalOpcode = Inst.getOpcode(); + + if (DstReg == SrcReg) { + ATReg = getATReg(Inst.getLoc()); + if (!ATReg) + return true; + FinalDstReg = DstReg; + DstReg = ATReg; + } + + if (!loadImmediate(ImmValue, DstReg, Mips::NoRegister, Is32Bit, false, Inst.getLoc(), Instructions)) { + switch (FinalOpcode) { + default: + llvm_unreachable("unimplemented expansion"); + case (Mips::ADDi): + FinalOpcode = Mips::ADD; + break; + case (Mips::ADDiu): + FinalOpcode = Mips::ADDu; + break; + case (Mips::ANDi): + FinalOpcode = Mips::AND; + break; + case (Mips::NORImm): + FinalOpcode = Mips::NOR; + break; + case (Mips::ORi): + FinalOpcode = Mips::OR; + break; + case (Mips::SLTi): + FinalOpcode = Mips::SLT; + break; + case (Mips::SLTiu): + FinalOpcode = Mips::SLTu; + break; + case (Mips::XORi): + FinalOpcode = Mips::XOR; + break; + } + + if (FinalDstReg == Mips::NoRegister) + emitRRR(FinalOpcode, DstReg, DstReg, SrcReg, IDLoc, Instructions); + else + emitRRR(FinalOpcode, FinalDstReg, FinalDstReg, DstReg, IDLoc, + Instructions); + return false; + } + return true; +} + +bool MipsAsmParser::expandRotation(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + unsigned ATReg = Mips::NoRegister; + unsigned DReg = Inst.getOperand(0).getReg(); + unsigned SReg = Inst.getOperand(1).getReg(); + unsigned TReg = Inst.getOperand(2).getReg(); + unsigned TmpReg = DReg; + + unsigned FirstShift = Mips::NOP; + unsigned SecondShift = Mips::NOP; + + if (hasMips32r2()) { + + if (DReg == SReg) { + TmpReg = getATReg(Inst.getLoc()); + if (!TmpReg) + return true; + } + + if (Inst.getOpcode() == Mips::ROL) { + emitRRR(Mips::SUBu, TmpReg, Mips::ZERO, TReg, Inst.getLoc(), Instructions); + emitRRR(Mips::ROTRV, DReg, SReg, TmpReg, Inst.getLoc(), Instructions); + return false; + } + + if (Inst.getOpcode() == Mips::ROR) { + emitRRR(Mips::ROTRV, DReg, SReg, TReg, Inst.getLoc(), Instructions); + return false; + } + + return true; + } + + if (hasMips32()) { + + switch (Inst.getOpcode()) { + default: + llvm_unreachable("unexpected instruction opcode"); + case Mips::ROL: + FirstShift = Mips::SRLV; + SecondShift = Mips::SLLV; + break; + case Mips::ROR: + FirstShift = Mips::SLLV; + SecondShift = Mips::SRLV; + break; + } + + ATReg = getATReg(Inst.getLoc()); + if (!ATReg) + return true; + + emitRRR(Mips::SUBu, ATReg, Mips::ZERO, TReg, Inst.getLoc(), Instructions); + emitRRR(FirstShift, ATReg, SReg, ATReg, Inst.getLoc(), Instructions); + emitRRR(SecondShift, DReg, SReg, TReg, Inst.getLoc(), Instructions); + emitRRR(Mips::OR, DReg, DReg, ATReg, Inst.getLoc(), Instructions); + + return false; + } + + return true; +} + +bool MipsAsmParser::expandRotationImm(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + + unsigned ATReg = Mips::NoRegister; + unsigned DReg = Inst.getOperand(0).getReg(); + unsigned SReg = Inst.getOperand(1).getReg(); + int64_t ImmValue = Inst.getOperand(2).getImm(); + + unsigned FirstShift = Mips::NOP; + unsigned SecondShift = Mips::NOP; + + if (hasMips32r2()) { + + if (Inst.getOpcode() == Mips::ROLImm) { + uint64_t MaxShift = 32; + uint64_t ShiftValue = ImmValue; + if (ImmValue != 0) + ShiftValue = MaxShift - ImmValue; + emitRRI(Mips::ROTR, DReg, SReg, ShiftValue, Inst.getLoc(), Instructions); + return false; + } + + if (Inst.getOpcode() == Mips::RORImm) { + emitRRI(Mips::ROTR, DReg, SReg, ImmValue, Inst.getLoc(), Instructions); + return false; + } + + return true; + } + + if (hasMips32()) { + + if (ImmValue == 0) { + emitRRI(Mips::SRL, DReg, SReg, 0, Inst.getLoc(), Instructions); + return false; + } + + switch (Inst.getOpcode()) { + default: + llvm_unreachable("unexpected instruction opcode"); + case Mips::ROLImm: + FirstShift = Mips::SLL; + SecondShift = Mips::SRL; + break; + case Mips::RORImm: + FirstShift = Mips::SRL; + SecondShift = Mips::SLL; + break; + } + + ATReg = getATReg(Inst.getLoc()); + if (!ATReg) + return true; + + emitRRI(FirstShift, ATReg, SReg, ImmValue, Inst.getLoc(), Instructions); + emitRRI(SecondShift, DReg, SReg, 32 - ImmValue, Inst.getLoc(), Instructions); + emitRRR(Mips::OR, DReg, DReg, ATReg, Inst.getLoc(), Instructions); + + return false; + } + + return true; +} + +bool MipsAsmParser::expandDRotation(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + + unsigned ATReg = Mips::NoRegister; + unsigned DReg = Inst.getOperand(0).getReg(); + unsigned SReg = Inst.getOperand(1).getReg(); + unsigned TReg = Inst.getOperand(2).getReg(); + unsigned TmpReg = DReg; + + unsigned FirstShift = Mips::NOP; + unsigned SecondShift = Mips::NOP; + + if (hasMips64r2()) { + + if (TmpReg == SReg) { + TmpReg = getATReg(Inst.getLoc()); + if (!TmpReg) + return true; + } + + if (Inst.getOpcode() == Mips::DROL) { + emitRRR(Mips::DSUBu, TmpReg, Mips::ZERO, TReg, Inst.getLoc(), Instructions); + emitRRR(Mips::DROTRV, DReg, SReg, TmpReg, Inst.getLoc(), Instructions); + return false; + } + + if (Inst.getOpcode() == Mips::DROR) { + emitRRR(Mips::DROTRV, DReg, SReg, TReg, Inst.getLoc(), Instructions); + return false; + } + + return true; + } + + if (hasMips64()) { + + switch (Inst.getOpcode()) { + default: + llvm_unreachable("unexpected instruction opcode"); + case Mips::DROL: + FirstShift = Mips::DSRLV; + SecondShift = Mips::DSLLV; + break; + case Mips::DROR: + FirstShift = Mips::DSLLV; + SecondShift = Mips::DSRLV; + break; + } + + ATReg = getATReg(Inst.getLoc()); + if (!ATReg) + return true; + + emitRRR(Mips::DSUBu, ATReg, Mips::ZERO, TReg, Inst.getLoc(), Instructions); + emitRRR(FirstShift, ATReg, SReg, ATReg, Inst.getLoc(), Instructions); + emitRRR(SecondShift, DReg, SReg, TReg, Inst.getLoc(), Instructions); + emitRRR(Mips::OR, DReg, DReg, ATReg, Inst.getLoc(), Instructions); + + return false; + } + + return true; +} + +bool MipsAsmParser::expandDRotationImm(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + + unsigned ATReg = Mips::NoRegister; + unsigned DReg = Inst.getOperand(0).getReg(); + unsigned SReg = Inst.getOperand(1).getReg(); + int64_t ImmValue = Inst.getOperand(2).getImm() % 64; + + unsigned FirstShift = Mips::NOP; + unsigned SecondShift = Mips::NOP; + + MCInst TmpInst; + + if (hasMips64r2()) { + + unsigned FinalOpcode = Mips::NOP; + if (ImmValue == 0) + FinalOpcode = Mips::DROTR; + else if (ImmValue % 32 == 0) + FinalOpcode = Mips::DROTR32; + else if ((ImmValue >= 1) && (ImmValue <= 32)) { + if (Inst.getOpcode() == Mips::DROLImm) + FinalOpcode = Mips::DROTR32; + else + FinalOpcode = Mips::DROTR; + } else if (ImmValue >= 33) { + if (Inst.getOpcode() == Mips::DROLImm) + FinalOpcode = Mips::DROTR; + else + FinalOpcode = Mips::DROTR32; + } + + uint64_t ShiftValue = ImmValue % 32; + if (Inst.getOpcode() == Mips::DROLImm) + ShiftValue = (32 - ImmValue % 32) % 32; + + emitRRI(FinalOpcode, DReg, SReg, ShiftValue, Inst.getLoc(), Instructions); + + return false; + } + + if (hasMips64()) { + + if (ImmValue == 0) { + emitRRI(Mips::DSRL, DReg, SReg, 0, Inst.getLoc(), Instructions); + return false; + } + + switch (Inst.getOpcode()) { + default: + llvm_unreachable("unexpected instruction opcode"); + case Mips::DROLImm: + if ((ImmValue >= 1) && (ImmValue <= 31)) { + FirstShift = Mips::DSLL; + SecondShift = Mips::DSRL32; + } + if (ImmValue == 32) { + FirstShift = Mips::DSLL32; + SecondShift = Mips::DSRL32; + } + if ((ImmValue >= 33) && (ImmValue <= 63)) { + FirstShift = Mips::DSLL32; + SecondShift = Mips::DSRL; + } + break; + case Mips::DRORImm: + if ((ImmValue >= 1) && (ImmValue <= 31)) { + FirstShift = Mips::DSRL; + SecondShift = Mips::DSLL32; + } + if (ImmValue == 32) { + FirstShift = Mips::DSRL32; + SecondShift = Mips::DSLL32; + } + if ((ImmValue >= 33) && (ImmValue <= 63)) { + FirstShift = Mips::DSRL32; + SecondShift = Mips::DSLL; + } + break; + } + + ATReg = getATReg(Inst.getLoc()); + if (!ATReg) + return true; + + emitRRI(FirstShift, ATReg, SReg, ImmValue % 32, Inst.getLoc(), Instructions); + emitRRI(SecondShift, DReg, SReg, (32 - ImmValue % 32) % 32, Inst.getLoc(), Instructions); + emitRRR(Mips::OR, DReg, DReg, ATReg, Inst.getLoc(), Instructions); + + return false; + } + + return true; +} + +void MipsAsmParser::createNop(bool hasShortDelaySlot, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + if (hasShortDelaySlot) + emitRR(Mips::MOVE16_MM, Mips::ZERO, Mips::ZERO, IDLoc, Instructions); + else + emitRRI(Mips::SLL, Mips::ZERO, Mips::ZERO, 0, IDLoc, Instructions); +} + +void MipsAsmParser::createAddu(unsigned DstReg, unsigned SrcReg, + unsigned TrgReg, bool Is64Bit, + SmallVectorImpl<MCInst> &Instructions) { + emitRRR(Is64Bit ? Mips::DADDu : Mips::ADDu, DstReg, SrcReg, TrgReg, SMLoc(), + Instructions); +} + +void MipsAsmParser::createCpRestoreMemOp( + bool IsLoad, int StackOffset, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + // If the offset can not fit into 16 bits, we need to expand. + if (!isInt<16>(StackOffset)) { + MCInst MemInst; + MemInst.setOpcode(IsLoad ? Mips::LW : Mips::SW); + MemInst.addOperand(MCOperand::createReg(Mips::GP)); + MemInst.addOperand(MCOperand::createReg(Mips::SP)); + MemInst.addOperand(MCOperand::createImm(StackOffset)); + expandMemInst(MemInst, IDLoc, Instructions, IsLoad, true /*HasImmOpnd*/); + return; + } + + emitRRI(IsLoad ? Mips::LW : Mips::SW, Mips::GP, Mips::SP, StackOffset, IDLoc, + Instructions); +} + +unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) { + // As described by the Mips32r2 spec, the registers Rd and Rs for + // jalr.hb must be different. + unsigned Opcode = Inst.getOpcode(); + + if (Opcode == Mips::JALR_HB && + (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg())) + return Match_RequiresDifferentSrcAndDst; + + return Match_Success; +} + +static SMLoc RefineErrorLoc(const SMLoc Loc, const OperandVector &Operands, + uint64_t ErrorInfo) { + if (ErrorInfo != ~0ULL && ErrorInfo < Operands.size()) { + SMLoc ErrorLoc = Operands[ErrorInfo]->getStartLoc(); + if (ErrorLoc == SMLoc()) + return Loc; + return ErrorLoc; + } + return Loc; +} + +bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, + MCStreamer &Out, + uint64_t &ErrorInfo, + bool MatchingInlineAsm) { + + MCInst Inst; + SmallVector<MCInst, 8> Instructions; + unsigned MatchResult = + MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm); + + switch (MatchResult) { + case Match_Success: { + if (processInstruction(Inst, IDLoc, Instructions)) + return true; + for (unsigned i = 0; i < Instructions.size(); i++) + Out.EmitInstruction(Instructions[i], getSTI()); + return false; + } + case Match_MissingFeature: + Error(IDLoc, "instruction requires a CPU feature not currently enabled"); + return true; + case Match_InvalidOperand: { + SMLoc ErrorLoc = IDLoc; + if (ErrorInfo != ~0ULL) { + if (ErrorInfo >= Operands.size()) + return Error(IDLoc, "too few operands for instruction"); + + ErrorLoc = Operands[ErrorInfo]->getStartLoc(); + if (ErrorLoc == SMLoc()) + ErrorLoc = IDLoc; + } + + return Error(ErrorLoc, "invalid operand for instruction"); + } + case Match_MnemonicFail: + return Error(IDLoc, "invalid instruction"); + case Match_RequiresDifferentSrcAndDst: + return Error(IDLoc, "source and destination must be different"); + case Match_Immz: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected '0'"); + case Match_UImm1_0: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 1-bit unsigned immediate"); + case Match_UImm2_0: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 2-bit unsigned immediate"); + case Match_UImm2_1: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range 1 .. 4"); + case Match_UImm3_0: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 3-bit unsigned immediate"); + case Match_UImm4_0: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 4-bit unsigned immediate"); + case Match_UImm5_0: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 5-bit unsigned immediate"); + case Match_UImm5_1: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range 1 .. 32"); + case Match_UImm5_32: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range 32 .. 63"); + case Match_UImm5_33: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range 33 .. 64"); + case Match_UImm5_0_Report_UImm6: + // This is used on UImm5 operands that have a corresponding UImm5_32 + // operand to avoid confusing the user. + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 6-bit unsigned immediate"); + case Match_UImm5_Lsl2: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected both 7-bit unsigned immediate and multiple of 4"); + case Match_UImm6_0: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 6-bit unsigned immediate"); + case Match_SImm6: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 6-bit signed immediate"); + case Match_UImm7_0: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 7-bit unsigned immediate"); + case Match_UImm8_0: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 8-bit unsigned immediate"); + case Match_UImm10_0: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 10-bit unsigned immediate"); + } + + llvm_unreachable("Implement any new match types added!"); +} + +void MipsAsmParser::warnIfRegIndexIsAT(unsigned RegIndex, SMLoc Loc) { + if (RegIndex != 0 && AssemblerOptions.back()->getATRegIndex() == RegIndex) + Warning(Loc, "used $at (currently $" + Twine(RegIndex) + + ") without \".set noat\""); +} + +void MipsAsmParser::warnIfNoMacro(SMLoc Loc) { + if (!AssemblerOptions.back()->isMacro()) + Warning(Loc, "macro instruction expanded into multiple instructions"); +} + +void +MipsAsmParser::printWarningWithFixIt(const Twine &Msg, const Twine &FixMsg, + SMRange Range, bool ShowColors) { + getSourceManager().PrintMessage(Range.Start, SourceMgr::DK_Warning, Msg, + Range, SMFixIt(Range, FixMsg), + ShowColors); +} + +int MipsAsmParser::matchCPURegisterName(StringRef Name) { + int CC; + + CC = StringSwitch<unsigned>(Name) + .Case("zero", 0) + .Case("at", 1) + .Case("a0", 4) + .Case("a1", 5) + .Case("a2", 6) + .Case("a3", 7) + .Case("v0", 2) + .Case("v1", 3) + .Case("s0", 16) + .Case("s1", 17) + .Case("s2", 18) + .Case("s3", 19) + .Case("s4", 20) + .Case("s5", 21) + .Case("s6", 22) + .Case("s7", 23) + .Case("k0", 26) + .Case("k1", 27) + .Case("gp", 28) + .Case("sp", 29) + .Case("fp", 30) + .Case("s8", 30) + .Case("ra", 31) + .Case("t0", 8) + .Case("t1", 9) + .Case("t2", 10) + .Case("t3", 11) + .Case("t4", 12) + .Case("t5", 13) + .Case("t6", 14) + .Case("t7", 15) + .Case("t8", 24) + .Case("t9", 25) + .Default(-1); + + if (!(isABI_N32() || isABI_N64())) + return CC; + + if (12 <= CC && CC <= 15) { + // Name is one of t4-t7 + AsmToken RegTok = getLexer().peekTok(); + SMRange RegRange = RegTok.getLocRange(); + + StringRef FixedName = StringSwitch<StringRef>(Name) + .Case("t4", "t0") + .Case("t5", "t1") + .Case("t6", "t2") + .Case("t7", "t3") + .Default(""); + assert(FixedName != "" && "Register name is not one of t4-t7."); + + printWarningWithFixIt("register names $t4-$t7 are only available in O32.", + "Did you mean $" + FixedName + "?", RegRange); + } + + // 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; +} + +int MipsAsmParser::matchHWRegsRegisterName(StringRef Name) { + int CC; + + CC = StringSwitch<unsigned>(Name) + .Case("hwr_cpunum", 0) + .Case("hwr_synci_step", 1) + .Case("hwr_cc", 2) + .Case("hwr_ccres", 3) + .Case("hwr_ulr", 29) + .Default(-1); + + return CC; +} + +int MipsAsmParser::matchFPURegisterName(StringRef Name) { + + if (Name[0] == 'f') { + StringRef NumString = Name.substr(1); + unsigned IntVal; + if (NumString.getAsInteger(10, IntVal)) + return -1; // This is not an integer. + if (IntVal > 31) // Maximum index for fpu register. + return -1; + return IntVal; + } + return -1; +} + +int MipsAsmParser::matchFCCRegisterName(StringRef Name) { + + if (Name.startswith("fcc")) { + StringRef NumString = Name.substr(3); + unsigned IntVal; + if (NumString.getAsInteger(10, IntVal)) + return -1; // This is not an integer. + if (IntVal > 7) // There are only 8 fcc registers. + return -1; + return IntVal; + } + return -1; +} + +int MipsAsmParser::matchACRegisterName(StringRef Name) { + + if (Name.startswith("ac")) { + StringRef NumString = Name.substr(2); + unsigned IntVal; + if (NumString.getAsInteger(10, IntVal)) + return -1; // This is not an integer. + if (IntVal > 3) // There are only 3 acc registers. + return -1; + return IntVal; + } + return -1; +} + +int MipsAsmParser::matchMSA128RegisterName(StringRef Name) { + unsigned IntVal; + + if (Name.front() != 'w' || Name.drop_front(1).getAsInteger(10, IntVal)) + return -1; + + if (IntVal > 31) + return -1; + + return IntVal; +} + +int MipsAsmParser::matchMSA128CtrlRegisterName(StringRef Name) { + int CC; + + CC = StringSwitch<unsigned>(Name) + .Case("msair", 0) + .Case("msacsr", 1) + .Case("msaaccess", 2) + .Case("msasave", 3) + .Case("msamodify", 4) + .Case("msarequest", 5) + .Case("msamap", 6) + .Case("msaunmap", 7) + .Default(-1); + + return CC; +} + +unsigned MipsAsmParser::getATReg(SMLoc Loc) { + unsigned ATIndex = AssemblerOptions.back()->getATRegIndex(); + if (ATIndex == 0) { + reportParseError(Loc, + "pseudo-instruction requires $at, which is not available"); + return 0; + } + unsigned AT = getReg( + (isGP64bit()) ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, ATIndex); + return AT; +} + +unsigned MipsAsmParser::getReg(int RC, int RegNo) { + return *(getContext().getRegisterInfo()->getRegClass(RC).begin() + RegNo); +} + +unsigned MipsAsmParser::getGPR(int RegNo) { + return getReg(isGP64bit() ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, + RegNo); +} + +int MipsAsmParser::matchRegisterByNumber(unsigned RegNum, unsigned RegClass) { + if (RegNum > + getContext().getRegisterInfo()->getRegClass(RegClass).getNumRegs() - 1) + return -1; + + return getReg(RegClass, RegNum); +} + +bool MipsAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { + MCAsmParser &Parser = getParser(); + 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); + if (ResTy == MatchOperand_Success) + return false; + // If there wasn't a custom match, try the generic matcher below. Otherwise, + // there was a match, but an error occurred, in which case, just return that + // the operand parsing failed. + if (ResTy == MatchOperand_ParseFail) + return true; + + DEBUG(dbgs() << ".. Generic Parser\n"); + + switch (getLexer().getKind()) { + default: + Error(Parser.getTok().getLoc(), "unexpected token in operand"); + return true; + case AsmToken::Dollar: { + // Parse the register. + SMLoc S = Parser.getTok().getLoc(); + + // 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)) + return true; + + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + MCSymbol *Sym = getContext().getOrCreateSymbol("$" + Identifier); + // Otherwise create a symbol reference. + const MCExpr *Res = + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + + Operands.push_back(MipsOperand::CreateImm(Res, S, E, *this)); + return false; + } + // Else drop to expression parsing. + case AsmToken::LParen: + case AsmToken::Minus: + case AsmToken::Plus: + case AsmToken::Integer: + case AsmToken::Tilde: + case AsmToken::String: { + DEBUG(dbgs() << ".. generic integer\n"); + OperandMatchResultTy ResTy = parseImm(Operands); + return ResTy != MatchOperand_Success; + } + case AsmToken::Percent: { + // It is a symbol reference or constant expression. + const MCExpr *IdVal; + SMLoc S = Parser.getTok().getLoc(); // Start location of the operand. + if (parseRelocOperand(IdVal)) + return true; + + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + + Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this)); + return false; + } // case AsmToken::Percent + } // switch(getLexer().getKind()) + return true; +} + +const MCExpr *MipsAsmParser::evaluateRelocExpr(const MCExpr *Expr, + StringRef RelocStr) { + const MCExpr *Res; + // Check the type of the expression. + if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Expr)) { + // It's a constant, evaluate 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 MCConstantExpr::create(Val, getContext()); + } + + if (const MCSymbolRefExpr *MSRE = dyn_cast<MCSymbolRefExpr>(Expr)) { + // It's a symbol, create a symbolic expression from the symbol. + const MCSymbol *Symbol = &MSRE->getSymbol(); + MCSymbolRefExpr::VariantKind VK = getVariantKind(RelocStr); + Res = MCSymbolRefExpr::create(Symbol, VK, getContext()); + return Res; + } + + 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()); + return Res; + } + + if (const MCUnaryExpr *UN = dyn_cast<MCUnaryExpr>(Expr)) { + const MCExpr *UnExp = evaluateRelocExpr(UN->getSubExpr(), RelocStr); + Res = MCUnaryExpr::create(UN->getOpcode(), UnExp, getContext()); + return Res; + } + // Just return the original expression. + return Expr; +} + +bool MipsAsmParser::isEvaluated(const MCExpr *Expr) { + + switch (Expr->getKind()) { + case MCExpr::Constant: + return true; + case MCExpr::SymbolRef: + return (cast<MCSymbolRefExpr>(Expr)->getKind() != MCSymbolRefExpr::VK_None); + case MCExpr::Binary: + if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr)) { + if (!isEvaluated(BE->getLHS())) + return false; + return isEvaluated(BE->getRHS()); + } + case MCExpr::Unary: + return isEvaluated(cast<MCUnaryExpr>(Expr)->getSubExpr()); + case MCExpr::Target: + return true; + } + return false; +} + +bool MipsAsmParser::parseRelocOperand(const MCExpr *&Res) { + MCAsmParser &Parser = getParser(); + Parser.Lex(); // Eat the % token. + const AsmToken &Tok = Parser.getTok(); // Get next token, operation. + if (Tok.isNot(AsmToken::Identifier)) + return true; + + std::string Str = Tok.getIdentifier(); + + Parser.Lex(); // Eat the identifier. + // Now make an expression from the rest of the operand. + const MCExpr *IdVal; + SMLoc EndLoc; + + if (getLexer().getKind() == AsmToken::LParen) { + while (1) { + Parser.Lex(); // Eat the '(' token. + if (getLexer().getKind() == AsmToken::Percent) { + Parser.Lex(); // Eat the % token. + const AsmToken &nextTok = Parser.getTok(); + if (nextTok.isNot(AsmToken::Identifier)) + return true; + Str += "(%"; + Str += nextTok.getIdentifier(); + Parser.Lex(); // Eat the identifier. + if (getLexer().getKind() != AsmToken::LParen) + return true; + } else + break; + } + if (getParser().parseParenExpression(IdVal, EndLoc)) + return true; + + while (getLexer().getKind() == AsmToken::RParen) + Parser.Lex(); // Eat the ')' token. + + } else + return true; // Parenthesis must follow the relocation operand. + + Res = evaluateRelocExpr(IdVal, Str); + return false; +} + +bool MipsAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, + SMLoc &EndLoc) { + SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> Operands; + OperandMatchResultTy ResTy = parseAnyRegister(Operands); + if (ResTy == MatchOperand_Success) { + assert(Operands.size() == 1); + MipsOperand &Operand = static_cast<MipsOperand &>(*Operands.front()); + StartLoc = Operand.getStartLoc(); + EndLoc = Operand.getEndLoc(); + + // AFAIK, we only support numeric registers and named GPR's in CFI + // directives. + // Don't worry about eating tokens before failing. Using an unrecognised + // register is a parse error. + if (Operand.isGPRAsmReg()) { + // Resolve to GPR32 or GPR64 appropriately. + RegNo = isGP64bit() ? Operand.getGPR64Reg() : Operand.getGPR32Reg(); + } + + return (RegNo == (unsigned)-1); + } + + assert(Operands.size() == 0); + return (RegNo == (unsigned)-1); +} + +bool MipsAsmParser::parseMemOffset(const MCExpr *&Res, bool isParenExpr) { + MCAsmParser &Parser = getParser(); + SMLoc S; + bool Result = true; + unsigned NumOfLParen = 0; + + while (getLexer().getKind() == AsmToken::LParen) { + Parser.Lex(); + ++NumOfLParen; + } + + switch (getLexer().getKind()) { + default: + return true; + case AsmToken::Identifier: + case AsmToken::LParen: + case AsmToken::Integer: + case AsmToken::Minus: + case AsmToken::Plus: + if (isParenExpr) + Result = getParser().parseParenExprOfDepth(NumOfLParen, Res, S); + else + Result = (getParser().parseExpression(Res)); + while (getLexer().getKind() == AsmToken::RParen) + Parser.Lex(); + break; + case AsmToken::Percent: + Result = parseRelocOperand(Res); + } + return Result; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseMemOperand(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + DEBUG(dbgs() << "parseMemOperand\n"); + const MCExpr *IdVal = nullptr; + SMLoc S; + bool isParenExpr = false; + MipsAsmParser::OperandMatchResultTy Res = MatchOperand_NoMatch; + // First operand is the offset. + S = Parser.getTok().getLoc(); + + if (getLexer().getKind() == AsmToken::LParen) { + Parser.Lex(); + isParenExpr = true; + } + + if (getLexer().getKind() != AsmToken::Dollar) { + if (parseMemOffset(IdVal, isParenExpr)) + return MatchOperand_ParseFail; + + const AsmToken &Tok = Parser.getTok(); // Get the next token. + if (Tok.isNot(AsmToken::LParen)) { + MipsOperand &Mnemonic = static_cast<MipsOperand &>(*Operands[0]); + if (Mnemonic.getToken() == "la" || Mnemonic.getToken() == "dla") { + SMLoc E = + SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this)); + return MatchOperand_Success; + } + if (Tok.is(AsmToken::EndOfStatement)) { + SMLoc E = + SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + + // Zero register assumed, add a memory operand with ZERO as its base. + // "Base" will be managed by k_Memory. + auto Base = MipsOperand::createGPRReg(0, getContext().getRegisterInfo(), + S, E, *this); + Operands.push_back( + MipsOperand::CreateMem(std::move(Base), IdVal, S, E, *this)); + return MatchOperand_Success; + } + Error(Parser.getTok().getLoc(), "'(' expected"); + return MatchOperand_ParseFail; + } + + Parser.Lex(); // Eat the '(' token. + } + + Res = parseAnyRegister(Operands); + if (Res != MatchOperand_Success) + return Res; + + if (Parser.getTok().isNot(AsmToken::RParen)) { + Error(Parser.getTok().getLoc(), "')' expected"); + return MatchOperand_ParseFail; + } + + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + + Parser.Lex(); // Eat the ')' token. + + if (!IdVal) + IdVal = MCConstantExpr::create(0, getContext()); + + // Replace the register operand with the memory operand. + std::unique_ptr<MipsOperand> op( + static_cast<MipsOperand *>(Operands.back().release())); + // Remove the register from the operands. + // "op" will be managed by k_Memory. + Operands.pop_back(); + // Add the memory operand. + if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(IdVal)) { + int64_t Imm; + if (IdVal->evaluateAsAbsolute(Imm)) + IdVal = MCConstantExpr::create(Imm, getContext()); + else if (BE->getLHS()->getKind() != MCExpr::SymbolRef) + IdVal = MCBinaryExpr::create(BE->getOpcode(), BE->getRHS(), BE->getLHS(), + getContext()); + } + + Operands.push_back(MipsOperand::CreateMem(std::move(op), IdVal, S, E, *this)); + return MatchOperand_Success; +} + +bool MipsAsmParser::searchSymbolAlias(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + 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) { + const MCSymbolRefExpr *Ref = static_cast<const MCSymbolRefExpr *>(Expr); + StringRef DefSymbol = Ref->getSymbol().getName(); + if (DefSymbol.startswith("$")) { + OperandMatchResultTy ResTy = + matchAnyRegisterNameWithoutDollar(Operands, DefSymbol.substr(1), S); + if (ResTy == MatchOperand_Success) { + Parser.Lex(); + return true; + } else if (ResTy == MatchOperand_ParseFail) + llvm_unreachable("Should never ParseFail"); + return false; + } + } else if (Expr->getKind() == MCExpr::Constant) { + Parser.Lex(); + const MCConstantExpr *Const = static_cast<const MCConstantExpr *>(Expr); + Operands.push_back( + MipsOperand::CreateImm(Const, S, Parser.getTok().getLoc(), *this)); + return true; + } + } + return false; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::matchAnyRegisterNameWithoutDollar(OperandVector &Operands, + StringRef Identifier, + SMLoc S) { + int Index = matchCPURegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::createGPRReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; + } + + Index = matchHWRegsRegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::createHWRegsReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; + } + + Index = matchFPURegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::createFGRReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; + } + + Index = matchFCCRegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::createFCCReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; + } + + Index = matchACRegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::createACCReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; + } + + Index = matchMSA128RegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::createMSA128Reg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; + } + + Index = matchMSA128CtrlRegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::createMSACtrlReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; + } + + return MatchOperand_NoMatch; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::matchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S) { + MCAsmParser &Parser = getParser(); + 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; + } + + DEBUG(dbgs() << Parser.getTok().getKind() << "\n"); + + return MatchOperand_NoMatch; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseAnyRegister(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + DEBUG(dbgs() << "parseAnyRegister\n"); + + auto Token = Parser.getTok(); + + SMLoc S = Token.getLoc(); + + 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"); + + OperandMatchResultTy ResTy = matchAnyRegisterWithoutDollar(Operands, S); + if (ResTy == MatchOperand_Success) { + Parser.Lex(); // $ + Parser.Lex(); // identifier + } + return ResTy; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseImm(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + switch (getLexer().getKind()) { + default: + return MatchOperand_NoMatch; + case AsmToken::LParen: + case AsmToken::Minus: + case AsmToken::Plus: + case AsmToken::Integer: + case AsmToken::Tilde: + case AsmToken::String: + break; + } + + const MCExpr *IdVal; + SMLoc S = Parser.getTok().getLoc(); + if (getParser().parseExpression(IdVal)) + return MatchOperand_ParseFail; + + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this)); + return MatchOperand_Success; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseJumpTarget(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + DEBUG(dbgs() << "parseJumpTarget\n"); + + SMLoc S = getLexer().getLoc(); + + // Integers and expressions are acceptable + OperandMatchResultTy ResTy = parseImm(Operands); + if (ResTy != MatchOperand_NoMatch) + return ResTy; + + // Registers are a valid target and have priority over symbols. + ResTy = parseAnyRegister(Operands); + if (ResTy != MatchOperand_NoMatch) + return ResTy; + + 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; + } + Operands.push_back( + MipsOperand::CreateImm(Expr, S, getLexer().getLoc(), *this)); + return MatchOperand_Success; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseInvNum(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + const MCExpr *IdVal; + // If the first token is '$' we may have register operand. + if (Parser.getTok().is(AsmToken::Dollar)) + return MatchOperand_NoMatch; + SMLoc S = Parser.getTok().getLoc(); + if (getParser().parseExpression(IdVal)) + return MatchOperand_ParseFail; + const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(IdVal); + assert(MCE && "Unexpected MCExpr type."); + int64_t Val = MCE->getValue(); + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Operands.push_back(MipsOperand::CreateImm( + MCConstantExpr::create(0 - Val, getContext()), S, E, *this)); + return MatchOperand_Success; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseLSAImm(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + switch (getLexer().getKind()) { + default: + return MatchOperand_NoMatch; + case AsmToken::LParen: + case AsmToken::Plus: + case AsmToken::Minus: + case AsmToken::Integer: + break; + } + + const MCExpr *Expr; + SMLoc S = Parser.getTok().getLoc(); + + if (getParser().parseExpression(Expr)) + return MatchOperand_ParseFail; + + int64_t Val; + if (!Expr->evaluateAsAbsolute(Val)) { + Error(S, "expected immediate value"); + return MatchOperand_ParseFail; + } + + // The LSA instruction allows a 2-bit unsigned immediate. For this reason + // and because the CPU always adds one to the immediate field, the allowed + // range becomes 1..4. We'll only check the range here and will deal + // with the addition/subtraction when actually decoding/encoding + // the instruction. + if (Val < 1 || Val > 4) { + Error(S, "immediate not in range (1..4)"); + return MatchOperand_ParseFail; + } + + Operands.push_back( + MipsOperand::CreateImm(Expr, S, Parser.getTok().getLoc(), *this)); + return MatchOperand_Success; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseRegisterList(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + SmallVector<unsigned, 10> Regs; + unsigned RegNo; + unsigned PrevReg = Mips::NoRegister; + bool RegRange = false; + SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> TmpOperands; + + if (Parser.getTok().isNot(AsmToken::Dollar)) + return MatchOperand_ParseFail; + + SMLoc S = Parser.getTok().getLoc(); + while (parseAnyRegister(TmpOperands) == MatchOperand_Success) { + SMLoc E = getLexer().getLoc(); + MipsOperand &Reg = static_cast<MipsOperand &>(*TmpOperands.back()); + RegNo = isGP64bit() ? Reg.getGPR64Reg() : Reg.getGPR32Reg(); + if (RegRange) { + // Remove last register operand because registers from register range + // should be inserted first. + if ((isGP64bit() && RegNo == Mips::RA_64) || + (!isGP64bit() && RegNo == Mips::RA)) { + Regs.push_back(RegNo); + } else { + unsigned TmpReg = PrevReg + 1; + while (TmpReg <= RegNo) { + if ((((TmpReg < Mips::S0) || (TmpReg > Mips::S7)) && !isGP64bit()) || + (((TmpReg < Mips::S0_64) || (TmpReg > Mips::S7_64)) && + isGP64bit())) { + Error(E, "invalid register operand"); + return MatchOperand_ParseFail; + } + + PrevReg = TmpReg; + Regs.push_back(TmpReg++); + } + } + + RegRange = false; + } else { + if ((PrevReg == Mips::NoRegister) && + ((isGP64bit() && (RegNo != Mips::S0_64) && (RegNo != Mips::RA_64)) || + (!isGP64bit() && (RegNo != Mips::S0) && (RegNo != Mips::RA)))) { + Error(E, "$16 or $31 expected"); + return MatchOperand_ParseFail; + } else if (!(((RegNo == Mips::FP || RegNo == Mips::RA || + (RegNo >= Mips::S0 && RegNo <= Mips::S7)) && + !isGP64bit()) || + ((RegNo == Mips::FP_64 || RegNo == Mips::RA_64 || + (RegNo >= Mips::S0_64 && RegNo <= Mips::S7_64)) && + isGP64bit()))) { + Error(E, "invalid register operand"); + return MatchOperand_ParseFail; + } else if ((PrevReg != Mips::NoRegister) && (RegNo != PrevReg + 1) && + ((RegNo != Mips::FP && RegNo != Mips::RA && !isGP64bit()) || + (RegNo != Mips::FP_64 && RegNo != Mips::RA_64 && + isGP64bit()))) { + Error(E, "consecutive register numbers expected"); + return MatchOperand_ParseFail; + } + + Regs.push_back(RegNo); + } + + if (Parser.getTok().is(AsmToken::Minus)) + RegRange = true; + + if (!Parser.getTok().isNot(AsmToken::Minus) && + !Parser.getTok().isNot(AsmToken::Comma)) { + Error(E, "',' or '-' expected"); + return MatchOperand_ParseFail; + } + + Lex(); // Consume comma or minus + if (Parser.getTok().isNot(AsmToken::Dollar)) + break; + + PrevReg = RegNo; + } + + SMLoc E = Parser.getTok().getLoc(); + Operands.push_back(MipsOperand::CreateRegList(Regs, S, E, *this)); + parseMemOperand(Operands); + return MatchOperand_Success; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseRegisterPair(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + + SMLoc S = Parser.getTok().getLoc(); + if (parseAnyRegister(Operands) != MatchOperand_Success) + return MatchOperand_ParseFail; + + SMLoc E = Parser.getTok().getLoc(); + MipsOperand &Op = static_cast<MipsOperand &>(*Operands.back()); + unsigned Reg = Op.getGPR32Reg(); + Operands.pop_back(); + Operands.push_back(MipsOperand::CreateRegPair(Reg, S, E, *this)); + return MatchOperand_Success; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseMovePRegPair(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> TmpOperands; + SmallVector<unsigned, 10> Regs; + + if (Parser.getTok().isNot(AsmToken::Dollar)) + return MatchOperand_ParseFail; + + SMLoc S = Parser.getTok().getLoc(); + + if (parseAnyRegister(TmpOperands) != MatchOperand_Success) + return MatchOperand_ParseFail; + + MipsOperand *Reg = &static_cast<MipsOperand &>(*TmpOperands.back()); + unsigned RegNo = isGP64bit() ? Reg->getGPR64Reg() : Reg->getGPR32Reg(); + Regs.push_back(RegNo); + + SMLoc E = Parser.getTok().getLoc(); + if (Parser.getTok().isNot(AsmToken::Comma)) { + Error(E, "',' expected"); + return MatchOperand_ParseFail; + } + + // Remove comma. + Parser.Lex(); + + if (parseAnyRegister(TmpOperands) != MatchOperand_Success) + return MatchOperand_ParseFail; + + Reg = &static_cast<MipsOperand &>(*TmpOperands.back()); + RegNo = isGP64bit() ? Reg->getGPR64Reg() : Reg->getGPR32Reg(); + Regs.push_back(RegNo); + + Operands.push_back(MipsOperand::CreateRegList(Regs, S, E, *this)); + + return MatchOperand_Success; +} + +MCSymbolRefExpr::VariantKind MipsAsmParser::getVariantKind(StringRef Symbol) { + + MCSymbolRefExpr::VariantKind VK = + StringSwitch<MCSymbolRefExpr::VariantKind>(Symbol) + .Case("hi", MCSymbolRefExpr::VK_Mips_ABS_HI) + .Case("lo", MCSymbolRefExpr::VK_Mips_ABS_LO) + .Case("gp_rel", MCSymbolRefExpr::VK_Mips_GPREL) + .Case("call16", MCSymbolRefExpr::VK_Mips_GOT_CALL) + .Case("got", MCSymbolRefExpr::VK_Mips_GOT) + .Case("tlsgd", MCSymbolRefExpr::VK_Mips_TLSGD) + .Case("tlsldm", MCSymbolRefExpr::VK_Mips_TLSLDM) + .Case("dtprel_hi", MCSymbolRefExpr::VK_Mips_DTPREL_HI) + .Case("dtprel_lo", MCSymbolRefExpr::VK_Mips_DTPREL_LO) + .Case("gottprel", MCSymbolRefExpr::VK_Mips_GOTTPREL) + .Case("tprel_hi", MCSymbolRefExpr::VK_Mips_TPREL_HI) + .Case("tprel_lo", MCSymbolRefExpr::VK_Mips_TPREL_LO) + .Case("got_disp", MCSymbolRefExpr::VK_Mips_GOT_DISP) + .Case("got_page", MCSymbolRefExpr::VK_Mips_GOT_PAGE) + .Case("got_ofst", MCSymbolRefExpr::VK_Mips_GOT_OFST) + .Case("hi(%neg(%gp_rel", MCSymbolRefExpr::VK_Mips_GPOFF_HI) + .Case("lo(%neg(%gp_rel", MCSymbolRefExpr::VK_Mips_GPOFF_LO) + .Case("got_hi", MCSymbolRefExpr::VK_Mips_GOT_HI16) + .Case("got_lo", MCSymbolRefExpr::VK_Mips_GOT_LO16) + .Case("call_hi", MCSymbolRefExpr::VK_Mips_CALL_HI16) + .Case("call_lo", MCSymbolRefExpr::VK_Mips_CALL_LO16) + .Case("higher", MCSymbolRefExpr::VK_Mips_HIGHER) + .Case("highest", MCSymbolRefExpr::VK_Mips_HIGHEST) + .Case("pcrel_hi", MCSymbolRefExpr::VK_Mips_PCREL_HI16) + .Case("pcrel_lo", MCSymbolRefExpr::VK_Mips_PCREL_LO16) + .Default(MCSymbolRefExpr::VK_None); + + assert(VK != MCSymbolRefExpr::VK_None); + + return VK; +} + +/// Sometimes (i.e. load/stores) the operand may be followed immediately by +/// either this. +/// ::= '(', register, ')' +/// handle it before we iterate so we don't get tripped up by the lack of +/// a comma. +bool MipsAsmParser::parseParenSuffix(StringRef Name, OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + if (getLexer().is(AsmToken::LParen)) { + Operands.push_back( + MipsOperand::CreateToken("(", getLexer().getLoc(), *this)); + Parser.Lex(); + if (parseOperand(Operands, Name)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + if (Parser.getTok().isNot(AsmToken::RParen)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token, expected ')'"); + } + Operands.push_back( + MipsOperand::CreateToken(")", getLexer().getLoc(), *this)); + Parser.Lex(); + } + return false; +} + +/// Sometimes (i.e. in MSA) the operand may be followed immediately by +/// either one of these. +/// ::= '[', register, ']' +/// ::= '[', integer, ']' +/// handle it before we iterate so we don't get tripped up by the lack of +/// a comma. +bool MipsAsmParser::parseBracketSuffix(StringRef Name, + OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + if (getLexer().is(AsmToken::LBrac)) { + Operands.push_back( + MipsOperand::CreateToken("[", getLexer().getLoc(), *this)); + Parser.Lex(); + if (parseOperand(Operands, Name)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + if (Parser.getTok().isNot(AsmToken::RBrac)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token, expected ']'"); + } + Operands.push_back( + MipsOperand::CreateToken("]", getLexer().getLoc(), *this)); + Parser.Lex(); + } + return false; +} + +bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + DEBUG(dbgs() << "ParseInstruction\n"); + + // We have reached first instruction, module directive are now forbidden. + getTargetStreamer().forbidModuleDirective(); + + // 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, *this)); + + // Read the remaining operands. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + // Read the first operand. + if (parseOperand(Operands, Name)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + 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. + // Parse and remember the operand. + if (parseOperand(Operands, Name)) { + SMLoc Loc = getLexer().getLoc(); + 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)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::reportParseError(Twine ErrorMsg) { + MCAsmParser &Parser = getParser(); + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, ErrorMsg); +} + +bool MipsAsmParser::reportParseError(SMLoc Loc, Twine ErrorMsg) { + return Error(Loc, ErrorMsg); +} + +bool MipsAsmParser::parseSetNoAtDirective() { + MCAsmParser &Parser = getParser(); + // Line should look like: ".set noat". + + // Set the $at register to $0. + AssemblerOptions.back()->setATRegIndex(0); + + Parser.Lex(); // Eat "noat". + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + getTargetStreamer().emitDirectiveSetNoAt(); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetAtDirective() { + // Line can be: ".set at", which sets $at to $1 + // or ".set at=$reg", which sets $at to $reg. + MCAsmParser &Parser = getParser(); + Parser.Lex(); // Eat "at". + + if (getLexer().is(AsmToken::EndOfStatement)) { + // No register was specified, so we set $at to $1. + AssemblerOptions.back()->setATRegIndex(1); + + getTargetStreamer().emitDirectiveSetAt(); + Parser.Lex(); // Consume the EndOfStatement. + return false; + } + + if (getLexer().isNot(AsmToken::Equal)) { + reportParseError("unexpected token, expected equals sign"); + return false; + } + Parser.Lex(); // Eat "=". + + if (getLexer().isNot(AsmToken::Dollar)) { + if (getLexer().is(AsmToken::EndOfStatement)) { + reportParseError("no register specified"); + return false; + } else { + reportParseError("unexpected token, expected dollar sign '$'"); + return false; + } + } + Parser.Lex(); // Eat "$". + + // Find out what "reg" is. + unsigned AtRegNo; + const AsmToken &Reg = Parser.getTok(); + if (Reg.is(AsmToken::Identifier)) { + AtRegNo = matchCPURegisterName(Reg.getIdentifier()); + } else if (Reg.is(AsmToken::Integer)) { + AtRegNo = Reg.getIntVal(); + } else { + reportParseError("unexpected token, expected identifier or integer"); + return false; + } + + // Check if $reg is a valid register. If it is, set $at to $reg. + if (!AssemblerOptions.back()->setATRegIndex(AtRegNo)) { + reportParseError("invalid register"); + return false; + } + Parser.Lex(); // Eat "reg". + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + getTargetStreamer().emitDirectiveSetAtWithArg(AtRegNo); + + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetReorderDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + AssemblerOptions.back()->setReorder(); + getTargetStreamer().emitDirectiveSetReorder(); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetNoReorderDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + AssemblerOptions.back()->setNoReorder(); + getTargetStreamer().emitDirectiveSetNoReorder(); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetMacroDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + AssemblerOptions.back()->setMacro(); + getTargetStreamer().emitDirectiveSetMacro(); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetNoMacroDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + if (AssemblerOptions.back()->isReorder()) { + reportParseError("`noreorder' must be set before `nomacro'"); + return false; + } + AssemblerOptions.back()->setNoMacro(); + getTargetStreamer().emitDirectiveSetNoMacro(); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetMsaDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token, expected end of statement"); + + setFeatureBits(Mips::FeatureMSA, "msa"); + getTargetStreamer().emitDirectiveSetMsa(); + return false; +} + +bool MipsAsmParser::parseSetNoMsaDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token, expected end of statement"); + + clearFeatureBits(Mips::FeatureMSA, "msa"); + getTargetStreamer().emitDirectiveSetNoMsa(); + return false; +} + +bool MipsAsmParser::parseSetNoDspDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); // Eat "nodsp". + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + clearFeatureBits(Mips::FeatureDSP, "dsp"); + getTargetStreamer().emitDirectiveSetNoDsp(); + return false; +} + +bool MipsAsmParser::parseSetMips16Directive() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); // Eat "mips16". + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + setFeatureBits(Mips::FeatureMips16, "mips16"); + getTargetStreamer().emitDirectiveSetMips16(); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetNoMips16Directive() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); // Eat "nomips16". + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + clearFeatureBits(Mips::FeatureMips16, "mips16"); + getTargetStreamer().emitDirectiveSetNoMips16(); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetFpDirective() { + MCAsmParser &Parser = getParser(); + MipsABIFlagsSection::FpABIKind FpAbiVal; + // Line can be: .set fp=32 + // .set fp=xx + // .set fp=64 + Parser.Lex(); // Eat fp token + AsmToken Tok = Parser.getTok(); + if (Tok.isNot(AsmToken::Equal)) { + reportParseError("unexpected token, expected equals sign '='"); + return false; + } + Parser.Lex(); // Eat '=' token. + Tok = Parser.getTok(); + + if (!parseFpABIValue(FpAbiVal, ".set")) + return false; + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + getTargetStreamer().emitDirectiveSetFp(FpAbiVal); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetOddSPRegDirective() { + MCAsmParser &Parser = getParser(); + + Parser.Lex(); // Eat "oddspreg". + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + clearFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg"); + getTargetStreamer().emitDirectiveSetOddSPReg(); + return false; +} + +bool MipsAsmParser::parseSetNoOddSPRegDirective() { + MCAsmParser &Parser = getParser(); + + Parser.Lex(); // Eat "nooddspreg". + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + setFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg"); + getTargetStreamer().emitDirectiveSetNoOddSPReg(); + return false; +} + +bool MipsAsmParser::parseSetPopDirective() { + MCAsmParser &Parser = getParser(); + SMLoc Loc = getLexer().getLoc(); + + Parser.Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token, expected end of statement"); + + // Always keep an element on the options "stack" to prevent the user + // from changing the initial options. This is how we remember them. + if (AssemblerOptions.size() == 2) + return reportParseError(Loc, ".set pop with no .set push"); + + MCSubtargetInfo &STI = copySTI(); + AssemblerOptions.pop_back(); + setAvailableFeatures( + ComputeAvailableFeatures(AssemblerOptions.back()->getFeatures())); + STI.setFeatureBits(AssemblerOptions.back()->getFeatures()); + + getTargetStreamer().emitDirectiveSetPop(); + return false; +} + +bool MipsAsmParser::parseSetPushDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token, expected end of statement"); + + // Create a copy of the current assembler options environment and push it. + AssemblerOptions.push_back( + make_unique<MipsAssemblerOptions>(AssemblerOptions.back().get())); + + getTargetStreamer().emitDirectiveSetPush(); + return false; +} + +bool MipsAsmParser::parseSetSoftFloatDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token, expected end of statement"); + + setFeatureBits(Mips::FeatureSoftFloat, "soft-float"); + getTargetStreamer().emitDirectiveSetSoftFloat(); + return false; +} + +bool MipsAsmParser::parseSetHardFloatDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token, expected end of statement"); + + clearFeatureBits(Mips::FeatureSoftFloat, "soft-float"); + getTargetStreamer().emitDirectiveSetHardFloat(); + return false; +} + +bool MipsAsmParser::parseSetAssignment() { + StringRef Name; + const MCExpr *Value; + MCAsmParser &Parser = getParser(); + + if (Parser.parseIdentifier(Name)) + reportParseError("expected identifier after .set"); + + if (getLexer().isNot(AsmToken::Comma)) + return reportParseError("unexpected token, expected comma"); + Lex(); // Eat comma + + if (Parser.parseExpression(Value)) + return reportParseError("expected valid expression after comma"); + + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + Sym->setVariableValue(Value); + + return false; +} + +bool MipsAsmParser::parseSetMips0Directive() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token, expected end of statement"); + + // Reset assembler options to their initial values. + MCSubtargetInfo &STI = copySTI(); + setAvailableFeatures( + ComputeAvailableFeatures(AssemblerOptions.front()->getFeatures())); + STI.setFeatureBits(AssemblerOptions.front()->getFeatures()); + AssemblerOptions.back()->setFeatures(AssemblerOptions.front()->getFeatures()); + + getTargetStreamer().emitDirectiveSetMips0(); + return false; +} + +bool MipsAsmParser::parseSetArchDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); + if (getLexer().isNot(AsmToken::Equal)) + return reportParseError("unexpected token, expected equals sign"); + + Parser.Lex(); + StringRef Arch; + if (Parser.parseIdentifier(Arch)) + return reportParseError("expected arch identifier"); + + StringRef ArchFeatureName = + StringSwitch<StringRef>(Arch) + .Case("mips1", "mips1") + .Case("mips2", "mips2") + .Case("mips3", "mips3") + .Case("mips4", "mips4") + .Case("mips5", "mips5") + .Case("mips32", "mips32") + .Case("mips32r2", "mips32r2") + .Case("mips32r3", "mips32r3") + .Case("mips32r5", "mips32r5") + .Case("mips32r6", "mips32r6") + .Case("mips64", "mips64") + .Case("mips64r2", "mips64r2") + .Case("mips64r3", "mips64r3") + .Case("mips64r5", "mips64r5") + .Case("mips64r6", "mips64r6") + .Case("cnmips", "cnmips") + .Case("r4000", "mips3") // This is an implementation of Mips3. + .Default(""); + + if (ArchFeatureName.empty()) + return reportParseError("unsupported architecture"); + + selectArch(ArchFeatureName); + getTargetStreamer().emitDirectiveSetArch(Arch); + return false; +} + +bool MipsAsmParser::parseSetFeature(uint64_t Feature) { + MCAsmParser &Parser = getParser(); + Parser.Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token, expected end of statement"); + + 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::FeatureMips1: + selectArch("mips1"); + getTargetStreamer().emitDirectiveSetMips1(); + break; + case Mips::FeatureMips2: + selectArch("mips2"); + getTargetStreamer().emitDirectiveSetMips2(); + break; + case Mips::FeatureMips3: + selectArch("mips3"); + getTargetStreamer().emitDirectiveSetMips3(); + break; + case Mips::FeatureMips4: + selectArch("mips4"); + getTargetStreamer().emitDirectiveSetMips4(); + break; + case Mips::FeatureMips5: + selectArch("mips5"); + getTargetStreamer().emitDirectiveSetMips5(); + break; + case Mips::FeatureMips32: + selectArch("mips32"); + getTargetStreamer().emitDirectiveSetMips32(); + break; + case Mips::FeatureMips32r2: + selectArch("mips32r2"); + getTargetStreamer().emitDirectiveSetMips32R2(); + break; + case Mips::FeatureMips32r3: + selectArch("mips32r3"); + getTargetStreamer().emitDirectiveSetMips32R3(); + break; + case Mips::FeatureMips32r5: + selectArch("mips32r5"); + getTargetStreamer().emitDirectiveSetMips32R5(); + break; + case Mips::FeatureMips32r6: + selectArch("mips32r6"); + getTargetStreamer().emitDirectiveSetMips32R6(); + break; + case Mips::FeatureMips64: + selectArch("mips64"); + getTargetStreamer().emitDirectiveSetMips64(); + break; + case Mips::FeatureMips64r2: + selectArch("mips64r2"); + getTargetStreamer().emitDirectiveSetMips64R2(); + break; + case Mips::FeatureMips64r3: + selectArch("mips64r3"); + getTargetStreamer().emitDirectiveSetMips64R3(); + break; + case Mips::FeatureMips64r5: + selectArch("mips64r5"); + getTargetStreamer().emitDirectiveSetMips64R5(); + break; + case Mips::FeatureMips64r6: + selectArch("mips64r6"); + getTargetStreamer().emitDirectiveSetMips64R6(); + break; + } + return false; +} + +bool MipsAsmParser::eatComma(StringRef ErrorStr) { + MCAsmParser &Parser = getParser(); + if (getLexer().isNot(AsmToken::Comma)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, ErrorStr); + } + + Parser.Lex(); // Eat the comma. + return true; +} + +// Used to determine if .cpload, .cprestore, and .cpsetup have any effect. +// In this class, it is only used for .cprestore. +// FIXME: Only keep track of IsPicEnabled in one place, instead of in both +// MipsTargetELFStreamer and MipsAsmParser. +bool MipsAsmParser::isPicAndNotNxxAbi() { + return inPicMode() && !(isABI_N32() || isABI_N64()); +} + +bool MipsAsmParser::parseDirectiveCpLoad(SMLoc Loc) { + if (AssemblerOptions.back()->isReorder()) + Warning(Loc, ".cpload should be inside a noreorder section"); + + if (inMips16Mode()) { + reportParseError(".cpload is not supported in Mips16 mode"); + return false; + } + + SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> Reg; + OperandMatchResultTy ResTy = parseAnyRegister(Reg); + if (ResTy == MatchOperand_NoMatch || ResTy == MatchOperand_ParseFail) { + reportParseError("expected register containing function address"); + return false; + } + + MipsOperand &RegOpnd = static_cast<MipsOperand &>(*Reg[0]); + if (!RegOpnd.isGPRAsmReg()) { + reportParseError(RegOpnd.getStartLoc(), "invalid register"); + return false; + } + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + getTargetStreamer().emitDirectiveCpLoad(RegOpnd.getGPR32Reg()); + return false; +} + +bool MipsAsmParser::parseDirectiveCpRestore(SMLoc Loc) { + MCAsmParser &Parser = getParser(); + + // Note that .cprestore is ignored if used with the N32 and N64 ABIs or if it + // is used in non-PIC mode. + + if (inMips16Mode()) { + reportParseError(".cprestore is not supported in Mips16 mode"); + return false; + } + + // Get the stack offset value. + const MCExpr *StackOffset; + int64_t StackOffsetVal; + if (Parser.parseExpression(StackOffset)) { + reportParseError("expected stack offset value"); + return false; + } + + if (!StackOffset->evaluateAsAbsolute(StackOffsetVal)) { + reportParseError("stack offset is not an absolute expression"); + return false; + } + + if (StackOffsetVal < 0) { + Warning(Loc, ".cprestore with negative stack offset has no effect"); + IsCpRestoreSet = false; + } else { + IsCpRestoreSet = true; + CpRestoreOffset = StackOffsetVal; + } + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + // Store the $gp on the stack. + SmallVector<MCInst, 3> StoreInsts; + createCpRestoreMemOp(false /*IsLoad*/, CpRestoreOffset /*StackOffset*/, Loc, + StoreInsts); + + getTargetStreamer().emitDirectiveCpRestore(StoreInsts, CpRestoreOffset); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseDirectiveCPSetup() { + MCAsmParser &Parser = getParser(); + unsigned FuncReg; + unsigned Save; + bool SaveIsReg = true; + + SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> TmpReg; + OperandMatchResultTy ResTy = parseAnyRegister(TmpReg); + if (ResTy == MatchOperand_NoMatch) { + reportParseError("expected register containing function address"); + Parser.eatToEndOfStatement(); + return false; + } + + MipsOperand &FuncRegOpnd = static_cast<MipsOperand &>(*TmpReg[0]); + if (!FuncRegOpnd.isGPRAsmReg()) { + reportParseError(FuncRegOpnd.getStartLoc(), "invalid register"); + Parser.eatToEndOfStatement(); + return false; + } + + FuncReg = FuncRegOpnd.getGPR32Reg(); + TmpReg.clear(); + + if (!eatComma("unexpected token, expected comma")) + return true; + + ResTy = parseAnyRegister(TmpReg); + if (ResTy == MatchOperand_NoMatch) { + const MCExpr *OffsetExpr; + int64_t OffsetVal; + SMLoc ExprLoc = getLexer().getLoc(); + + if (Parser.parseExpression(OffsetExpr) || + !OffsetExpr->evaluateAsAbsolute(OffsetVal)) { + reportParseError(ExprLoc, "expected save register or stack offset"); + Parser.eatToEndOfStatement(); + return false; + } + + Save = OffsetVal; + SaveIsReg = false; + } else { + MipsOperand &SaveOpnd = static_cast<MipsOperand &>(*TmpReg[0]); + if (!SaveOpnd.isGPRAsmReg()) { + reportParseError(SaveOpnd.getStartLoc(), "invalid register"); + Parser.eatToEndOfStatement(); + return false; + } + Save = SaveOpnd.getGPR32Reg(); + } + + if (!eatComma("unexpected token, expected comma")) + return true; + + const MCExpr *Expr; + if (Parser.parseExpression(Expr)) { + reportParseError("expected expression"); + return false; + } + + if (Expr->getKind() != MCExpr::SymbolRef) { + reportParseError("expected symbol"); + return false; + } + const MCSymbolRefExpr *Ref = static_cast<const MCSymbolRefExpr *>(Expr); + + CpSaveLocation = Save; + CpSaveLocationIsRegister = SaveIsReg; + + getTargetStreamer().emitDirectiveCpsetup(FuncReg, Save, Ref->getSymbol(), + SaveIsReg); + return false; +} + +bool MipsAsmParser::parseDirectiveCPReturn() { + getTargetStreamer().emitDirectiveCpreturn(CpSaveLocation, + CpSaveLocationIsRegister); + return false; +} + +bool MipsAsmParser::parseDirectiveNaN() { + MCAsmParser &Parser = getParser(); + if (getLexer().isNot(AsmToken::EndOfStatement)) { + const AsmToken &Tok = Parser.getTok(); + + if (Tok.getString() == "2008") { + Parser.Lex(); + getTargetStreamer().emitDirectiveNaN2008(); + return false; + } else if (Tok.getString() == "legacy") { + Parser.Lex(); + getTargetStreamer().emitDirectiveNaNLegacy(); + return false; + } + } + // If we don't recognize the option passed to the .nan + // directive (e.g. no option or unknown option), emit an error. + reportParseError("invalid option in .nan directive"); + return false; +} + +bool MipsAsmParser::parseDirectiveSet() { + MCAsmParser &Parser = getParser(); + // Get the next token. + const AsmToken &Tok = Parser.getTok(); + + if (Tok.getString() == "noat") { + return parseSetNoAtDirective(); + } else if (Tok.getString() == "at") { + return parseSetAtDirective(); + } else if (Tok.getString() == "arch") { + return parseSetArchDirective(); + } else if (Tok.getString() == "fp") { + return parseSetFpDirective(); + } else if (Tok.getString() == "oddspreg") { + return parseSetOddSPRegDirective(); + } else if (Tok.getString() == "nooddspreg") { + return parseSetNoOddSPRegDirective(); + } else if (Tok.getString() == "pop") { + return parseSetPopDirective(); + } else if (Tok.getString() == "push") { + return parseSetPushDirective(); + } else if (Tok.getString() == "reorder") { + return parseSetReorderDirective(); + } else if (Tok.getString() == "noreorder") { + return parseSetNoReorderDirective(); + } else if (Tok.getString() == "macro") { + return parseSetMacroDirective(); + } else if (Tok.getString() == "nomacro") { + return parseSetNoMacroDirective(); + } else if (Tok.getString() == "mips16") { + return parseSetMips16Directive(); + } else if (Tok.getString() == "nomips16") { + return parseSetNoMips16Directive(); + } else if (Tok.getString() == "nomicromips") { + getTargetStreamer().emitDirectiveSetNoMicroMips(); + Parser.eatToEndOfStatement(); + return false; + } else if (Tok.getString() == "micromips") { + return parseSetFeature(Mips::FeatureMicroMips); + } else if (Tok.getString() == "mips0") { + return parseSetMips0Directive(); + } else if (Tok.getString() == "mips1") { + return parseSetFeature(Mips::FeatureMips1); + } else if (Tok.getString() == "mips2") { + return parseSetFeature(Mips::FeatureMips2); + } else if (Tok.getString() == "mips3") { + return parseSetFeature(Mips::FeatureMips3); + } else if (Tok.getString() == "mips4") { + return parseSetFeature(Mips::FeatureMips4); + } else if (Tok.getString() == "mips5") { + return parseSetFeature(Mips::FeatureMips5); + } else if (Tok.getString() == "mips32") { + return parseSetFeature(Mips::FeatureMips32); + } else if (Tok.getString() == "mips32r2") { + return parseSetFeature(Mips::FeatureMips32r2); + } else if (Tok.getString() == "mips32r3") { + return parseSetFeature(Mips::FeatureMips32r3); + } else if (Tok.getString() == "mips32r5") { + return parseSetFeature(Mips::FeatureMips32r5); + } else if (Tok.getString() == "mips32r6") { + return parseSetFeature(Mips::FeatureMips32r6); + } else if (Tok.getString() == "mips64") { + return parseSetFeature(Mips::FeatureMips64); + } else if (Tok.getString() == "mips64r2") { + return parseSetFeature(Mips::FeatureMips64r2); + } else if (Tok.getString() == "mips64r3") { + return parseSetFeature(Mips::FeatureMips64r3); + } else if (Tok.getString() == "mips64r5") { + return parseSetFeature(Mips::FeatureMips64r5); + } else if (Tok.getString() == "mips64r6") { + return parseSetFeature(Mips::FeatureMips64r6); + } else if (Tok.getString() == "dsp") { + return parseSetFeature(Mips::FeatureDSP); + } else if (Tok.getString() == "nodsp") { + return parseSetNoDspDirective(); + } else if (Tok.getString() == "msa") { + return parseSetMsaDirective(); + } else if (Tok.getString() == "nomsa") { + return parseSetNoMsaDirective(); + } else if (Tok.getString() == "softfloat") { + return parseSetSoftFloatDirective(); + } else if (Tok.getString() == "hardfloat") { + return parseSetHardFloatDirective(); + } else { + // It is just an identifier, look for an assignment. + parseSetAssignment(); + return false; + } + + return true; +} + +/// parseDataDirective +/// ::= .word [ expression (, expression)* ] +bool MipsAsmParser::parseDataDirective(unsigned Size, SMLoc L) { + MCAsmParser &Parser = getParser(); + if (getLexer().isNot(AsmToken::EndOfStatement)) { + for (;;) { + const MCExpr *Value; + if (getParser().parseExpression(Value)) + return true; + + getParser().getStreamer().EmitValue(Value, Size); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + if (getLexer().isNot(AsmToken::Comma)) + return Error(L, "unexpected token, expected comma"); + Parser.Lex(); + } + } + + Parser.Lex(); + return false; +} + +/// parseDirectiveGpWord +/// ::= .gpword local_sym +bool MipsAsmParser::parseDirectiveGpWord() { + MCAsmParser &Parser = getParser(); + const MCExpr *Value; + // EmitGPRel32Value requires an expression, so we are using base class + // method to evaluate the expression. + if (getParser().parseExpression(Value)) + return true; + getParser().getStreamer().EmitGPRel32Value(Value); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), + "unexpected token, expected end of statement"); + Parser.Lex(); // Eat EndOfStatement token. + return false; +} + +/// parseDirectiveGpDWord +/// ::= .gpdword local_sym +bool MipsAsmParser::parseDirectiveGpDWord() { + MCAsmParser &Parser = getParser(); + 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, expected end of statement"); + Parser.Lex(); // Eat EndOfStatement token. + return false; +} + +bool MipsAsmParser::parseDirectiveOption() { + MCAsmParser &Parser = getParser(); + // 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, expected identifier"); + Parser.eatToEndOfStatement(); + return false; + } + + StringRef Option = Tok.getIdentifier(); + + if (Option == "pic0") { + // MipsAsmParser needs to know if the current PIC mode changes. + IsPicEnabled = false; + + getTargetStreamer().emitDirectiveOptionPic0(); + Parser.Lex(); + if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { + Error(Parser.getTok().getLoc(), + "unexpected token, expected end of statement"); + Parser.eatToEndOfStatement(); + } + return false; + } + + if (Option == "pic2") { + // MipsAsmParser needs to know if the current PIC mode changes. + IsPicEnabled = true; + + getTargetStreamer().emitDirectiveOptionPic2(); + Parser.Lex(); + if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { + Error(Parser.getTok().getLoc(), + "unexpected token, expected end of statement"); + Parser.eatToEndOfStatement(); + } + return false; + } + + // Unknown option. + Warning(Parser.getTok().getLoc(), + "unknown option, expected 'pic0' or 'pic2'"); + Parser.eatToEndOfStatement(); + return false; +} + +/// parseInsnDirective +/// ::= .insn +bool MipsAsmParser::parseInsnDirective() { + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + // The actual label marking happens in + // MipsELFStreamer::createPendingLabelRelocs(). + getTargetStreamer().emitDirectiveInsn(); + + getParser().Lex(); // Eat EndOfStatement token. + return false; +} + +/// parseDirectiveModule +/// ::= .module oddspreg +/// ::= .module nooddspreg +/// ::= .module fp=value +/// ::= .module softfloat +/// ::= .module hardfloat +bool MipsAsmParser::parseDirectiveModule() { + MCAsmParser &Parser = getParser(); + MCAsmLexer &Lexer = getLexer(); + SMLoc L = Lexer.getLoc(); + + if (!getTargetStreamer().isModuleDirectiveAllowed()) { + // TODO : get a better message. + reportParseError(".module directive must appear before any code"); + return false; + } + + StringRef Option; + if (Parser.parseIdentifier(Option)) { + reportParseError("expected .module option identifier"); + return false; + } + + if (Option == "oddspreg") { + clearModuleFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg"); + + // Synchronize the abiflags information with the FeatureBits information we + // changed above. + getTargetStreamer().updateABIInfo(*this); + + // If printing assembly, use the recently updated abiflags information. + // If generating ELF, don't do anything (the .MIPS.abiflags section gets + // emitted at the end). + getTargetStreamer().emitDirectiveModuleOddSPReg(); + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + return false; // parseDirectiveModule has finished successfully. + } else if (Option == "nooddspreg") { + if (!isABI_O32()) { + Error(L, "'.module nooddspreg' requires the O32 ABI"); + return false; + } + + setModuleFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg"); + + // Synchronize the abiflags information with the FeatureBits information we + // changed above. + getTargetStreamer().updateABIInfo(*this); + + // If printing assembly, use the recently updated abiflags information. + // If generating ELF, don't do anything (the .MIPS.abiflags section gets + // emitted at the end). + getTargetStreamer().emitDirectiveModuleOddSPReg(); + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + return false; // parseDirectiveModule has finished successfully. + } else if (Option == "fp") { + return parseDirectiveModuleFP(); + } else if (Option == "softfloat") { + setModuleFeatureBits(Mips::FeatureSoftFloat, "soft-float"); + + // Synchronize the ABI Flags information with the FeatureBits information we + // updated above. + getTargetStreamer().updateABIInfo(*this); + + // If printing assembly, use the recently updated ABI Flags information. + // If generating ELF, don't do anything (the .MIPS.abiflags section gets + // emitted later). + getTargetStreamer().emitDirectiveModuleSoftFloat(); + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + return false; // parseDirectiveModule has finished successfully. + } else if (Option == "hardfloat") { + clearModuleFeatureBits(Mips::FeatureSoftFloat, "soft-float"); + + // Synchronize the ABI Flags information with the FeatureBits information we + // updated above. + getTargetStreamer().updateABIInfo(*this); + + // If printing assembly, use the recently updated ABI Flags information. + // If generating ELF, don't do anything (the .MIPS.abiflags section gets + // emitted later). + getTargetStreamer().emitDirectiveModuleHardFloat(); + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + return false; // parseDirectiveModule has finished successfully. + } else { + return Error(L, "'" + Twine(Option) + "' is not a valid .module option."); + } +} + +/// parseDirectiveModuleFP +/// ::= =32 +/// ::= =xx +/// ::= =64 +bool MipsAsmParser::parseDirectiveModuleFP() { + MCAsmParser &Parser = getParser(); + MCAsmLexer &Lexer = getLexer(); + + if (Lexer.isNot(AsmToken::Equal)) { + reportParseError("unexpected token, expected equals sign '='"); + return false; + } + Parser.Lex(); // Eat '=' token. + + MipsABIFlagsSection::FpABIKind FpABI; + if (!parseFpABIValue(FpABI, ".module")) + return false; + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + // Synchronize the abiflags information with the FeatureBits information we + // changed above. + getTargetStreamer().updateABIInfo(*this); + + // If printing assembly, use the recently updated abiflags information. + // If generating ELF, don't do anything (the .MIPS.abiflags section gets + // emitted at the end). + getTargetStreamer().emitDirectiveModuleFP(); + + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI, + StringRef Directive) { + MCAsmParser &Parser = getParser(); + MCAsmLexer &Lexer = getLexer(); + bool ModuleLevelOptions = Directive == ".module"; + + if (Lexer.is(AsmToken::Identifier)) { + StringRef Value = Parser.getTok().getString(); + Parser.Lex(); + + if (Value != "xx") { + reportParseError("unsupported value, expected 'xx', '32' or '64'"); + return false; + } + + if (!isABI_O32()) { + reportParseError("'" + Directive + " fp=xx' requires the O32 ABI"); + return false; + } + + FpABI = MipsABIFlagsSection::FpABIKind::XX; + if (ModuleLevelOptions) { + setModuleFeatureBits(Mips::FeatureFPXX, "fpxx"); + clearModuleFeatureBits(Mips::FeatureFP64Bit, "fp64"); + } else { + setFeatureBits(Mips::FeatureFPXX, "fpxx"); + clearFeatureBits(Mips::FeatureFP64Bit, "fp64"); + } + return true; + } + + if (Lexer.is(AsmToken::Integer)) { + unsigned Value = Parser.getTok().getIntVal(); + Parser.Lex(); + + if (Value != 32 && Value != 64) { + reportParseError("unsupported value, expected 'xx', '32' or '64'"); + return false; + } + + if (Value == 32) { + if (!isABI_O32()) { + reportParseError("'" + Directive + " fp=32' requires the O32 ABI"); + return false; + } + + FpABI = MipsABIFlagsSection::FpABIKind::S32; + if (ModuleLevelOptions) { + clearModuleFeatureBits(Mips::FeatureFPXX, "fpxx"); + clearModuleFeatureBits(Mips::FeatureFP64Bit, "fp64"); + } else { + clearFeatureBits(Mips::FeatureFPXX, "fpxx"); + clearFeatureBits(Mips::FeatureFP64Bit, "fp64"); + } + } else { + FpABI = MipsABIFlagsSection::FpABIKind::S64; + if (ModuleLevelOptions) { + clearModuleFeatureBits(Mips::FeatureFPXX, "fpxx"); + setModuleFeatureBits(Mips::FeatureFP64Bit, "fp64"); + } else { + clearFeatureBits(Mips::FeatureFPXX, "fpxx"); + setFeatureBits(Mips::FeatureFP64Bit, "fp64"); + } + } + + return true; + } + + return false; +} + +bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { + MCAsmParser &Parser = getParser(); + StringRef IDVal = DirectiveID.getString(); + + if (IDVal == ".cpload") + return parseDirectiveCpLoad(DirectiveID.getLoc()); + if (IDVal == ".cprestore") + return parseDirectiveCpRestore(DirectiveID.getLoc()); + if (IDVal == ".dword") { + parseDataDirective(8, DirectiveID.getLoc()); + return false; + } + if (IDVal == ".ent") { + StringRef SymbolName; + + if (Parser.parseIdentifier(SymbolName)) { + reportParseError("expected identifier after .ent"); + return false; + } + + // There's an undocumented extension that allows an integer to + // follow the name of the procedure which AFAICS is ignored by GAS. + // Example: .ent foo,2 + if (getLexer().isNot(AsmToken::EndOfStatement)) { + if (getLexer().isNot(AsmToken::Comma)) { + // Even though we accept this undocumented extension for compatibility + // reasons, the additional integer argument does not actually change + // the behaviour of the '.ent' directive, so we would like to discourage + // its use. We do this by not referring to the extended version in + // error messages which are not directly related to its use. + reportParseError("unexpected token, expected end of statement"); + return false; + } + Parser.Lex(); // Eat the comma. + const MCExpr *DummyNumber; + int64_t DummyNumberVal; + // If the user was explicitly trying to use the extended version, + // we still give helpful extension-related error messages. + if (Parser.parseExpression(DummyNumber)) { + reportParseError("expected number after comma"); + return false; + } + if (!DummyNumber->evaluateAsAbsolute(DummyNumberVal)) { + reportParseError("expected an absolute expression after comma"); + return false; + } + } + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName); + + getTargetStreamer().emitDirectiveEnt(*Sym); + CurrentFn = Sym; + IsCpRestoreSet = false; + return false; + } + + if (IDVal == ".end") { + StringRef SymbolName; + + if (Parser.parseIdentifier(SymbolName)) { + reportParseError("expected identifier after .end"); + return false; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + if (CurrentFn == nullptr) { + reportParseError(".end used without .ent"); + return false; + } + + if ((SymbolName != CurrentFn->getName())) { + reportParseError(".end symbol does not match .ent symbol"); + return false; + } + + getTargetStreamer().emitDirectiveEnd(SymbolName); + CurrentFn = nullptr; + IsCpRestoreSet = false; + return false; + } + + if (IDVal == ".frame") { + // .frame $stack_reg, frame_size_in_bytes, $return_reg + SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> TmpReg; + OperandMatchResultTy ResTy = parseAnyRegister(TmpReg); + if (ResTy == MatchOperand_NoMatch || ResTy == MatchOperand_ParseFail) { + reportParseError("expected stack register"); + return false; + } + + MipsOperand &StackRegOpnd = static_cast<MipsOperand &>(*TmpReg[0]); + if (!StackRegOpnd.isGPRAsmReg()) { + reportParseError(StackRegOpnd.getStartLoc(), + "expected general purpose register"); + return false; + } + unsigned StackReg = StackRegOpnd.getGPR32Reg(); + + if (Parser.getTok().is(AsmToken::Comma)) + Parser.Lex(); + else { + reportParseError("unexpected token, expected comma"); + return false; + } + + // Parse the frame size. + const MCExpr *FrameSize; + int64_t FrameSizeVal; + + if (Parser.parseExpression(FrameSize)) { + reportParseError("expected frame size value"); + return false; + } + + if (!FrameSize->evaluateAsAbsolute(FrameSizeVal)) { + reportParseError("frame size not an absolute expression"); + return false; + } + + if (Parser.getTok().is(AsmToken::Comma)) + Parser.Lex(); + else { + reportParseError("unexpected token, expected comma"); + return false; + } + + // Parse the return register. + TmpReg.clear(); + ResTy = parseAnyRegister(TmpReg); + if (ResTy == MatchOperand_NoMatch || ResTy == MatchOperand_ParseFail) { + reportParseError("expected return register"); + return false; + } + + MipsOperand &ReturnRegOpnd = static_cast<MipsOperand &>(*TmpReg[0]); + if (!ReturnRegOpnd.isGPRAsmReg()) { + reportParseError(ReturnRegOpnd.getStartLoc(), + "expected general purpose register"); + return false; + } + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + getTargetStreamer().emitFrame(StackReg, FrameSizeVal, + ReturnRegOpnd.getGPR32Reg()); + IsCpRestoreSet = false; + return false; + } + + if (IDVal == ".set") { + return parseDirectiveSet(); + } + + if (IDVal == ".mask" || IDVal == ".fmask") { + // .mask bitmask, frame_offset + // bitmask: One bit for each register used. + // frame_offset: Offset from Canonical Frame Address ($sp on entry) where + // first register is expected to be saved. + // Examples: + // .mask 0x80000000, -4 + // .fmask 0x80000000, -4 + // + + // Parse the bitmask + const MCExpr *BitMask; + int64_t BitMaskVal; + + if (Parser.parseExpression(BitMask)) { + reportParseError("expected bitmask value"); + return false; + } + + if (!BitMask->evaluateAsAbsolute(BitMaskVal)) { + reportParseError("bitmask not an absolute expression"); + return false; + } + + if (Parser.getTok().is(AsmToken::Comma)) + Parser.Lex(); + else { + reportParseError("unexpected token, expected comma"); + return false; + } + + // Parse the frame_offset + const MCExpr *FrameOffset; + int64_t FrameOffsetVal; + + if (Parser.parseExpression(FrameOffset)) { + reportParseError("expected frame offset value"); + return false; + } + + if (!FrameOffset->evaluateAsAbsolute(FrameOffsetVal)) { + reportParseError("frame offset not an absolute expression"); + return false; + } + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + if (IDVal == ".mask") + getTargetStreamer().emitMask(BitMaskVal, FrameOffsetVal); + else + getTargetStreamer().emitFMask(BitMaskVal, FrameOffsetVal); + return false; + } + + if (IDVal == ".nan") + return parseDirectiveNaN(); + + if (IDVal == ".gpword") { + parseDirectiveGpWord(); + return false; + } + + if (IDVal == ".gpdword") { + parseDirectiveGpDWord(); + return false; + } + + if (IDVal == ".word") { + parseDataDirective(4, DirectiveID.getLoc()); + return false; + } + + if (IDVal == ".option") + return parseDirectiveOption(); + + if (IDVal == ".abicalls") { + getTargetStreamer().emitDirectiveAbiCalls(); + if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { + Error(Parser.getTok().getLoc(), + "unexpected token, expected end of statement"); + // Clear line + Parser.eatToEndOfStatement(); + } + return false; + } + + if (IDVal == ".cpsetup") + return parseDirectiveCPSetup(); + + if (IDVal == ".cpreturn") + return parseDirectiveCPReturn(); + + if (IDVal == ".module") + return parseDirectiveModule(); + + if (IDVal == ".llvm_internal_mips_reallow_module_directive") + return parseInternalDirectiveReallowModule(); + + if (IDVal == ".insn") + return parseInsnDirective(); + + return true; +} + +bool MipsAsmParser::parseInternalDirectiveReallowModule() { + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + getTargetStreamer().reallowModuleDirective(); + + getParser().Lex(); // Eat EndOfStatement token. + return false; +} + +extern "C" void LLVMInitializeMipsAsmParser() { + RegisterMCAsmParser<MipsAsmParser> X(TheMipsTarget); + RegisterMCAsmParser<MipsAsmParser> Y(TheMipselTarget); + RegisterMCAsmParser<MipsAsmParser> A(TheMips64Target); + RegisterMCAsmParser<MipsAsmParser> B(TheMips64elTarget); +} + +#define GET_REGISTER_MATCHER +#define GET_MATCHER_IMPLEMENTATION +#include "MipsGenAsmMatcher.inc" diff --git a/contrib/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp b/contrib/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp new file mode 100644 index 0000000..3c1a771 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp @@ -0,0 +1,2107 @@ +//===- MipsDisassembler.cpp - Disassembler for Mips -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is part of the Mips Disassembler. +// +//===----------------------------------------------------------------------===// + +#include "Mips.h" +#include "MipsRegisterInfo.h" +#include "MipsSubtarget.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCFixedLenDisassembler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +#define DEBUG_TYPE "mips-disassembler" + +typedef MCDisassembler::DecodeStatus DecodeStatus; + +namespace { + +class MipsDisassembler : public MCDisassembler { + bool IsMicroMips; + bool IsBigEndian; +public: + MipsDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, bool IsBigEndian) + : MCDisassembler(STI, Ctx), + IsMicroMips(STI.getFeatureBits()[Mips::FeatureMicroMips]), + IsBigEndian(IsBigEndian) {} + + bool hasMips3() const { return STI.getFeatureBits()[Mips::FeatureMips3]; } + bool hasMips32() const { return STI.getFeatureBits()[Mips::FeatureMips32]; } + bool hasMips32r6() const { + return STI.getFeatureBits()[Mips::FeatureMips32r6]; + } + + bool isGP64() const { return STI.getFeatureBits()[Mips::FeatureGP64Bit]; } + + bool hasCnMips() const { return STI.getFeatureBits()[Mips::FeatureCnMips]; } + + bool hasCOP3() const { + // Only present in MIPS-I and MIPS-II + return !hasMips32() && !hasMips3(); + } + + DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, + ArrayRef<uint8_t> Bytes, uint64_t Address, + raw_ostream &VStream, + raw_ostream &CStream) const override; +}; + +} // end anonymous namespace + +// Forward declare these because the autogenerated code will reference them. +// Definitions are further down. +static DecodeStatus DecodeGPR64RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeCPU16RegsRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeGPRMM16RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeGPRMM16ZeroRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeGPRMM16MovePRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeGPR32RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodePtrRegisterClass(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeDSPRRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeFGR64RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeFGR32RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeCCRRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeFCCRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeFGRCCRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeHWRegsRegisterClass(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeAFGR64RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeACC64DSPRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeHI32DSPRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeLO32DSPRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMSA128BRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMSA128HRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMSA128WRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMSA128DRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMSACtrlRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeCOP0RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeCOP2RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeBranchTarget(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeJumpTarget(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeBranchTarget21(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeBranchTarget26(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder); + +// DecodeBranchTarget7MM - Decode microMIPS branch offset, which is +// shifted left by 1 bit. +static DecodeStatus DecodeBranchTarget7MM(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder); + +// DecodeBranchTarget10MM - Decode microMIPS branch offset, which is +// shifted left by 1 bit. +static DecodeStatus DecodeBranchTarget10MM(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder); + +// DecodeBranchTargetMM - Decode microMIPS branch offset, which is +// shifted left by 1 bit. +static DecodeStatus DecodeBranchTargetMM(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder); + +// DecodeBranchTarget26MM - Decode microMIPS branch offset, which is +// shifted left by 1 bit. +static DecodeStatus DecodeBranchTarget26MM(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder); + +// DecodeJumpTargetMM - Decode microMIPS jump target, which is +// shifted left by 1 bit. +static DecodeStatus DecodeJumpTargetMM(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMem(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMemEVA(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeLoadByte9(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeLoadByte15(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeCacheOp(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeCacheeOp_CacheOpR6(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeCacheOpMM(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeStoreEvaOpMM(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodePrefeOpMM(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeSyncI(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeSynciR6(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMSA128Mem(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); + +static DecodeStatus DecodeMemMMImm4(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMemMMSPImm5Lsl2(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMemMMGPImm7Lsl2(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMemMMReglistImm4Lsl2(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMemMMImm9(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMemMMImm12(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMemMMImm16(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeFMem(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeFMem2(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeFMem3(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeFMemCop2R6(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeSpecial3LlSc(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeAddiur2Simm7(MCInst &Inst, + unsigned Value, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeUImm6Lsl2(MCInst &Inst, + unsigned Value, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeLiSimm7(MCInst &Inst, + unsigned Value, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodePOOL16BEncodedField(MCInst &Inst, + unsigned Value, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeSimm4(MCInst &Inst, + unsigned Value, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeSimm16(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +template <unsigned Bits, int Offset> +static DecodeStatus DecodeUImmWithOffset(MCInst &Inst, unsigned Value, + uint64_t Address, const void *Decoder); + +static DecodeStatus DecodeInsSize(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeSimm19Lsl2(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); + +static DecodeStatus DecodeSimm18Lsl3(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); + +static DecodeStatus DecodeSimm9SP(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); + +static DecodeStatus DecodeANDI16Imm(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); + +static DecodeStatus DecodeUImm5lsl2(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); + +static DecodeStatus DecodeSimm23Lsl2(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); + +/// INSVE_[BHWD] have an implicit operand that the generated decoder doesn't +/// handle. +template <typename InsnType> +static DecodeStatus DecodeINSVE_DF(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template <typename InsnType> +static DecodeStatus +DecodeAddiGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template <typename InsnType> +static DecodeStatus +DecodeDaddiGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template <typename InsnType> +static DecodeStatus +DecodeBlezlGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template <typename InsnType> +static DecodeStatus +DecodeBgtzlGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template <typename InsnType> +static DecodeStatus +DecodeBgtzGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template <typename InsnType> +static DecodeStatus +DecodeBlezGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeRegListOperand(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeRegListOperand16(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMovePRegPair(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder); + +namespace llvm { +extern Target TheMipselTarget, TheMipsTarget, TheMips64Target, + TheMips64elTarget; +} + +static MCDisassembler *createMipsDisassembler( + const Target &T, + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new MipsDisassembler(STI, Ctx, true); +} + +static MCDisassembler *createMipselDisassembler( + const Target &T, + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new MipsDisassembler(STI, Ctx, false); +} + +extern "C" void LLVMInitializeMipsDisassembler() { + // Register the disassembler. + TargetRegistry::RegisterMCDisassembler(TheMipsTarget, + createMipsDisassembler); + TargetRegistry::RegisterMCDisassembler(TheMipselTarget, + createMipselDisassembler); + TargetRegistry::RegisterMCDisassembler(TheMips64Target, + createMipsDisassembler); + TargetRegistry::RegisterMCDisassembler(TheMips64elTarget, + createMipselDisassembler); +} + +#include "MipsGenDisassemblerTables.inc" + +static unsigned getReg(const void *D, unsigned RC, unsigned RegNo) { + const MipsDisassembler *Dis = static_cast<const MipsDisassembler*>(D); + const MCRegisterInfo *RegInfo = Dis->getContext().getRegisterInfo(); + return *(RegInfo->getRegClass(RC).begin() + RegNo); +} + +template <typename InsnType> +static DecodeStatus DecodeINSVE_DF(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder) { + typedef DecodeStatus (*DecodeFN)(MCInst &, unsigned, uint64_t, const void *); + // The size of the n field depends on the element size + // The register class also depends on this. + InsnType tmp = fieldFromInstruction(insn, 17, 5); + unsigned NSize = 0; + DecodeFN RegDecoder = nullptr; + if ((tmp & 0x18) == 0x00) { // INSVE_B + NSize = 4; + RegDecoder = DecodeMSA128BRegisterClass; + } else if ((tmp & 0x1c) == 0x10) { // INSVE_H + NSize = 3; + RegDecoder = DecodeMSA128HRegisterClass; + } else if ((tmp & 0x1e) == 0x18) { // INSVE_W + NSize = 2; + RegDecoder = DecodeMSA128WRegisterClass; + } else if ((tmp & 0x1f) == 0x1c) { // INSVE_D + NSize = 1; + RegDecoder = DecodeMSA128DRegisterClass; + } else + llvm_unreachable("Invalid encoding"); + + assert(NSize != 0 && RegDecoder != nullptr); + + // $wd + tmp = fieldFromInstruction(insn, 6, 5); + if (RegDecoder(MI, tmp, Address, Decoder) == MCDisassembler::Fail) + return MCDisassembler::Fail; + // $wd_in + if (RegDecoder(MI, tmp, Address, Decoder) == MCDisassembler::Fail) + return MCDisassembler::Fail; + // $n + tmp = fieldFromInstruction(insn, 16, NSize); + MI.addOperand(MCOperand::createImm(tmp)); + // $ws + tmp = fieldFromInstruction(insn, 11, 5); + if (RegDecoder(MI, tmp, Address, Decoder) == MCDisassembler::Fail) + return MCDisassembler::Fail; + // $n2 + MI.addOperand(MCOperand::createImm(0)); + + return MCDisassembler::Success; +} + +template <typename InsnType> +static DecodeStatus DecodeAddiGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the ADDI instruction from the earlier + // ISA's instead). + // + // We have: + // 0b001000 sssss ttttt iiiiiiiiiiiiiiii + // BOVC if rs >= rt + // BEQZALC if rs == 0 && rt != 0 + // BEQC if rs < rt && rs != 0 + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4; + bool HasRs = false; + + if (Rs >= Rt) { + MI.setOpcode(Mips::BOVC); + HasRs = true; + } else if (Rs != 0 && Rs < Rt) { + MI.setOpcode(Mips::BEQC); + HasRs = true; + } else + MI.setOpcode(Mips::BEQZALC); + + if (HasRs) + MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + + MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + MI.addOperand(MCOperand::createImm(Imm)); + + return MCDisassembler::Success; +} + +template <typename InsnType> +static DecodeStatus DecodeDaddiGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the ADDI instruction from the earlier + // ISA's instead). + // + // We have: + // 0b011000 sssss ttttt iiiiiiiiiiiiiiii + // BNVC if rs >= rt + // BNEZALC if rs == 0 && rt != 0 + // BNEC if rs < rt && rs != 0 + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4; + bool HasRs = false; + + if (Rs >= Rt) { + MI.setOpcode(Mips::BNVC); + HasRs = true; + } else if (Rs != 0 && Rs < Rt) { + MI.setOpcode(Mips::BNEC); + HasRs = true; + } else + MI.setOpcode(Mips::BNEZALC); + + if (HasRs) + MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + + MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + MI.addOperand(MCOperand::createImm(Imm)); + + return MCDisassembler::Success; +} + +template <typename InsnType> +static DecodeStatus DecodeBlezlGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the BLEZL instruction from the earlier + // ISA's instead). + // + // We have: + // 0b010110 sssss ttttt iiiiiiiiiiiiiiii + // Invalid if rs == 0 + // BLEZC if rs == 0 && rt != 0 + // BGEZC if rs == rt && rt != 0 + // BGEC if rs != rt && rs != 0 && rt != 0 + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4; + bool HasRs = false; + + if (Rt == 0) + return MCDisassembler::Fail; + else if (Rs == 0) + MI.setOpcode(Mips::BLEZC); + else if (Rs == Rt) + MI.setOpcode(Mips::BGEZC); + else { + HasRs = true; + MI.setOpcode(Mips::BGEC); + } + + if (HasRs) + MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + + MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + + MI.addOperand(MCOperand::createImm(Imm)); + + return MCDisassembler::Success; +} + +template <typename InsnType> +static DecodeStatus DecodeBgtzlGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the BGTZL instruction from the earlier + // ISA's instead). + // + // We have: + // 0b010111 sssss ttttt iiiiiiiiiiiiiiii + // Invalid if rs == 0 + // BGTZC if rs == 0 && rt != 0 + // BLTZC if rs == rt && rt != 0 + // BLTC if rs != rt && rs != 0 && rt != 0 + + bool HasRs = false; + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4; + + if (Rt == 0) + return MCDisassembler::Fail; + else if (Rs == 0) + MI.setOpcode(Mips::BGTZC); + else if (Rs == Rt) + MI.setOpcode(Mips::BLTZC); + else { + MI.setOpcode(Mips::BLTC); + HasRs = true; + } + + if (HasRs) + MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + + MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + + MI.addOperand(MCOperand::createImm(Imm)); + + return MCDisassembler::Success; +} + +template <typename InsnType> +static DecodeStatus DecodeBgtzGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the BGTZ instruction from the earlier + // ISA's instead). + // + // We have: + // 0b000111 sssss ttttt iiiiiiiiiiiiiiii + // BGTZ if rt == 0 + // BGTZALC if rs == 0 && rt != 0 + // BLTZALC if rs != 0 && rs == rt + // BLTUC if rs != 0 && rs != rt + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4; + bool HasRs = false; + bool HasRt = false; + + if (Rt == 0) { + MI.setOpcode(Mips::BGTZ); + HasRs = true; + } else if (Rs == 0) { + MI.setOpcode(Mips::BGTZALC); + HasRt = true; + } else if (Rs == Rt) { + MI.setOpcode(Mips::BLTZALC); + HasRs = true; + } else { + MI.setOpcode(Mips::BLTUC); + HasRs = true; + HasRt = true; + } + + if (HasRs) + MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + + if (HasRt) + MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + + MI.addOperand(MCOperand::createImm(Imm)); + + return MCDisassembler::Success; +} + +template <typename InsnType> +static DecodeStatus DecodeBlezGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the BLEZL instruction from the earlier + // ISA's instead). + // + // We have: + // 0b000110 sssss ttttt iiiiiiiiiiiiiiii + // Invalid if rs == 0 + // BLEZALC if rs == 0 && rt != 0 + // BGEZALC if rs == rt && rt != 0 + // BGEUC if rs != rt && rs != 0 && rt != 0 + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4; + bool HasRs = false; + + if (Rt == 0) + return MCDisassembler::Fail; + else if (Rs == 0) + MI.setOpcode(Mips::BLEZALC); + else if (Rs == Rt) + MI.setOpcode(Mips::BGEZALC); + else { + HasRs = true; + MI.setOpcode(Mips::BGEUC); + } + + if (HasRs) + MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + + MI.addOperand(MCOperand::createImm(Imm)); + + return MCDisassembler::Success; +} + +/// Read two bytes from the ArrayRef and return 16 bit halfword sorted +/// according to the given endianess. +static DecodeStatus readInstruction16(ArrayRef<uint8_t> Bytes, uint64_t Address, + uint64_t &Size, uint32_t &Insn, + bool IsBigEndian) { + // We want to read exactly 2 Bytes of data. + if (Bytes.size() < 2) { + Size = 0; + return MCDisassembler::Fail; + } + + if (IsBigEndian) { + Insn = (Bytes[0] << 8) | Bytes[1]; + } else { + Insn = (Bytes[1] << 8) | Bytes[0]; + } + + return MCDisassembler::Success; +} + +/// Read four bytes from the ArrayRef and return 32 bit word sorted +/// according to the given endianess +static DecodeStatus readInstruction32(ArrayRef<uint8_t> Bytes, uint64_t Address, + uint64_t &Size, uint32_t &Insn, + bool IsBigEndian, bool IsMicroMips) { + // We want to read exactly 4 Bytes of data. + if (Bytes.size() < 4) { + Size = 0; + return MCDisassembler::Fail; + } + + // High 16 bits of a 32-bit microMIPS instruction (where the opcode is) + // always precede the low 16 bits in the instruction stream (that is, they + // are placed at lower addresses in the instruction stream). + // + // microMIPS byte ordering: + // Big-endian: 0 | 1 | 2 | 3 + // Little-endian: 1 | 0 | 3 | 2 + + if (IsBigEndian) { + // Encoded as a big-endian 32-bit word in the stream. + Insn = + (Bytes[3] << 0) | (Bytes[2] << 8) | (Bytes[1] << 16) | (Bytes[0] << 24); + } else { + if (IsMicroMips) { + Insn = (Bytes[2] << 0) | (Bytes[3] << 8) | (Bytes[0] << 16) | + (Bytes[1] << 24); + } else { + Insn = (Bytes[0] << 0) | (Bytes[1] << 8) | (Bytes[2] << 16) | + (Bytes[3] << 24); + } + } + + return MCDisassembler::Success; +} + +DecodeStatus MipsDisassembler::getInstruction(MCInst &Instr, uint64_t &Size, + ArrayRef<uint8_t> Bytes, + uint64_t Address, + raw_ostream &VStream, + raw_ostream &CStream) const { + uint32_t Insn; + DecodeStatus Result; + + if (IsMicroMips) { + Result = readInstruction16(Bytes, Address, Size, Insn, IsBigEndian); + if (Result == MCDisassembler::Fail) + return MCDisassembler::Fail; + + if (hasMips32r6()) { + DEBUG(dbgs() << "Trying MicroMipsR616 table (16-bit instructions):\n"); + // Calling the auto-generated decoder function for microMIPS32R6 + // (and microMIPS64R6) 16-bit instructions. + Result = decodeInstruction(DecoderTableMicroMipsR616, Instr, Insn, + Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 2; + return Result; + } + } + + DEBUG(dbgs() << "Trying MicroMips16 table (16-bit instructions):\n"); + // Calling the auto-generated decoder function for microMIPS 16-bit + // instructions. + Result = decodeInstruction(DecoderTableMicroMips16, Instr, Insn, Address, + this, STI); + if (Result != MCDisassembler::Fail) { + Size = 2; + return Result; + } + + Result = readInstruction32(Bytes, Address, Size, Insn, IsBigEndian, true); + if (Result == MCDisassembler::Fail) + return MCDisassembler::Fail; + + if (hasMips32r6()) { + DEBUG(dbgs() << "Trying MicroMips32r632 table (32-bit instructions):\n"); + // Calling the auto-generated decoder function. + Result = decodeInstruction(DecoderTableMicroMipsR632, Instr, Insn, Address, + this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + } + + DEBUG(dbgs() << "Trying MicroMips32 table (32-bit instructions):\n"); + // Calling the auto-generated decoder function. + Result = decodeInstruction(DecoderTableMicroMips32, Instr, Insn, Address, + this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + // This is an invalid instruction. Let the disassembler move forward by the + // minimum instruction size. + Size = 2; + return MCDisassembler::Fail; + } + + Result = readInstruction32(Bytes, Address, Size, Insn, IsBigEndian, false); + if (Result == MCDisassembler::Fail) { + Size = 4; + return MCDisassembler::Fail; + } + + if (hasCOP3()) { + DEBUG(dbgs() << "Trying COP3_ table (32-bit opcodes):\n"); + Result = + decodeInstruction(DecoderTableCOP3_32, Instr, Insn, Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + } + + if (hasMips32r6() && isGP64()) { + DEBUG(dbgs() << "Trying Mips32r6_64r6 (GPR64) table (32-bit opcodes):\n"); + Result = decodeInstruction(DecoderTableMips32r6_64r6_GP6432, Instr, Insn, + Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + } + + if (hasMips32r6()) { + DEBUG(dbgs() << "Trying Mips32r6_64r6 table (32-bit opcodes):\n"); + Result = decodeInstruction(DecoderTableMips32r6_64r632, Instr, Insn, + Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + } + + if (hasCnMips()) { + DEBUG(dbgs() << "Trying CnMips table (32-bit opcodes):\n"); + Result = decodeInstruction(DecoderTableCnMips32, Instr, Insn, + Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + } + + if (isGP64()) { + DEBUG(dbgs() << "Trying Mips64 (GPR64) table (32-bit opcodes):\n"); + Result = decodeInstruction(DecoderTableMips6432, Instr, Insn, + Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + } + + DEBUG(dbgs() << "Trying Mips table (32-bit opcodes):\n"); + // Calling the auto-generated decoder function. + Result = + decodeInstruction(DecoderTableMips32, Instr, Insn, Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + + Size = 4; + return MCDisassembler::Fail; +} + +static DecodeStatus DecodeCPU16RegsRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + + return MCDisassembler::Fail; + +} + +static DecodeStatus DecodeGPR64RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::GPR64RegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeGPRMM16RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 7) + return MCDisassembler::Fail; + unsigned Reg = getReg(Decoder, Mips::GPRMM16RegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeGPRMM16ZeroRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 7) + return MCDisassembler::Fail; + unsigned Reg = getReg(Decoder, Mips::GPRMM16ZeroRegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeGPRMM16MovePRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 7) + return MCDisassembler::Fail; + unsigned Reg = getReg(Decoder, Mips::GPRMM16MovePRegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeGPR32RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + unsigned Reg = getReg(Decoder, Mips::GPR32RegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodePtrRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (static_cast<const MipsDisassembler *>(Decoder)->isGP64()) + return DecodeGPR64RegisterClass(Inst, RegNo, Address, Decoder); + + return DecodeGPR32RegisterClass(Inst, RegNo, Address, Decoder); +} + +static DecodeStatus DecodeDSPRRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + return DecodeGPR32RegisterClass(Inst, RegNo, Address, Decoder); +} + +static DecodeStatus DecodeFGR64RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::FGR64RegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeFGR32RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::FGR32RegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeCCRRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + unsigned Reg = getReg(Decoder, Mips::CCRRegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeFCCRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 7) + return MCDisassembler::Fail; + unsigned Reg = getReg(Decoder, Mips::FCCRegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeFGRCCRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::FGRCCRegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMem(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<16>(Insn & 0xffff); + unsigned Reg = fieldFromInstruction(Insn, 16, 5); + unsigned Base = fieldFromInstruction(Insn, 21, 5); + + Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + if (Inst.getOpcode() == Mips::SC || + Inst.getOpcode() == Mips::SCD) + Inst.addOperand(MCOperand::createReg(Reg)); + + Inst.addOperand(MCOperand::createReg(Reg)); + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMemEVA(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<9>(Insn >> 7); + unsigned Reg = fieldFromInstruction(Insn, 16, 5); + unsigned Base = fieldFromInstruction(Insn, 21, 5); + + Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + if (Inst.getOpcode() == Mips::SCE) + Inst.addOperand(MCOperand::createReg(Reg)); + + Inst.addOperand(MCOperand::createReg(Reg)); + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeLoadByte9(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<9>(Insn & 0x1ff); + unsigned Base = fieldFromInstruction(Insn, 16, 5); + unsigned Reg = fieldFromInstruction(Insn, 21, 5); + + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg); + + Inst.addOperand(MCOperand::createReg(Reg)); + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeLoadByte15(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<16>(Insn & 0xffff); + unsigned Base = fieldFromInstruction(Insn, 16, 5); + unsigned Reg = fieldFromInstruction(Insn, 21, 5); + + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg); + + Inst.addOperand(MCOperand::createReg(Reg)); + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeCacheOp(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<16>(Insn & 0xffff); + unsigned Hint = fieldFromInstruction(Insn, 16, 5); + unsigned Base = fieldFromInstruction(Insn, 21, 5); + + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + Inst.addOperand(MCOperand::createImm(Hint)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeCacheOpMM(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<12>(Insn & 0xfff); + unsigned Base = fieldFromInstruction(Insn, 16, 5); + unsigned Hint = fieldFromInstruction(Insn, 21, 5); + + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + Inst.addOperand(MCOperand::createImm(Hint)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodePrefeOpMM(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<9>(Insn & 0x1ff); + unsigned Base = fieldFromInstruction(Insn, 16, 5); + unsigned Hint = fieldFromInstruction(Insn, 21, 5); + + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + Inst.addOperand(MCOperand::createImm(Hint)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeCacheeOp_CacheOpR6(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<9>(Insn >> 7); + unsigned Hint = fieldFromInstruction(Insn, 16, 5); + unsigned Base = fieldFromInstruction(Insn, 21, 5); + + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + Inst.addOperand(MCOperand::createImm(Hint)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeStoreEvaOpMM(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<9>(Insn & 0x1ff); + unsigned Reg = fieldFromInstruction(Insn, 21, 5); + unsigned Base = fieldFromInstruction(Insn, 16, 5); + + Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::createReg(Reg)); + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeSyncI(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<16>(Insn & 0xffff); + unsigned Base = fieldFromInstruction(Insn, 21, 5); + + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeSynciR6(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Immediate = SignExtend32<16>(Insn & 0xffff); + unsigned Base = fieldFromInstruction(Insn, 16, 5); + + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Immediate)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMSA128Mem(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + int Offset = SignExtend32<10>(fieldFromInstruction(Insn, 16, 10)); + unsigned Reg = fieldFromInstruction(Insn, 6, 5); + unsigned Base = fieldFromInstruction(Insn, 11, 5); + + Reg = getReg(Decoder, Mips::MSA128BRegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::createReg(Reg)); + Inst.addOperand(MCOperand::createReg(Base)); + + // 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 * 2)); + break; + case Mips::LD_W: + case Mips::ST_W: + Inst.addOperand(MCOperand::createImm(Offset * 4)); + break; + case Mips::LD_D: + case Mips::ST_D: + Inst.addOperand(MCOperand::createImm(Offset * 8)); + break; + } + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMemMMImm4(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + unsigned Offset = Insn & 0xf; + unsigned Reg = fieldFromInstruction(Insn, 7, 3); + unsigned Base = fieldFromInstruction(Insn, 4, 3); + + switch (Inst.getOpcode()) { + case Mips::LBU16_MM: + case Mips::LHU16_MM: + case Mips::LW16_MM: + if (DecodeGPRMM16RegisterClass(Inst, Reg, Address, Decoder) + == MCDisassembler::Fail) + return MCDisassembler::Fail; + break; + case Mips::SB16_MM: + case Mips::SB16_MMR6: + case Mips::SH16_MM: + case Mips::SH16_MMR6: + case Mips::SW16_MM: + case Mips::SW16_MMR6: + if (DecodeGPRMM16ZeroRegisterClass(Inst, Reg, Address, Decoder) + == MCDisassembler::Fail) + return MCDisassembler::Fail; + break; + } + + if (DecodeGPRMM16RegisterClass(Inst, Base, Address, Decoder) + == MCDisassembler::Fail) + return MCDisassembler::Fail; + + switch (Inst.getOpcode()) { + case Mips::LBU16_MM: + if (Offset == 0xf) + Inst.addOperand(MCOperand::createImm(-1)); + else + Inst.addOperand(MCOperand::createImm(Offset)); + break; + case Mips::SB16_MM: + case Mips::SB16_MMR6: + Inst.addOperand(MCOperand::createImm(Offset)); + break; + case Mips::LHU16_MM: + case Mips::SH16_MM: + case Mips::SH16_MMR6: + Inst.addOperand(MCOperand::createImm(Offset << 1)); + break; + case Mips::LW16_MM: + case Mips::SW16_MM: + case Mips::SW16_MMR6: + Inst.addOperand(MCOperand::createImm(Offset << 2)); + break; + } + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMemMMSPImm5Lsl2(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + unsigned Offset = Insn & 0x1F; + unsigned Reg = fieldFromInstruction(Insn, 5, 5); + + Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg); + + Inst.addOperand(MCOperand::createReg(Reg)); + Inst.addOperand(MCOperand::createReg(Mips::SP)); + Inst.addOperand(MCOperand::createImm(Offset << 2)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMemMMGPImm7Lsl2(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + unsigned Offset = Insn & 0x7F; + unsigned Reg = fieldFromInstruction(Insn, 7, 3); + + Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg); + + Inst.addOperand(MCOperand::createReg(Reg)); + Inst.addOperand(MCOperand::createReg(Mips::GP)); + Inst.addOperand(MCOperand::createImm(Offset << 2)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMemMMReglistImm4Lsl2(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset; + switch (Inst.getOpcode()) { + case Mips::LWM16_MMR6: + case Mips::SWM16_MMR6: + Offset = fieldFromInstruction(Insn, 4, 4); + break; + default: + Offset = SignExtend32<4>(Insn & 0xf); + break; + } + + if (DecodeRegListOperand16(Inst, Insn, Address, Decoder) + == MCDisassembler::Fail) + return MCDisassembler::Fail; + + Inst.addOperand(MCOperand::createReg(Mips::SP)); + Inst.addOperand(MCOperand::createImm(Offset << 2)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMemMMImm9(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<9>(Insn & 0x1ff); + unsigned Reg = fieldFromInstruction(Insn, 21, 5); + unsigned Base = fieldFromInstruction(Insn, 16, 5); + + Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + if (Inst.getOpcode() == Mips::SCE_MM) + Inst.addOperand(MCOperand::createReg(Reg)); + + Inst.addOperand(MCOperand::createReg(Reg)); + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMemMMImm12(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<12>(Insn & 0x0fff); + unsigned Reg = fieldFromInstruction(Insn, 21, 5); + unsigned Base = fieldFromInstruction(Insn, 16, 5); + + Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + switch (Inst.getOpcode()) { + case Mips::SWM32_MM: + case Mips::LWM32_MM: + if (DecodeRegListOperand(Inst, Insn, Address, Decoder) + == MCDisassembler::Fail) + return MCDisassembler::Fail; + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + break; + case Mips::SC_MM: + Inst.addOperand(MCOperand::createReg(Reg)); + // fallthrough + default: + Inst.addOperand(MCOperand::createReg(Reg)); + if (Inst.getOpcode() == Mips::LWP_MM || Inst.getOpcode() == Mips::SWP_MM) + Inst.addOperand(MCOperand::createReg(Reg+1)); + + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + } + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMemMMImm16(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<16>(Insn & 0xffff); + unsigned Reg = fieldFromInstruction(Insn, 21, 5); + unsigned Base = fieldFromInstruction(Insn, 16, 5); + + Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::createReg(Reg)); + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeFMem(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<16>(Insn & 0xffff); + unsigned Reg = fieldFromInstruction(Insn, 16, 5); + unsigned Base = fieldFromInstruction(Insn, 21, 5); + + Reg = getReg(Decoder, Mips::FGR64RegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::createReg(Reg)); + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeFMem2(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<16>(Insn & 0xffff); + unsigned Reg = fieldFromInstruction(Insn, 16, 5); + unsigned Base = fieldFromInstruction(Insn, 21, 5); + + Reg = getReg(Decoder, Mips::COP2RegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::createReg(Reg)); + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeFMem3(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<16>(Insn & 0xffff); + unsigned Reg = fieldFromInstruction(Insn, 16, 5); + unsigned Base = fieldFromInstruction(Insn, 21, 5); + + Reg = getReg(Decoder, Mips::COP3RegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::createReg(Reg)); + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeFMemCop2R6(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<11>(Insn & 0x07ff); + unsigned Reg = fieldFromInstruction(Insn, 16, 5); + unsigned Base = fieldFromInstruction(Insn, 11, 5); + + Reg = getReg(Decoder, Mips::COP2RegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::createReg(Reg)); + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + + return MCDisassembler::Success; +} +static DecodeStatus DecodeSpecial3LlSc(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int64_t Offset = SignExtend64<9>((Insn >> 7) & 0x1ff); + unsigned Rt = fieldFromInstruction(Insn, 16, 5); + unsigned Base = fieldFromInstruction(Insn, 21, 5); + + Rt = getReg(Decoder, Mips::GPR32RegClassID, Rt); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + if(Inst.getOpcode() == Mips::SC_R6 || Inst.getOpcode() == Mips::SCD_R6){ + Inst.addOperand(MCOperand::createReg(Rt)); + } + + Inst.addOperand(MCOperand::createReg(Rt)); + Inst.addOperand(MCOperand::createReg(Base)); + Inst.addOperand(MCOperand::createImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeHWRegsRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + // Currently only hardware register 29 is supported. + if (RegNo != 29) + return MCDisassembler::Fail; + Inst.addOperand(MCOperand::createReg(Mips::HWR29)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeAFGR64RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 30 || RegNo %2) + return MCDisassembler::Fail; + + ; + unsigned Reg = getReg(Decoder, Mips::AFGR64RegClassID, RegNo /2); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeACC64DSPRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo >= 4) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::ACC64DSPRegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeHI32DSPRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo >= 4) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::HI32DSPRegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeLO32DSPRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo >= 4) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::LO32DSPRegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMSA128BRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::MSA128BRegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMSA128HRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::MSA128HRegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMSA128WRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::MSA128WRegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMSA128DRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::MSA128DRegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMSACtrlRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 7) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::MSACtrlRegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeCOP0RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::COP0RegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeCOP2RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::COP2RegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeBranchTarget(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder) { + int32_t BranchOffset = (SignExtend32<16>(Offset) * 4) + 4; + Inst.addOperand(MCOperand::createImm(BranchOffset)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeJumpTarget(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + + unsigned JumpOffset = fieldFromInstruction(Insn, 0, 26) << 2; + Inst.addOperand(MCOperand::createImm(JumpOffset)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeBranchTarget21(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder) { + int32_t BranchOffset = SignExtend32<21>(Offset) * 4; + + Inst.addOperand(MCOperand::createImm(BranchOffset)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeBranchTarget26(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder) { + int32_t BranchOffset = SignExtend32<26>(Offset) * 4; + + Inst.addOperand(MCOperand::createImm(BranchOffset)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeBranchTarget7MM(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder) { + int32_t BranchOffset = SignExtend32<7>(Offset) << 1; + Inst.addOperand(MCOperand::createImm(BranchOffset)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeBranchTarget10MM(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder) { + int32_t BranchOffset = SignExtend32<10>(Offset) << 1; + Inst.addOperand(MCOperand::createImm(BranchOffset)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeBranchTargetMM(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder) { + int32_t BranchOffset = SignExtend32<16>(Offset) * 2; + Inst.addOperand(MCOperand::createImm(BranchOffset)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeBranchTarget26MM(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder) { + int32_t BranchOffset = SignExtend32<26>(Offset) << 1; + + Inst.addOperand(MCOperand::createImm(BranchOffset)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeJumpTargetMM(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + unsigned JumpOffset = fieldFromInstruction(Insn, 0, 26) << 1; + Inst.addOperand(MCOperand::createImm(JumpOffset)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeAddiur2Simm7(MCInst &Inst, + unsigned Value, + uint64_t Address, + const void *Decoder) { + if (Value == 0) + Inst.addOperand(MCOperand::createImm(1)); + else if (Value == 0x7) + Inst.addOperand(MCOperand::createImm(-1)); + else + Inst.addOperand(MCOperand::createImm(Value << 2)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeUImm6Lsl2(MCInst &Inst, + unsigned Value, + uint64_t Address, + const void *Decoder) { + Inst.addOperand(MCOperand::createImm(Value << 2)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeLiSimm7(MCInst &Inst, + unsigned Value, + uint64_t Address, + const void *Decoder) { + if (Value == 0x7F) + Inst.addOperand(MCOperand::createImm(-1)); + else + Inst.addOperand(MCOperand::createImm(Value)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodePOOL16BEncodedField(MCInst &Inst, + unsigned Value, + uint64_t Address, + const void *Decoder) { + Inst.addOperand(MCOperand::createImm(Value == 0x0 ? 8 : Value)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeSimm4(MCInst &Inst, + unsigned Value, + uint64_t Address, + const void *Decoder) { + Inst.addOperand(MCOperand::createImm(SignExtend32<4>(Value))); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeSimm16(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Insn))); + return MCDisassembler::Success; +} + +template <unsigned Bits, int Offset> +static DecodeStatus DecodeUImmWithOffset(MCInst &Inst, unsigned Value, + uint64_t Address, + const void *Decoder) { + Value &= ((1 << Bits) - 1); + Inst.addOperand(MCOperand::createImm(Value + Offset)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeInsSize(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + // First we need to grab the pos(lsb) from MCInst. + int Pos = Inst.getOperand(2).getImm(); + int Size = (int) Insn - Pos + 1; + Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Size))); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeSimm19Lsl2(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + Inst.addOperand(MCOperand::createImm(SignExtend32<19>(Insn) * 4)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeSimm18Lsl3(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + Inst.addOperand(MCOperand::createImm(SignExtend32<18>(Insn) * 8)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeSimm9SP(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + int32_t DecodedValue; + switch (Insn) { + case 0: DecodedValue = 256; break; + case 1: DecodedValue = 257; break; + case 510: DecodedValue = -258; break; + case 511: DecodedValue = -257; break; + default: DecodedValue = SignExtend32<9>(Insn); break; + } + Inst.addOperand(MCOperand::createImm(DecodedValue * 4)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeANDI16Imm(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + // Insn must be >= 0, since it is unsigned that condition is always true. + assert(Insn < 16); + int32_t DecodedValues[] = {128, 1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, + 255, 32768, 65535}; + Inst.addOperand(MCOperand::createImm(DecodedValues[Insn])); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeUImm5lsl2(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + Inst.addOperand(MCOperand::createImm(Insn << 2)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeRegListOperand(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + unsigned Regs[] = {Mips::S0, Mips::S1, Mips::S2, Mips::S3, Mips::S4, Mips::S5, + Mips::S6, Mips::S7, Mips::FP}; + unsigned RegNum; + + unsigned RegLst = fieldFromInstruction(Insn, 21, 5); + + // Empty register lists are not allowed. + if (RegLst == 0) + return MCDisassembler::Fail; + + RegNum = RegLst & 0xf; + + // RegLst values 10-15, and 26-31 are reserved. + if (RegNum > 9) + return MCDisassembler::Fail; + + for (unsigned i = 0; i < RegNum; i++) + Inst.addOperand(MCOperand::createReg(Regs[i])); + + if (RegLst & 0x10) + Inst.addOperand(MCOperand::createReg(Mips::RA)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeRegListOperand16(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder) { + unsigned Regs[] = {Mips::S0, Mips::S1, Mips::S2, Mips::S3}; + unsigned RegLst; + switch(Inst.getOpcode()) { + default: + RegLst = fieldFromInstruction(Insn, 4, 2); + break; + case Mips::LWM16_MMR6: + case Mips::SWM16_MMR6: + RegLst = fieldFromInstruction(Insn, 8, 2); + break; + } + unsigned RegNum = RegLst & 0x3; + + for (unsigned i = 0; i <= RegNum; i++) + Inst.addOperand(MCOperand::createReg(Regs[i])); + + Inst.addOperand(MCOperand::createReg(Mips::RA)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMovePRegPair(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + + unsigned RegPair = fieldFromInstruction(Insn, 7, 3); + + switch (RegPair) { + default: + return MCDisassembler::Fail; + case 0: + Inst.addOperand(MCOperand::createReg(Mips::A1)); + Inst.addOperand(MCOperand::createReg(Mips::A2)); + break; + case 1: + Inst.addOperand(MCOperand::createReg(Mips::A1)); + Inst.addOperand(MCOperand::createReg(Mips::A3)); + break; + case 2: + Inst.addOperand(MCOperand::createReg(Mips::A2)); + Inst.addOperand(MCOperand::createReg(Mips::A3)); + break; + case 3: + Inst.addOperand(MCOperand::createReg(Mips::A0)); + Inst.addOperand(MCOperand::createReg(Mips::S5)); + break; + case 4: + Inst.addOperand(MCOperand::createReg(Mips::A0)); + Inst.addOperand(MCOperand::createReg(Mips::S6)); + break; + case 5: + Inst.addOperand(MCOperand::createReg(Mips::A0)); + Inst.addOperand(MCOperand::createReg(Mips::A1)); + break; + case 6: + Inst.addOperand(MCOperand::createReg(Mips::A0)); + Inst.addOperand(MCOperand::createReg(Mips::A2)); + break; + case 7: + Inst.addOperand(MCOperand::createReg(Mips::A0)); + Inst.addOperand(MCOperand::createReg(Mips::A3)); + break; + } + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeSimm23Lsl2(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + Inst.addOperand(MCOperand::createImm(SignExtend32<25>(Insn << 2))); + return MCDisassembler::Success; +} diff --git a/contrib/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp b/contrib/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp new file mode 100644 index 0000000..a7b7d2e --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp @@ -0,0 +1,359 @@ +//===-- MipsInstPrinter.cpp - Convert Mips MCInst to assembly syntax ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints an Mips MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#include "MipsInstPrinter.h" +#include "MCTargetDesc/MipsMCExpr.h" +#include "MipsInstrInfo.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define DEBUG_TYPE "asm-printer" + +#define PRINT_ALIAS_INSTR +#include "MipsGenAsmWriter.inc" + +template<unsigned R> +static bool isReg(const MCInst &MI, unsigned OpNo) { + assert(MI.getOperand(OpNo).isReg() && "Register operand expected."); + return MI.getOperand(OpNo).getReg() == R; +} + +const char* Mips::MipsFCCToString(Mips::CondCode CC) { + switch (CC) { + case FCOND_F: + case FCOND_T: return "f"; + case FCOND_UN: + case FCOND_OR: return "un"; + case FCOND_OEQ: + case FCOND_UNE: return "eq"; + case FCOND_UEQ: + case FCOND_ONE: return "ueq"; + case FCOND_OLT: + case FCOND_UGE: return "olt"; + case FCOND_ULT: + case FCOND_OGE: return "ult"; + case FCOND_OLE: + case FCOND_UGT: return "ole"; + case FCOND_ULE: + case FCOND_OGT: return "ule"; + case FCOND_SF: + case FCOND_ST: return "sf"; + case FCOND_NGLE: + case FCOND_GLE: return "ngle"; + case FCOND_SEQ: + case FCOND_SNE: return "seq"; + case FCOND_NGL: + case FCOND_GL: return "ngl"; + case FCOND_LT: + case FCOND_NLT: return "lt"; + case FCOND_NGE: + case FCOND_GE: return "nge"; + case FCOND_LE: + case FCOND_NLE: return "le"; + case FCOND_NGT: + case FCOND_GT: return "ngt"; + } + llvm_unreachable("Impossible condition code!"); +} + +void MipsInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const { + OS << '$' << StringRef(getRegisterName(RegNo)).lower(); +} + +void MipsInstPrinter::printInst(const MCInst *MI, raw_ostream &O, + StringRef Annot, const MCSubtargetInfo &STI) { + switch (MI->getOpcode()) { + default: + break; + case Mips::RDHWR: + 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. + if (!printAliasInstr(MI, O) && !printAlias(*MI, O)) + printInstruction(MI, O); + printAnnotation(O, Annot); + + switch (MI->getOpcode()) { + default: + break; + case Mips::RDHWR: + case Mips::RDHWR64: + O << "\n\t.set\tpop"; + } +} + +static void printExpr(const MCExpr *Expr, const MCAsmInfo *MAI, + raw_ostream &OS) { + int Offset = 0; + const MCSymbolRefExpr *SRE; + + if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr)) { + SRE = dyn_cast<MCSymbolRefExpr>(BE->getLHS()); + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(BE->getRHS()); + assert(SRE && CE && "Binary expression must be sym+const."); + Offset = CE->getValue(); + } else if (const MipsMCExpr *ME = dyn_cast<MipsMCExpr>(Expr)) { + ME->print(OS, MAI); + return; + } else + SRE = cast<MCSymbolRefExpr>(Expr); + + MCSymbolRefExpr::VariantKind Kind = SRE->getKind(); + + switch (Kind) { + default: llvm_unreachable("Invalid kind!"); + case MCSymbolRefExpr::VK_None: break; + case MCSymbolRefExpr::VK_Mips_GPREL: OS << "%gp_rel("; break; + case MCSymbolRefExpr::VK_Mips_GOT_CALL: OS << "%call16("; break; + case MCSymbolRefExpr::VK_Mips_GOT16: OS << "%got("; break; + case MCSymbolRefExpr::VK_Mips_GOT: OS << "%got("; break; + case MCSymbolRefExpr::VK_Mips_ABS_HI: OS << "%hi("; break; + case MCSymbolRefExpr::VK_Mips_ABS_LO: OS << "%lo("; break; + case MCSymbolRefExpr::VK_Mips_TLSGD: OS << "%tlsgd("; break; + case MCSymbolRefExpr::VK_Mips_TLSLDM: OS << "%tlsldm("; break; + case MCSymbolRefExpr::VK_Mips_DTPREL_HI: OS << "%dtprel_hi("; break; + case MCSymbolRefExpr::VK_Mips_DTPREL_LO: OS << "%dtprel_lo("; break; + case MCSymbolRefExpr::VK_Mips_GOTTPREL: OS << "%gottprel("; break; + case MCSymbolRefExpr::VK_Mips_TPREL_HI: OS << "%tprel_hi("; break; + case MCSymbolRefExpr::VK_Mips_TPREL_LO: OS << "%tprel_lo("; break; + case MCSymbolRefExpr::VK_Mips_GPOFF_HI: OS << "%hi(%neg(%gp_rel("; break; + case MCSymbolRefExpr::VK_Mips_GPOFF_LO: OS << "%lo(%neg(%gp_rel("; break; + case MCSymbolRefExpr::VK_Mips_GOT_DISP: OS << "%got_disp("; break; + case MCSymbolRefExpr::VK_Mips_GOT_PAGE: OS << "%got_page("; break; + case MCSymbolRefExpr::VK_Mips_GOT_OFST: OS << "%got_ofst("; break; + case MCSymbolRefExpr::VK_Mips_HIGHER: OS << "%higher("; break; + case MCSymbolRefExpr::VK_Mips_HIGHEST: OS << "%highest("; break; + case MCSymbolRefExpr::VK_Mips_GOT_HI16: OS << "%got_hi("; break; + case MCSymbolRefExpr::VK_Mips_GOT_LO16: OS << "%got_lo("; break; + case MCSymbolRefExpr::VK_Mips_CALL_HI16: OS << "%call_hi("; break; + case MCSymbolRefExpr::VK_Mips_CALL_LO16: OS << "%call_lo("; break; + case MCSymbolRefExpr::VK_Mips_PCREL_HI16: OS << "%pcrel_hi("; break; + case MCSymbolRefExpr::VK_Mips_PCREL_LO16: OS << "%pcrel_lo("; break; + } + + SRE->getSymbol().print(OS, MAI); + + if (Offset) { + if (Offset > 0) + OS << '+'; + OS << Offset; + } + + if ((Kind == MCSymbolRefExpr::VK_Mips_GPOFF_HI) || + (Kind == MCSymbolRefExpr::VK_Mips_GPOFF_LO)) + OS << ")))"; + else if (Kind != MCSymbolRefExpr::VK_None) + OS << ')'; +} + +void MipsInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O) { + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isReg()) { + printRegName(O, Op.getReg()); + return; + } + + if (Op.isImm()) { + O << Op.getImm(); + return; + } + + assert(Op.isExpr() && "unknown operand kind in printOperand"); + printExpr(Op.getExpr(), &MAI, O); +} + +void MipsInstPrinter::printUnsignedImm(const MCInst *MI, int opNum, + raw_ostream &O) { + const MCOperand &MO = MI->getOperand(opNum); + if (MO.isImm()) + O << (unsigned short int)MO.getImm(); + else + printOperand(MI, opNum, O); +} + +void MipsInstPrinter::printUnsignedImm8(const MCInst *MI, int opNum, + raw_ostream &O) { + const MCOperand &MO = MI->getOperand(opNum); + if (MO.isImm()) + O << (unsigned short int)(unsigned char)MO.getImm(); + else + printOperand(MI, opNum, O); +} + +void MipsInstPrinter:: +printMemOperand(const MCInst *MI, int opNum, raw_ostream &O) { + // Load/Store memory operands -- imm($reg) + // If PIC target the target is loaded as the + // pattern lw $25,%call16($28) + + // opNum can be invalid if instruction had reglist as operand. + // MemOperand is always last operand of instruction (base + offset). + switch (MI->getOpcode()) { + default: + break; + case Mips::SWM32_MM: + case Mips::LWM32_MM: + case Mips::SWM16_MM: + case Mips::SWM16_MMR6: + case Mips::LWM16_MM: + case Mips::LWM16_MMR6: + opNum = MI->getNumOperands() - 2; + break; + } + + printOperand(MI, opNum+1, O); + O << "("; + printOperand(MI, opNum, O); + O << ")"; +} + +void MipsInstPrinter:: +printMemOperandEA(const MCInst *MI, int opNum, raw_ostream &O) { + // when using stack locations for not load/store instructions + // print the same way as all normal 3 operand instructions. + printOperand(MI, opNum, O); + O << ", "; + printOperand(MI, opNum+1, O); + return; +} + +void MipsInstPrinter:: +printFCCOperand(const MCInst *MI, int opNum, raw_ostream &O) { + const MCOperand& MO = MI->getOperand(opNum); + O << MipsFCCToString((Mips::CondCode)MO.getImm()); +} + +void MipsInstPrinter:: +printRegisterPair(const MCInst *MI, int opNum, raw_ostream &O) { + printRegName(O, MI->getOperand(opNum).getReg()); +} + +void MipsInstPrinter:: +printSHFMask(const MCInst *MI, int opNum, raw_ostream &O) { + llvm_unreachable("TODO"); +} + +bool MipsInstPrinter::printAlias(const char *Str, const MCInst &MI, + unsigned OpNo, raw_ostream &OS) { + OS << "\t" << Str << "\t"; + printOperand(&MI, OpNo, OS); + return true; +} + +bool MipsInstPrinter::printAlias(const char *Str, const MCInst &MI, + unsigned OpNo0, unsigned OpNo1, + raw_ostream &OS) { + printAlias(Str, MI, OpNo0, OS); + OS << ", "; + printOperand(&MI, OpNo1, OS); + return true; +} + +bool MipsInstPrinter::printAlias(const MCInst &MI, raw_ostream &OS) { + switch (MI.getOpcode()) { + case Mips::BEQ: + case Mips::BEQ_MM: + // beq $zero, $zero, $L2 => b $L2 + // beq $r0, $zero, $L2 => beqz $r0, $L2 + return (isReg<Mips::ZERO>(MI, 0) && isReg<Mips::ZERO>(MI, 1) && + printAlias("b", MI, 2, OS)) || + (isReg<Mips::ZERO>(MI, 1) && printAlias("beqz", MI, 0, 2, OS)); + case Mips::BEQ64: + // beq $r0, $zero, $L2 => beqz $r0, $L2 + return isReg<Mips::ZERO_64>(MI, 1) && printAlias("beqz", MI, 0, 2, OS); + case Mips::BNE: + // bne $r0, $zero, $L2 => bnez $r0, $L2 + return isReg<Mips::ZERO>(MI, 1) && printAlias("bnez", MI, 0, 2, OS); + case Mips::BNE64: + // bne $r0, $zero, $L2 => bnez $r0, $L2 + return isReg<Mips::ZERO_64>(MI, 1) && printAlias("bnez", MI, 0, 2, OS); + case Mips::BGEZAL: + // bgezal $zero, $L1 => bal $L1 + return isReg<Mips::ZERO>(MI, 0) && printAlias("bal", MI, 1, OS); + case Mips::BC1T: + // bc1t $fcc0, $L1 => bc1t $L1 + return isReg<Mips::FCC0>(MI, 0) && printAlias("bc1t", MI, 1, OS); + case Mips::BC1F: + // bc1f $fcc0, $L1 => bc1f $L1 + return isReg<Mips::FCC0>(MI, 0) && printAlias("bc1f", MI, 1, OS); + case Mips::JALR: + // jalr $ra, $r1 => jalr $r1 + return isReg<Mips::RA>(MI, 0) && printAlias("jalr", MI, 1, OS); + case Mips::JALR64: + // jalr $ra, $r1 => jalr $r1 + return isReg<Mips::RA_64>(MI, 0) && printAlias("jalr", MI, 1, OS); + case Mips::NOR: + case Mips::NOR_MM: + // nor $r0, $r1, $zero => not $r0, $r1 + return isReg<Mips::ZERO>(MI, 2) && printAlias("not", MI, 0, 1, OS); + case Mips::NOR64: + // nor $r0, $r1, $zero => not $r0, $r1 + return isReg<Mips::ZERO_64>(MI, 2) && printAlias("not", MI, 0, 1, OS); + case Mips::OR: + // or $r0, $r1, $zero => move $r0, $r1 + return isReg<Mips::ZERO>(MI, 2) && printAlias("move", MI, 0, 1, OS); + default: return false; + } +} + +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); + } +} + +void MipsInstPrinter:: +printRegisterList(const MCInst *MI, int opNum, raw_ostream &O) { + // - 2 because register List is always first operand of instruction and it is + // always followed by memory operand (base + offset). + for (int i = opNum, e = MI->getNumOperands() - 2; i != e; ++i) { + if (i != opNum) + O << ", "; + printRegName(O, MI->getOperand(i).getReg()); + } +} diff --git a/contrib/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.h b/contrib/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.h new file mode 100644 index 0000000..0e61ea6 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.h @@ -0,0 +1,114 @@ +//=== MipsInstPrinter.h - Convert Mips MCInst to assembly syntax -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints a Mips MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_INSTPRINTER_MIPSINSTPRINTER_H +#define LLVM_LIB_TARGET_MIPS_INSTPRINTER_MIPSINSTPRINTER_H +#include "llvm/MC/MCInstPrinter.h" + +namespace llvm { +// These enumeration declarations were originally in MipsInstrInfo.h but +// had to be moved here to avoid circular dependencies between +// LLVMMipsCodeGen and LLVMMipsAsmPrinter. +namespace Mips { +// Mips Branch Codes +enum FPBranchCode { + BRANCH_F, + BRANCH_T, + BRANCH_FL, + BRANCH_TL, + BRANCH_INVALID +}; + +// Mips Condition Codes +enum CondCode { + // To be used with float branch True + FCOND_F, + FCOND_UN, + FCOND_OEQ, + FCOND_UEQ, + FCOND_OLT, + FCOND_ULT, + FCOND_OLE, + FCOND_ULE, + FCOND_SF, + FCOND_NGLE, + FCOND_SEQ, + FCOND_NGL, + FCOND_LT, + FCOND_NGE, + FCOND_LE, + FCOND_NGT, + + // To be used with float branch False + // This conditions have the same mnemonic as the + // above ones, but are used with a branch False; + FCOND_T, + FCOND_OR, + FCOND_UNE, + FCOND_ONE, + FCOND_UGE, + FCOND_OGE, + FCOND_UGT, + FCOND_OGT, + FCOND_ST, + FCOND_GLE, + FCOND_SNE, + FCOND_GL, + FCOND_NLT, + FCOND_GE, + FCOND_NLE, + FCOND_GT +}; + +const char *MipsFCCToString(Mips::CondCode CC); +} // end namespace Mips + +class MipsInstPrinter : public MCInstPrinter { +public: + MipsInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, + const MCRegisterInfo &MRI) + : MCInstPrinter(MAI, MII, MRI) {} + + // Autogenerated by tblgen. + void printInstruction(const MCInst *MI, raw_ostream &O); + static const char *getRegisterName(unsigned RegNo); + + void printRegName(raw_ostream &OS, unsigned RegNo) const override; + void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot, + const MCSubtargetInfo &STI) override; + + bool printAliasInstr(const MCInst *MI, raw_ostream &OS); + void printCustomAliasOperand(const MCInst *MI, unsigned OpIdx, + unsigned PrintMethodIdx, raw_ostream &O); + +private: + void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printUnsignedImm(const MCInst *MI, int opNum, raw_ostream &O); + void printUnsignedImm8(const MCInst *MI, int opNum, raw_ostream &O); + void printMemOperand(const MCInst *MI, int opNum, raw_ostream &O); + void printMemOperandEA(const MCInst *MI, int opNum, raw_ostream &O); + void printFCCOperand(const MCInst *MI, int opNum, raw_ostream &O); + void printRegisterPair(const MCInst *MI, int opNum, raw_ostream &O); + void printSHFMask(const MCInst *MI, int opNum, raw_ostream &O); + + bool printAlias(const char *Str, const MCInst &MI, unsigned OpNo, + raw_ostream &OS); + bool printAlias(const char *Str, const MCInst &MI, unsigned OpNo0, + unsigned OpNo1, raw_ostream &OS); + bool printAlias(const MCInst &MI, raw_ostream &OS); + void printSaveRestore(const MCInst *MI, raw_ostream &O); + void printRegisterList(const MCInst *MI, int opNum, raw_ostream &O); +}; +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.cpp new file mode 100644 index 0000000..70b9cca --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.cpp @@ -0,0 +1,69 @@ +//===-- MipsABIFlagsSection.cpp - Mips ELF ABI Flags Section ---*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsABIFlagsSection.h" + +using namespace llvm; + +uint8_t MipsABIFlagsSection::getFpABIValue() { + switch (FpABI) { + case FpABIKind::ANY: + return Mips::Val_GNU_MIPS_ABI_FP_ANY; + case FpABIKind::SOFT: + return Mips::Val_GNU_MIPS_ABI_FP_SOFT; + case FpABIKind::XX: + return Mips::Val_GNU_MIPS_ABI_FP_XX; + case FpABIKind::S32: + return Mips::Val_GNU_MIPS_ABI_FP_DOUBLE; + case FpABIKind::S64: + if (Is32BitABI) + return OddSPReg ? Mips::Val_GNU_MIPS_ABI_FP_64 + : Mips::Val_GNU_MIPS_ABI_FP_64A; + return Mips::Val_GNU_MIPS_ABI_FP_DOUBLE; + } + + llvm_unreachable("unexpected fp abi value"); +} + +StringRef MipsABIFlagsSection::getFpABIString(FpABIKind Value) { + switch (Value) { + case FpABIKind::XX: + return "xx"; + case FpABIKind::S32: + return "32"; + case FpABIKind::S64: + return "64"; + default: + llvm_unreachable("unsupported fp abi value"); + } +} + +uint8_t MipsABIFlagsSection::getCPR1SizeValue() { + if (FpABI == FpABIKind::XX) + return (uint8_t)Mips::AFL_REG_32; + return (uint8_t)CPR1Size; +} + +namespace llvm { +MCStreamer &operator<<(MCStreamer &OS, MipsABIFlagsSection &ABIFlagsSection) { + // Write out a Elf_Internal_ABIFlags_v0 struct + OS.EmitIntValue(ABIFlagsSection.getVersionValue(), 2); // version + OS.EmitIntValue(ABIFlagsSection.getISALevelValue(), 1); // isa_level + OS.EmitIntValue(ABIFlagsSection.getISARevisionValue(), 1); // isa_rev + OS.EmitIntValue(ABIFlagsSection.getGPRSizeValue(), 1); // gpr_size + OS.EmitIntValue(ABIFlagsSection.getCPR1SizeValue(), 1); // cpr1_size + OS.EmitIntValue(ABIFlagsSection.getCPR2SizeValue(), 1); // cpr2_size + OS.EmitIntValue(ABIFlagsSection.getFpABIValue(), 1); // fp_abi + OS.EmitIntValue(ABIFlagsSection.getISAExtensionSetValue(), 4); // isa_ext + OS.EmitIntValue(ABIFlagsSection.getASESetValue(), 4); // ases + OS.EmitIntValue(ABIFlagsSection.getFlags1Value(), 4); // flags1 + OS.EmitIntValue(ABIFlagsSection.getFlags2Value(), 4); // flags2 + return OS; +} +} diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h new file mode 100644 index 0000000..b078cd3 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h @@ -0,0 +1,191 @@ +//===-- MipsABIFlagsSection.h - Mips ELF ABI Flags Section -----*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSABIFLAGSSECTION_H +#define LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSABIFLAGSSECTION_H + +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MipsABIFlags.h" + +namespace llvm { + +class MCStreamer; + +struct MipsABIFlagsSection { + // Internal representation of the fp_abi related values used in .module. + enum class FpABIKind { ANY, XX, S32, S64, SOFT }; + + // Version of flags structure. + uint16_t Version; + // The level of the ISA: 1-5, 32, 64. + uint8_t ISALevel; + // The revision of ISA: 0 for MIPS V and below, 1-n otherwise. + uint8_t ISARevision; + // The size of general purpose registers. + Mips::AFL_REG GPRSize; + // The size of co-processor 1 registers. + Mips::AFL_REG CPR1Size; + // The size of co-processor 2 registers. + Mips::AFL_REG CPR2Size; + // Processor-specific extension. + uint32_t ISAExtensionSet; + // Mask of ASEs used. + uint32_t ASESet; + + bool OddSPReg; + + bool Is32BitABI; + +protected: + // The floating-point ABI. + FpABIKind FpABI; + +public: + MipsABIFlagsSection() + : Version(0), ISALevel(0), ISARevision(0), GPRSize(Mips::AFL_REG_NONE), + CPR1Size(Mips::AFL_REG_NONE), CPR2Size(Mips::AFL_REG_NONE), + ISAExtensionSet(0), ASESet(0), OddSPReg(false), Is32BitABI(false), + FpABI(FpABIKind::ANY) {} + + uint16_t getVersionValue() { return (uint16_t)Version; } + uint8_t getISALevelValue() { return (uint8_t)ISALevel; } + uint8_t getISARevisionValue() { return (uint8_t)ISARevision; } + uint8_t getGPRSizeValue() { return (uint8_t)GPRSize; } + uint8_t getCPR1SizeValue(); + uint8_t getCPR2SizeValue() { return (uint8_t)CPR2Size; } + uint8_t getFpABIValue(); + uint32_t getISAExtensionSetValue() { return (uint32_t)ISAExtensionSet; } + uint32_t getASESetValue() { return (uint32_t)ASESet; } + + uint32_t getFlags1Value() { + uint32_t Value = 0; + + if (OddSPReg) + Value |= (uint32_t)Mips::AFL_FLAGS1_ODDSPREG; + + return Value; + } + + uint32_t getFlags2Value() { return 0; } + + FpABIKind getFpABI() { return FpABI; } + void setFpABI(FpABIKind Value, bool IsABI32Bit) { + FpABI = Value; + Is32BitABI = IsABI32Bit; + } + StringRef getFpABIString(FpABIKind Value); + + template <class PredicateLibrary> + void setISALevelAndRevisionFromPredicates(const PredicateLibrary &P) { + if (P.hasMips64()) { + ISALevel = 64; + if (P.hasMips64r6()) + ISARevision = 6; + else if (P.hasMips64r5()) + ISARevision = 5; + else if (P.hasMips64r3()) + ISARevision = 3; + else if (P.hasMips64r2()) + ISARevision = 2; + else + ISARevision = 1; + } else if (P.hasMips32()) { + ISALevel = 32; + if (P.hasMips32r6()) + ISARevision = 6; + else if (P.hasMips32r5()) + ISARevision = 5; + else if (P.hasMips32r3()) + ISARevision = 3; + else if (P.hasMips32r2()) + ISARevision = 2; + else + ISARevision = 1; + } else { + ISARevision = 0; + if (P.hasMips5()) + ISALevel = 5; + else if (P.hasMips4()) + ISALevel = 4; + else if (P.hasMips3()) + ISALevel = 3; + else if (P.hasMips2()) + ISALevel = 2; + else if (P.hasMips1()) + ISALevel = 1; + else + llvm_unreachable("Unknown ISA level!"); + } + } + + template <class PredicateLibrary> + void setGPRSizeFromPredicates(const PredicateLibrary &P) { + GPRSize = P.isGP64bit() ? Mips::AFL_REG_64 : Mips::AFL_REG_32; + } + + template <class PredicateLibrary> + void setCPR1SizeFromPredicates(const PredicateLibrary &P) { + if (P.useSoftFloat()) + CPR1Size = Mips::AFL_REG_NONE; + else if (P.hasMSA()) + CPR1Size = Mips::AFL_REG_128; + else + CPR1Size = P.isFP64bit() ? Mips::AFL_REG_64 : Mips::AFL_REG_32; + } + + template <class PredicateLibrary> + void setASESetFromPredicates(const PredicateLibrary &P) { + ASESet = 0; + if (P.hasDSP()) + ASESet |= Mips::AFL_ASE_DSP; + if (P.hasDSPR2()) + ASESet |= Mips::AFL_ASE_DSPR2; + if (P.hasMSA()) + ASESet |= Mips::AFL_ASE_MSA; + if (P.inMicroMipsMode()) + ASESet |= Mips::AFL_ASE_MICROMIPS; + if (P.inMips16Mode()) + ASESet |= Mips::AFL_ASE_MIPS16; + } + + template <class PredicateLibrary> + void setFpAbiFromPredicates(const PredicateLibrary &P) { + Is32BitABI = P.isABI_O32(); + + FpABI = FpABIKind::ANY; + if (P.useSoftFloat()) + FpABI = FpABIKind::SOFT; + else if (P.isABI_N32() || P.isABI_N64()) + FpABI = FpABIKind::S64; + else if (P.isABI_O32()) { + if (P.isABI_FPXX()) + FpABI = FpABIKind::XX; + else if (P.isFP64bit()) + FpABI = FpABIKind::S64; + else + FpABI = FpABIKind::S32; + } + } + + template <class PredicateLibrary> + void setAllFromPredicates(const PredicateLibrary &P) { + setISALevelAndRevisionFromPredicates(P); + setGPRSizeFromPredicates(P); + setCPR1SizeFromPredicates(P); + setASESetFromPredicates(P); + setFpAbiFromPredicates(P); + OddSPReg = P.useOddSPReg(); + } +}; + +MCStreamer &operator<<(MCStreamer &OS, MipsABIFlagsSection &ABIFlagsSection); +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp new file mode 100644 index 0000000..cdcc392 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp @@ -0,0 +1,135 @@ +//===---- MipsABIInfo.cpp - Information about MIPS ABI's ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsABIInfo.h" +#include "MipsRegisterInfo.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/MC/MCTargetOptions.h" + +using namespace llvm; + +namespace { +static const MCPhysReg O32IntRegs[4] = {Mips::A0, Mips::A1, Mips::A2, Mips::A3}; + +static const MCPhysReg Mips64IntRegs[8] = { + Mips::A0_64, Mips::A1_64, Mips::A2_64, Mips::A3_64, + Mips::T0_64, Mips::T1_64, Mips::T2_64, Mips::T3_64}; +} + +ArrayRef<MCPhysReg> MipsABIInfo::GetByValArgRegs() const { + if (IsO32()) + return makeArrayRef(O32IntRegs); + if (IsN32() || IsN64()) + return makeArrayRef(Mips64IntRegs); + llvm_unreachable("Unhandled ABI"); +} + +ArrayRef<MCPhysReg> MipsABIInfo::GetVarArgRegs() const { + if (IsO32()) + return makeArrayRef(O32IntRegs); + if (IsN32() || IsN64()) + return makeArrayRef(Mips64IntRegs); + llvm_unreachable("Unhandled ABI"); +} + +unsigned MipsABIInfo::GetCalleeAllocdArgSizeInBytes(CallingConv::ID CC) const { + if (IsO32()) + return CC != CallingConv::Fast ? 16 : 0; + if (IsN32() || IsN64() || IsEABI()) + return 0; + llvm_unreachable("Unhandled ABI"); +} + +MipsABIInfo MipsABIInfo::computeTargetABI(const Triple &TT, StringRef CPU, + const MCTargetOptions &Options) { + if (Options.getABIName().startswith("o32")) + return MipsABIInfo::O32(); + else if (Options.getABIName().startswith("n32")) + return MipsABIInfo::N32(); + else if (Options.getABIName().startswith("n64")) + return MipsABIInfo::N64(); + else if (Options.getABIName().startswith("eabi")) + return MipsABIInfo::EABI(); + else if (!Options.getABIName().empty()) + llvm_unreachable("Unknown ABI option for MIPS"); + + // FIXME: This shares code with the selectMipsCPU routine that's + // used and not shared in a couple of other places. This needs unifying + // at some level. + if (CPU.empty() || CPU == "generic") { + if (TT.getArch() == Triple::mips || TT.getArch() == Triple::mipsel) + CPU = "mips32"; + else + CPU = "mips64"; + } + + return StringSwitch<MipsABIInfo>(CPU) + .Case("mips1", MipsABIInfo::O32()) + .Case("mips2", MipsABIInfo::O32()) + .Case("mips32", MipsABIInfo::O32()) + .Case("mips32r2", MipsABIInfo::O32()) + .Case("mips32r3", MipsABIInfo::O32()) + .Case("mips32r5", MipsABIInfo::O32()) + .Case("mips32r6", MipsABIInfo::O32()) + .Case("mips3", MipsABIInfo::N64()) + .Case("mips4", MipsABIInfo::N64()) + .Case("mips5", MipsABIInfo::N64()) + .Case("mips64", MipsABIInfo::N64()) + .Case("mips64r2", MipsABIInfo::N64()) + .Case("mips64r3", MipsABIInfo::N64()) + .Case("mips64r5", MipsABIInfo::N64()) + .Case("mips64r6", MipsABIInfo::N64()) + .Case("octeon", MipsABIInfo::N64()) + .Default(MipsABIInfo::Unknown()); +} + +unsigned MipsABIInfo::GetStackPtr() const { + return ArePtrs64bit() ? Mips::SP_64 : Mips::SP; +} + +unsigned MipsABIInfo::GetFramePtr() const { + return ArePtrs64bit() ? Mips::FP_64 : Mips::FP; +} + +unsigned MipsABIInfo::GetBasePtr() const { + return ArePtrs64bit() ? Mips::S7_64 : Mips::S7; +} + +unsigned MipsABIInfo::GetNullPtr() const { + return ArePtrs64bit() ? Mips::ZERO_64 : Mips::ZERO; +} + +unsigned MipsABIInfo::GetZeroReg() const { + return AreGprs64bit() ? Mips::ZERO_64 : Mips::ZERO; +} + +unsigned MipsABIInfo::GetPtrAdduOp() const { + return ArePtrs64bit() ? Mips::DADDu : Mips::ADDu; +} + +unsigned MipsABIInfo::GetPtrAddiuOp() const { + return ArePtrs64bit() ? Mips::DADDiu : Mips::ADDiu; +} + +unsigned MipsABIInfo::GetGPRMoveOp() const { + return ArePtrs64bit() ? Mips::OR64 : Mips::OR; +} + +unsigned MipsABIInfo::GetEhDataReg(unsigned I) const { + static const unsigned EhDataReg[] = { + Mips::A0, Mips::A1, Mips::A2, Mips::A3 + }; + static const unsigned EhDataReg64[] = { + Mips::A0_64, Mips::A1_64, Mips::A2_64, Mips::A3_64 + }; + + return IsN64() ? EhDataReg64[I] : EhDataReg[I]; +} + diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.h new file mode 100644 index 0000000..ffa2c76 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.h @@ -0,0 +1,81 @@ +//===---- MipsABIInfo.h - Information about MIPS ABI's --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSABIINFO_H +#define LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSABIINFO_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/IR/CallingConv.h" +#include "llvm/MC/MCRegisterInfo.h" + +namespace llvm { + +class MCTargetOptions; +class StringRef; +class TargetRegisterClass; + +class MipsABIInfo { +public: + enum class ABI { Unknown, O32, N32, N64, EABI }; + +protected: + ABI ThisABI; + +public: + MipsABIInfo(ABI ThisABI) : ThisABI(ThisABI) {} + + static MipsABIInfo Unknown() { return MipsABIInfo(ABI::Unknown); } + static MipsABIInfo O32() { return MipsABIInfo(ABI::O32); } + static MipsABIInfo N32() { return MipsABIInfo(ABI::N32); } + static MipsABIInfo N64() { return MipsABIInfo(ABI::N64); } + static MipsABIInfo EABI() { return MipsABIInfo(ABI::EABI); } + static MipsABIInfo computeTargetABI(const Triple &TT, StringRef CPU, + const MCTargetOptions &Options); + + bool IsKnown() const { return ThisABI != ABI::Unknown; } + bool IsO32() const { return ThisABI == ABI::O32; } + bool IsN32() const { return ThisABI == ABI::N32; } + bool IsN64() const { return ThisABI == ABI::N64; } + bool IsEABI() const { return ThisABI == ABI::EABI; } + ABI GetEnumValue() const { return ThisABI; } + + /// The registers to use for byval arguments. + ArrayRef<MCPhysReg> GetByValArgRegs() const; + + /// The registers to use for the variable argument list. + ArrayRef<MCPhysReg> GetVarArgRegs() const; + + /// Obtain the size of the area allocated by the callee for arguments. + /// CallingConv::FastCall affects the value for O32. + unsigned GetCalleeAllocdArgSizeInBytes(CallingConv::ID CC) const; + + /// Ordering of ABI's + /// MipsGenSubtargetInfo.inc will use this to resolve conflicts when given + /// multiple ABI options. + bool operator<(const MipsABIInfo Other) const { + return ThisABI < Other.GetEnumValue(); + } + + unsigned GetStackPtr() const; + unsigned GetFramePtr() const; + unsigned GetBasePtr() const; + unsigned GetNullPtr() const; + unsigned GetZeroReg() const; + unsigned GetPtrAdduOp() const; + unsigned GetPtrAddiuOp() const; + unsigned GetGPRMoveOp() const; + inline bool ArePtrs64bit() const { return IsN64(); } + inline bool AreGprs64bit() const { return IsN32() || IsN64(); } + + unsigned GetEhDataReg(unsigned I) const; +}; +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp new file mode 100644 index 0000000..e4865e2 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp @@ -0,0 +1,467 @@ +//===-- MipsAsmBackend.cpp - Mips Asm Backend ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the MipsAsmBackend class. +// +//===----------------------------------------------------------------------===// +// + +#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(const MCFixup &Fixup, uint64_t Value, + MCContext *Ctx = nullptr) { + + unsigned Kind = Fixup.getKind(); + + // Add/subtract and shift + switch (Kind) { + default: + return 0; + case FK_Data_2: + case FK_GPRel_4: + case FK_Data_4: + case FK_Data_8: + case Mips::fixup_Mips_LO16: + case Mips::fixup_Mips_GPREL16: + case Mips::fixup_Mips_GPOFF_HI: + case Mips::fixup_Mips_GPOFF_LO: + case Mips::fixup_Mips_GOT_PAGE: + case Mips::fixup_Mips_GOT_OFST: + case Mips::fixup_Mips_GOT_DISP: + case Mips::fixup_Mips_GOT_LO16: + case Mips::fixup_Mips_CALL_LO16: + case Mips::fixup_MICROMIPS_LO16: + case Mips::fixup_MICROMIPS_GOT_PAGE: + case Mips::fixup_MICROMIPS_GOT_OFST: + case Mips::fixup_MICROMIPS_GOT_DISP: + case Mips::fixup_MIPS_PCLO16: + break; + case Mips::fixup_Mips_PC16: + // The displacement is then divided by 4 to give us an 18 bit + // 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 (!isInt<16>(Value) && Ctx) { + Ctx->reportError(Fixup.getLoc(), "out of range PC16 fixup"); + return 0; + } + break; + case Mips::fixup_MIPS_PC19_S2: + // Forcing a signed division because Value can be negative. + Value = (int64_t)Value / 4; + // We now check if Value can be encoded as a 19-bit signed immediate. + if (!isInt<19>(Value) && Ctx) { + Ctx->reportError(Fixup.getLoc(), "out of range PC19 fixup"); + return 0; + } + break; + case Mips::fixup_Mips_26: + // So far we are only using this type for jumps. + // The displacement is then divided by 4 to give us an 28 bit + // address range. + Value >>= 2; + break; + case Mips::fixup_Mips_HI16: + case Mips::fixup_Mips_GOT_Local: + case Mips::fixup_Mips_GOT_HI16: + case Mips::fixup_Mips_CALL_HI16: + case Mips::fixup_MICROMIPS_HI16: + case Mips::fixup_MIPS_PCHI16: + // Get the 2nd 16-bits. Also add 1 if bit 15 is 1. + Value = ((Value + 0x8000) >> 16) & 0xffff; + break; + case Mips::fixup_Mips_HIGHER: + // Get the 3rd 16-bits. + Value = ((Value + 0x80008000LL) >> 32) & 0xffff; + break; + case Mips::fixup_Mips_HIGHEST: + // Get the 4th 16-bits. + Value = ((Value + 0x800080008000LL) >> 48) & 0xffff; + break; + case Mips::fixup_MICROMIPS_26_S1: + Value >>= 1; + break; + case Mips::fixup_MICROMIPS_PC7_S1: + Value -= 4; + // Forcing a signed division because Value can be negative. + Value = (int64_t) Value / 2; + // We now check if Value can be encoded as a 7-bit signed immediate. + if (!isInt<7>(Value) && Ctx) { + Ctx->reportError(Fixup.getLoc(), "out of range PC7 fixup"); + return 0; + } + break; + case Mips::fixup_MICROMIPS_PC10_S1: + Value -= 2; + // Forcing a signed division because Value can be negative. + Value = (int64_t) Value / 2; + // We now check if Value can be encoded as a 10-bit signed immediate. + if (!isInt<10>(Value) && Ctx) { + Ctx->reportError(Fixup.getLoc(), "out of range PC10 fixup"); + return 0; + } + break; + case Mips::fixup_MICROMIPS_PC16_S1: + Value -= 4; + // 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 (!isInt<16>(Value) && Ctx) { + Ctx->reportError(Fixup.getLoc(), "out of range PC16 fixup"); + return 0; + } + break; + case Mips::fixup_MIPS_PC18_S3: + // Forcing a signed division because Value can be negative. + Value = (int64_t)Value / 8; + // We now check if Value can be encoded as a 18-bit signed immediate. + if (!isInt<18>(Value) && Ctx) { + Ctx->reportError(Fixup.getLoc(), "out of range PC18 fixup"); + return 0; + } + break; + case Mips::fixup_MIPS_PC21_S2: + // Forcing a signed division because Value can be negative. + Value = (int64_t) Value / 4; + // We now check if Value can be encoded as a 21-bit signed immediate. + if (!isInt<21>(Value) && Ctx) { + Ctx->reportError(Fixup.getLoc(), "out of range PC21 fixup"); + return 0; + } + break; + case Mips::fixup_MIPS_PC26_S2: + // Forcing a signed division because Value can be negative. + Value = (int64_t) Value / 4; + // We now check if Value can be encoded as a 26-bit signed immediate. + if (!isInt<26>(Value) && Ctx) { + Ctx->reportError(Fixup.getLoc(), "out of range PC26 fixup"); + return 0; + } + break; + } + + return Value; +} + +MCObjectWriter * +MipsAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const { + return createMipsELFObjectWriter(OS, + MCELFObjectTargetWriter::getOSABI(OSType), IsLittle, Is64Bit); +} + +// Little-endian fixup data byte ordering: +// mips32r2: a | b | x | x +// microMIPS: x | x | a | b + +static bool needsMMLEByteOrder(unsigned Kind) { + return Kind != Mips::fixup_MICROMIPS_PC10_S1 && + Kind >= Mips::fixup_MICROMIPS_26_S1 && + Kind < Mips::LastTargetFixupKind; +} + +// Calculate index for microMIPS specific little endian byte order +static unsigned calculateMMLEIndex(unsigned i) { + assert(i <= 3 && "Index out of range!"); + + return (1 - i / 2) * 2 + i % 2; +} + +/// 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: + case Mips::fixup_MICROMIPS_PC10_S1: + FullSize = 2; + break; + case FK_Data_8: + case Mips::fixup_Mips_64: + FullSize = 8; + break; + case FK_Data_4: + default: + FullSize = 4; + break; + } + + // Grab current value, if any, from bits. + uint64_t CurVal = 0; + + bool microMipsLEByteOrder = needsMMLEByteOrder((unsigned) Kind); + + 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); + } + + uint64_t Mask = ((uint64_t)(-1) >> + (64 - getFixupKindInfo(Kind).TargetSize)); + CurVal |= Value & Mask; + + // Write out the fixed up bytes back to the code/data bits. + for (unsigned i = 0; i != NumBytes; ++i) { + unsigned Idx = IsLittle ? (microMipsLEByteOrder ? calculateMMLEIndex(i) + : i) + : (FullSize - 1 - i); + Data[Offset + Idx] = (uint8_t)((CurVal >> (i*8)) & 0xff); + } +} + +bool MipsAsmBackend::getFixupKind(StringRef Name, MCFixupKind &MappedKind) const { + if (Name == "R_MIPS_NONE") { + MappedKind = (MCFixupKind)Mips::fixup_Mips_NONE; + return true; + } + if (Name == "R_MIPS_32") { + MappedKind = FK_Data_4; + return true; + } + return MCAsmBackend::getFixupKind(Name, MappedKind); +} + +const MCFixupKindInfo &MipsAsmBackend:: +getFixupKindInfo(MCFixupKind Kind) const { + const static MCFixupKindInfo LittleEndianInfos[Mips::NumTargetFixupKinds] = { + // This table *must* be in same the order of fixup_* kinds in + // MipsFixupKinds.h. + // + // name offset bits flags + { "fixup_Mips_NONE", 0, 0, 0 }, + { "fixup_Mips_16", 0, 16, 0 }, + { "fixup_Mips_32", 0, 32, 0 }, + { "fixup_Mips_REL32", 0, 32, 0 }, + { "fixup_Mips_26", 0, 26, 0 }, + { "fixup_Mips_HI16", 0, 16, 0 }, + { "fixup_Mips_LO16", 0, 16, 0 }, + { "fixup_Mips_GPREL16", 0, 16, 0 }, + { "fixup_Mips_LITERAL", 0, 16, 0 }, + { "fixup_Mips_GOT_Global", 0, 16, 0 }, + { "fixup_Mips_GOT_Local", 0, 16, 0 }, + { "fixup_Mips_PC16", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_Mips_CALL16", 0, 16, 0 }, + { "fixup_Mips_GPREL32", 0, 32, 0 }, + { "fixup_Mips_SHIFT5", 6, 5, 0 }, + { "fixup_Mips_SHIFT6", 6, 5, 0 }, + { "fixup_Mips_64", 0, 64, 0 }, + { "fixup_Mips_TLSGD", 0, 16, 0 }, + { "fixup_Mips_GOTTPREL", 0, 16, 0 }, + { "fixup_Mips_TPREL_HI", 0, 16, 0 }, + { "fixup_Mips_TPREL_LO", 0, 16, 0 }, + { "fixup_Mips_TLSLDM", 0, 16, 0 }, + { "fixup_Mips_DTPREL_HI", 0, 16, 0 }, + { "fixup_Mips_DTPREL_LO", 0, 16, 0 }, + { "fixup_Mips_Branch_PCRel", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_Mips_GPOFF_HI", 0, 16, 0 }, + { "fixup_Mips_GPOFF_LO", 0, 16, 0 }, + { "fixup_Mips_GOT_PAGE", 0, 16, 0 }, + { "fixup_Mips_GOT_OFST", 0, 16, 0 }, + { "fixup_Mips_GOT_DISP", 0, 16, 0 }, + { "fixup_Mips_HIGHER", 0, 16, 0 }, + { "fixup_Mips_HIGHEST", 0, 16, 0 }, + { "fixup_Mips_GOT_HI16", 0, 16, 0 }, + { "fixup_Mips_GOT_LO16", 0, 16, 0 }, + { "fixup_Mips_CALL_HI16", 0, 16, 0 }, + { "fixup_Mips_CALL_LO16", 0, 16, 0 }, + { "fixup_Mips_PC18_S3", 0, 18, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PC19_S2", 0, 19, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PC21_S2", 0, 21, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PC26_S2", 0, 26, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PCHI16", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PCLO16", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MICROMIPS_26_S1", 0, 26, 0 }, + { "fixup_MICROMIPS_HI16", 0, 16, 0 }, + { "fixup_MICROMIPS_LO16", 0, 16, 0 }, + { "fixup_MICROMIPS_GOT16", 0, 16, 0 }, + { "fixup_MICROMIPS_PC7_S1", 0, 7, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MICROMIPS_PC10_S1", 0, 10, MCFixupKindInfo::FKF_IsPCRel }, + { "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 } + }; + + const static MCFixupKindInfo BigEndianInfos[Mips::NumTargetFixupKinds] = { + // This table *must* be in same the order of fixup_* kinds in + // MipsFixupKinds.h. + // + // name offset bits flags + { "fixup_Mips_NONE", 0, 0, 0 }, + { "fixup_Mips_16", 16, 16, 0 }, + { "fixup_Mips_32", 0, 32, 0 }, + { "fixup_Mips_REL32", 0, 32, 0 }, + { "fixup_Mips_26", 6, 26, 0 }, + { "fixup_Mips_HI16", 16, 16, 0 }, + { "fixup_Mips_LO16", 16, 16, 0 }, + { "fixup_Mips_GPREL16", 16, 16, 0 }, + { "fixup_Mips_LITERAL", 16, 16, 0 }, + { "fixup_Mips_GOT_Global", 16, 16, 0 }, + { "fixup_Mips_GOT_Local", 16, 16, 0 }, + { "fixup_Mips_PC16", 16, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_Mips_CALL16", 16, 16, 0 }, + { "fixup_Mips_GPREL32", 0, 32, 0 }, + { "fixup_Mips_SHIFT5", 21, 5, 0 }, + { "fixup_Mips_SHIFT6", 21, 5, 0 }, + { "fixup_Mips_64", 0, 64, 0 }, + { "fixup_Mips_TLSGD", 16, 16, 0 }, + { "fixup_Mips_GOTTPREL", 16, 16, 0 }, + { "fixup_Mips_TPREL_HI", 16, 16, 0 }, + { "fixup_Mips_TPREL_LO", 16, 16, 0 }, + { "fixup_Mips_TLSLDM", 16, 16, 0 }, + { "fixup_Mips_DTPREL_HI", 16, 16, 0 }, + { "fixup_Mips_DTPREL_LO", 16, 16, 0 }, + { "fixup_Mips_Branch_PCRel",16, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_Mips_GPOFF_HI", 16, 16, 0 }, + { "fixup_Mips_GPOFF_LO", 16, 16, 0 }, + { "fixup_Mips_GOT_PAGE", 16, 16, 0 }, + { "fixup_Mips_GOT_OFST", 16, 16, 0 }, + { "fixup_Mips_GOT_DISP", 16, 16, 0 }, + { "fixup_Mips_HIGHER", 16, 16, 0 }, + { "fixup_Mips_HIGHEST", 16, 16, 0 }, + { "fixup_Mips_GOT_HI16", 16, 16, 0 }, + { "fixup_Mips_GOT_LO16", 16, 16, 0 }, + { "fixup_Mips_CALL_HI16", 16, 16, 0 }, + { "fixup_Mips_CALL_LO16", 16, 16, 0 }, + { "fixup_Mips_PC18_S3", 14, 18, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PC19_S2", 13, 19, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PC21_S2", 11, 21, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PC26_S2", 6, 26, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PCHI16", 16, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MIPS_PCLO16", 16, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MICROMIPS_26_S1", 6, 26, 0 }, + { "fixup_MICROMIPS_HI16", 16, 16, 0 }, + { "fixup_MICROMIPS_LO16", 16, 16, 0 }, + { "fixup_MICROMIPS_GOT16", 16, 16, 0 }, + { "fixup_MICROMIPS_PC7_S1", 9, 7, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MICROMIPS_PC10_S1", 6, 10, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MICROMIPS_PC16_S1",16, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MICROMIPS_CALL16", 16, 16, 0 }, + { "fixup_MICROMIPS_GOT_DISP", 16, 16, 0 }, + { "fixup_MICROMIPS_GOT_PAGE", 16, 16, 0 }, + { "fixup_MICROMIPS_GOT_OFST", 16, 16, 0 }, + { "fixup_MICROMIPS_TLS_GD", 16, 16, 0 }, + { "fixup_MICROMIPS_TLS_LDM", 16, 16, 0 }, + { "fixup_MICROMIPS_TLS_DTPREL_HI16", 16, 16, 0 }, + { "fixup_MICROMIPS_TLS_DTPREL_LO16", 16, 16, 0 }, + { "fixup_MICROMIPS_TLS_TPREL_HI16", 16, 16, 0 }, + { "fixup_MICROMIPS_TLS_TPREL_LO16", 16, 16, 0 } + }; + + if (Kind < FirstTargetFixupKind) + return MCAsmBackend::getFixupKindInfo(Kind); + + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); + + if (IsLittle) + return LittleEndianInfos[Kind - FirstTargetFixupKind]; + return BigEndianInfos[Kind - FirstTargetFixupKind]; +} + +/// WriteNopData - Write an (optimal) nop sequence of Count bytes +/// to the given output. If the target cannot generate such a sequence, +/// it should return an error. +/// +/// \return - True on success. +bool MipsAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const { + // Check for a less than instruction size number of bytes + // FIXME: 16 bit instructions are not handled yet here. + // We shouldn't be using a hard coded number for instruction size. + + // If the count is not 4-byte aligned, we must be writing data into the text + // section (otherwise we have unaligned instructions, and thus have far + // bigger problems), so just write zeros instead. + OW->WriteZeros(Count); + return true; +} + +/// processFixupValue - Target hook to process the literal value of a fixup +/// if necessary. +void MipsAsmBackend::processFixupValue(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFixup &Fixup, + const MCFragment *DF, + const MCValue &Target, + uint64_t &Value, + bool &IsResolved) { + // At this point we'll ignore the value returned by adjustFixupValue as + // we are only checking if the fixup can be applied correctly. We have + // access to MCContext from here which allows us to report a fatal error + // with *possibly* a source code location. + (void)adjustFixupValue(Fixup, Value, &Asm.getContext()); +} + +// MCAsmBackend +MCAsmBackend *llvm::createMipsAsmBackendEL32(const Target &T, + const MCRegisterInfo &MRI, + const Triple &TT, StringRef CPU) { + return new MipsAsmBackend(T, TT.getOS(), /*IsLittle*/ true, + /*Is64Bit*/ false); +} + +MCAsmBackend *llvm::createMipsAsmBackendEB32(const Target &T, + const MCRegisterInfo &MRI, + const Triple &TT, StringRef CPU) { + return new MipsAsmBackend(T, TT.getOS(), /*IsLittle*/ false, + /*Is64Bit*/ false); +} + +MCAsmBackend *llvm::createMipsAsmBackendEL64(const Target &T, + const MCRegisterInfo &MRI, + const Triple &TT, StringRef CPU) { + return new MipsAsmBackend(T, TT.getOS(), /*IsLittle*/ true, /*Is64Bit*/ true); +} + +MCAsmBackend *llvm::createMipsAsmBackendEB64(const Target &T, + const MCRegisterInfo &MRI, + const Triple &TT, StringRef CPU) { + return new MipsAsmBackend(T, TT.getOS(), /*IsLittle*/ false, + /*Is64Bit*/ true); +} diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h new file mode 100644 index 0000000..1c9af92 --- /dev/null +++ b/contrib/llvm/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 LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSASMBACKEND_H +#define LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSASMBACKEND_H + +#include "MCTargetDesc/MipsFixupKinds.h" +#include "llvm/ADT/Triple.h" +#include "llvm/MC/MCAsmBackend.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_pwrite_stream &OS) const override; + + void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, + uint64_t Value, bool IsPCRel) const override; + + bool getFixupKind(StringRef Name, MCFixupKind &MappedKind) const override; + const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; + + unsigned getNumFixupKinds() const override { + return Mips::NumTargetFixupKinds; + } + + /// @name Target Relaxation Interfaces + /// @{ + + /// MayNeedRelaxation - Check whether the given instruction may need + /// relaxation. + /// + /// \param Inst - The instruction to test. + bool mayNeedRelaxation(const MCInst &Inst) const override { + return false; + } + + /// fixupNeedsRelaxation - Target specific predicate for whether a given + /// fixup requires the associated instruction to be relaxed. + bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const override { + // FIXME. + llvm_unreachable("RelaxInstruction() unimplemented"); + return false; + } + + /// RelaxInstruction - Relax the instruction in the given fragment + /// to the next wider instruction. + /// + /// \param Inst - The instruction to relax, which may be the same + /// as the output. + /// \param [out] Res On return, the relaxed instruction. + void relaxInstruction(const MCInst &Inst, MCInst &Res) const override {} + + /// @} + + bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override; + + void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout, + const MCFixup &Fixup, const MCFragment *DF, + const MCValue &Target, uint64_t &Value, + bool &IsResolved) override; + +}; // class MipsAsmBackend + +} // namespace + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h new file mode 100644 index 0000000..ff7779e --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h @@ -0,0 +1,125 @@ +//===-- MipsBaseInfo.h - Top level definitions for MIPS MC ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains small standalone helper functions and enum definitions for +// the Mips target useful for the compiler back-end and the MC libraries. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSBASEINFO_H +#define LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSBASEINFO_H + +#include "MipsFixupKinds.h" +#include "MipsMCTargetDesc.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" + +namespace llvm { + +/// MipsII - This namespace holds all of the target specific flags that +/// instruction info tracks. +/// +namespace MipsII { + /// Target Operand Flag enum. + enum TOF { + //===------------------------------------------------------------------===// + // Mips Specific MachineOperand flags. + + MO_NO_FLAG, + + /// MO_GOT16 - Represents the offset into the global offset table at which + /// the address the relocation entry symbol resides during execution. + MO_GOT16, + MO_GOT, + + /// MO_GOT_CALL - Represents the offset into the global offset table at + /// which the address of a call site relocation entry symbol resides + /// during execution. This is different from the above since this flag + /// can only be present in call instructions. + MO_GOT_CALL, + + /// MO_GPREL - Represents the offset from the current gp value to be used + /// for the relocatable object file being produced. + MO_GPREL, + + /// MO_ABS_HI/LO - Represents the hi or low part of an absolute symbol + /// address. + MO_ABS_HI, + MO_ABS_LO, + + /// MO_TLSGD - Represents the offset into the global offset table at which + // the module ID and TSL block offset reside during execution (General + // Dynamic TLS). + MO_TLSGD, + + /// MO_TLSLDM - Represents the offset into the global offset table at which + // the module ID and TSL block offset reside during execution (Local + // Dynamic TLS). + MO_TLSLDM, + MO_DTPREL_HI, + MO_DTPREL_LO, + + /// MO_GOTTPREL - Represents the offset from the thread pointer (Initial + // Exec TLS). + MO_GOTTPREL, + + /// MO_TPREL_HI/LO - Represents the hi and low part of the offset from + // the thread pointer (Local Exec TLS). + MO_TPREL_HI, + MO_TPREL_LO, + + // N32/64 Flags. + MO_GPOFF_HI, + MO_GPOFF_LO, + MO_GOT_DISP, + MO_GOT_PAGE, + MO_GOT_OFST, + + /// MO_HIGHER/HIGHEST - Represents the highest or higher half word of a + /// 64-bit symbol address. + MO_HIGHER, + MO_HIGHEST, + + /// MO_GOT_HI16/LO16, MO_CALL_HI16/LO16 - Relocations used for large GOTs. + MO_GOT_HI16, + MO_GOT_LO16, + MO_CALL_HI16, + MO_CALL_LO16 + }; + + enum { + //===------------------------------------------------------------------===// + // Instruction encodings. These are the standard/most common forms for + // Mips instructions. + // + + // Pseudo - This represents an instruction that is a pseudo instruction + // or one that has not been implemented yet. It is illegal to code generate + // it, but tolerated for intermediate implementation stages. + Pseudo = 0, + + /// FrmR - This form is for instructions of the format R. + FrmR = 1, + /// FrmI - This form is for instructions of the format I. + FrmI = 2, + /// FrmJ - This form is for instructions of the format J. + FrmJ = 3, + /// FrmFR - This form is for instructions of the format FR. + FrmFR = 4, + /// FrmFI - This form is for instructions of the format FI. + FrmFI = 5, + /// FrmOther - This form is for instructions that have no specific format. + FrmOther = 6, + + FormMask = 15 + }; +} +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp new file mode 100644 index 0000000..5b9f02b --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp @@ -0,0 +1,431 @@ +//===-- MipsELFObjectWriter.cpp - Mips ELF Writer -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MCTargetDesc/MipsFixupKinds.h" +#include "MCTargetDesc/MipsMCTargetDesc.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSymbolELF.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/ErrorHandling.h" +#include <list> + +using namespace llvm; + +namespace { +// A helper structure based on ELFRelocationEntry, used for sorting entries in +// the relocation table. +struct MipsRelocationEntry { + MipsRelocationEntry(const ELFRelocationEntry &R) + : R(R), SortOffset(R.Offset), HasMatchingHi(false) {} + const ELFRelocationEntry R; + // SortOffset equals R.Offset except for the *HI16 relocations, for which it + // will be set based on the R.Offset of the matching *LO16 relocation. + int64_t SortOffset; + // True when this is a *LO16 relocation chosen as a match for a *HI16 + // relocation. + bool HasMatchingHi; +}; + + class MipsELFObjectWriter : public MCELFObjectTargetWriter { + public: + MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI, + bool _isN64, bool IsLittleEndian); + + ~MipsELFObjectWriter() override; + + unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel) const override; + bool needsRelocateWithSymbol(const MCSymbol &Sym, + unsigned Type) const override; + virtual void sortRelocs(const MCAssembler &Asm, + std::vector<ELFRelocationEntry> &Relocs) override; + }; +} + +MipsELFObjectWriter::MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI, + bool _isN64, bool IsLittleEndian) + : MCELFObjectTargetWriter(_is64Bit, OSABI, ELF::EM_MIPS, + /*HasRelocationAddend*/ _isN64, + /*IsN64*/ _isN64) {} + +MipsELFObjectWriter::~MipsELFObjectWriter() {} + +unsigned MipsELFObjectWriter::GetRelocType(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const { + // Determine the type of the relocation. + unsigned Kind = (unsigned)Fixup.getKind(); + + switch (Kind) { + case Mips::fixup_Mips_NONE: + return ELF::R_MIPS_NONE; + case Mips::fixup_Mips_16: + case FK_Data_2: + return IsPCRel ? ELF::R_MIPS_PC16 : ELF::R_MIPS_16; + case Mips::fixup_Mips_32: + case FK_Data_4: + return IsPCRel ? ELF::R_MIPS_PC32 : ELF::R_MIPS_32; + } + + if (IsPCRel) { + switch (Kind) { + case Mips::fixup_Mips_Branch_PCRel: + case Mips::fixup_Mips_PC16: + return ELF::R_MIPS_PC16; + case Mips::fixup_MICROMIPS_PC7_S1: + return ELF::R_MICROMIPS_PC7_S1; + case Mips::fixup_MICROMIPS_PC10_S1: + return ELF::R_MICROMIPS_PC10_S1; + case Mips::fixup_MICROMIPS_PC16_S1: + return ELF::R_MICROMIPS_PC16_S1; + case Mips::fixup_MIPS_PC19_S2: + return ELF::R_MIPS_PC19_S2; + case Mips::fixup_MIPS_PC18_S3: + return ELF::R_MIPS_PC18_S3; + case Mips::fixup_MIPS_PC21_S2: + return ELF::R_MIPS_PC21_S2; + case Mips::fixup_MIPS_PC26_S2: + return ELF::R_MIPS_PC26_S2; + case Mips::fixup_MIPS_PCHI16: + return ELF::R_MIPS_PCHI16; + case Mips::fixup_MIPS_PCLO16: + return ELF::R_MIPS_PCLO16; + } + + llvm_unreachable("invalid PC-relative fixup kind!"); + } + + switch (Kind) { + case Mips::fixup_Mips_64: + case FK_Data_8: + return ELF::R_MIPS_64; + case FK_GPRel_4: + if (isN64()) { + unsigned Type = (unsigned)ELF::R_MIPS_NONE; + Type = setRType((unsigned)ELF::R_MIPS_GPREL32, Type); + Type = setRType2((unsigned)ELF::R_MIPS_64, Type); + Type = setRType3((unsigned)ELF::R_MIPS_NONE, Type); + return Type; + } + return ELF::R_MIPS_GPREL32; + case Mips::fixup_Mips_GPREL16: + return ELF::R_MIPS_GPREL16; + case Mips::fixup_Mips_26: + return ELF::R_MIPS_26; + case Mips::fixup_Mips_CALL16: + return ELF::R_MIPS_CALL16; + case Mips::fixup_Mips_GOT_Global: + case Mips::fixup_Mips_GOT_Local: + return ELF::R_MIPS_GOT16; + case Mips::fixup_Mips_HI16: + return ELF::R_MIPS_HI16; + case Mips::fixup_Mips_LO16: + return ELF::R_MIPS_LO16; + case Mips::fixup_Mips_TLSGD: + return ELF::R_MIPS_TLS_GD; + case Mips::fixup_Mips_GOTTPREL: + return ELF::R_MIPS_TLS_GOTTPREL; + case Mips::fixup_Mips_TPREL_HI: + return ELF::R_MIPS_TLS_TPREL_HI16; + case Mips::fixup_Mips_TPREL_LO: + return ELF::R_MIPS_TLS_TPREL_LO16; + case Mips::fixup_Mips_TLSLDM: + return ELF::R_MIPS_TLS_LDM; + case Mips::fixup_Mips_DTPREL_HI: + return ELF::R_MIPS_TLS_DTPREL_HI16; + case Mips::fixup_Mips_DTPREL_LO: + return ELF::R_MIPS_TLS_DTPREL_LO16; + case Mips::fixup_Mips_GOT_PAGE: + return ELF::R_MIPS_GOT_PAGE; + case Mips::fixup_Mips_GOT_OFST: + return ELF::R_MIPS_GOT_OFST; + case Mips::fixup_Mips_GOT_DISP: + return ELF::R_MIPS_GOT_DISP; + case Mips::fixup_Mips_GPOFF_HI: { + unsigned Type = (unsigned)ELF::R_MIPS_NONE; + Type = setRType((unsigned)ELF::R_MIPS_GPREL16, Type); + Type = setRType2((unsigned)ELF::R_MIPS_SUB, Type); + Type = setRType3((unsigned)ELF::R_MIPS_HI16, Type); + return Type; + } + case Mips::fixup_Mips_GPOFF_LO: { + unsigned Type = (unsigned)ELF::R_MIPS_NONE; + Type = setRType((unsigned)ELF::R_MIPS_GPREL16, Type); + Type = setRType2((unsigned)ELF::R_MIPS_SUB, Type); + Type = setRType3((unsigned)ELF::R_MIPS_LO16, Type); + return Type; + } + case Mips::fixup_Mips_HIGHER: + return ELF::R_MIPS_HIGHER; + case Mips::fixup_Mips_HIGHEST: + return ELF::R_MIPS_HIGHEST; + case Mips::fixup_Mips_GOT_HI16: + return ELF::R_MIPS_GOT_HI16; + case Mips::fixup_Mips_GOT_LO16: + return ELF::R_MIPS_GOT_LO16; + case Mips::fixup_Mips_CALL_HI16: + return ELF::R_MIPS_CALL_HI16; + case Mips::fixup_Mips_CALL_LO16: + return ELF::R_MIPS_CALL_LO16; + case Mips::fixup_MICROMIPS_26_S1: + return ELF::R_MICROMIPS_26_S1; + case Mips::fixup_MICROMIPS_HI16: + return ELF::R_MICROMIPS_HI16; + case Mips::fixup_MICROMIPS_LO16: + return ELF::R_MICROMIPS_LO16; + case Mips::fixup_MICROMIPS_GOT16: + return ELF::R_MICROMIPS_GOT16; + case Mips::fixup_MICROMIPS_CALL16: + return ELF::R_MICROMIPS_CALL16; + case Mips::fixup_MICROMIPS_GOT_DISP: + return ELF::R_MICROMIPS_GOT_DISP; + case Mips::fixup_MICROMIPS_GOT_PAGE: + return ELF::R_MICROMIPS_GOT_PAGE; + case Mips::fixup_MICROMIPS_GOT_OFST: + return ELF::R_MICROMIPS_GOT_OFST; + case Mips::fixup_MICROMIPS_TLS_GD: + return ELF::R_MICROMIPS_TLS_GD; + case Mips::fixup_MICROMIPS_TLS_LDM: + return ELF::R_MICROMIPS_TLS_LDM; + case Mips::fixup_MICROMIPS_TLS_DTPREL_HI16: + return ELF::R_MICROMIPS_TLS_DTPREL_HI16; + case Mips::fixup_MICROMIPS_TLS_DTPREL_LO16: + return ELF::R_MICROMIPS_TLS_DTPREL_LO16; + case Mips::fixup_MICROMIPS_TLS_TPREL_HI16: + return ELF::R_MICROMIPS_TLS_TPREL_HI16; + case Mips::fixup_MICROMIPS_TLS_TPREL_LO16: + return ELF::R_MICROMIPS_TLS_TPREL_LO16; + } + + llvm_unreachable("invalid fixup kind!"); +} + +// Sort entries by SortOffset in descending order. +// When there are more *HI16 relocs paired with one *LO16 reloc, the 2nd rule +// sorts them in ascending order of R.Offset. +static int cmpRelMips(const MipsRelocationEntry *AP, + const MipsRelocationEntry *BP) { + const MipsRelocationEntry &A = *AP; + const MipsRelocationEntry &B = *BP; + if (A.SortOffset != B.SortOffset) + return B.SortOffset - A.SortOffset; + if (A.R.Offset != B.R.Offset) + return A.R.Offset - B.R.Offset; + if (B.R.Type != A.R.Type) + return B.R.Type - A.R.Type; + //llvm_unreachable("ELFRelocs might be unstable!"); + return 0; +} + +// For the given Reloc.Type, return the matching relocation type, as in the +// table below. +static unsigned getMatchingLoType(const MCAssembler &Asm, + const ELFRelocationEntry &Reloc) { + unsigned Type = Reloc.Type; + if (Type == ELF::R_MIPS_HI16) + return ELF::R_MIPS_LO16; + if (Type == ELF::R_MICROMIPS_HI16) + return ELF::R_MICROMIPS_LO16; + if (Type == ELF::R_MIPS16_HI16) + return ELF::R_MIPS16_LO16; + + if (Reloc.Symbol->getBinding() != ELF::STB_LOCAL) + return ELF::R_MIPS_NONE; + + if (Type == ELF::R_MIPS_GOT16) + return ELF::R_MIPS_LO16; + if (Type == ELF::R_MICROMIPS_GOT16) + return ELF::R_MICROMIPS_LO16; + if (Type == ELF::R_MIPS16_GOT16) + return ELF::R_MIPS16_LO16; + + return ELF::R_MIPS_NONE; +} + +// Return true if First needs a matching *LO16, its matching *LO16 type equals +// Second's type and both relocations are against the same symbol. +static bool areMatchingHiAndLo(const MCAssembler &Asm, + const ELFRelocationEntry &First, + const ELFRelocationEntry &Second) { + return getMatchingLoType(Asm, First) != ELF::R_MIPS_NONE && + getMatchingLoType(Asm, First) == Second.Type && + First.Symbol && First.Symbol == Second.Symbol; +} + +// Return true if MipsRelocs[Index] is a *LO16 preceded by a matching *HI16. +static bool +isPrecededByMatchingHi(const MCAssembler &Asm, uint32_t Index, + std::vector<MipsRelocationEntry> &MipsRelocs) { + return Index < MipsRelocs.size() - 1 && + areMatchingHiAndLo(Asm, MipsRelocs[Index + 1].R, MipsRelocs[Index].R); +} + +// Return true if MipsRelocs[Index] is a *LO16 not preceded by a matching *HI16 +// and not chosen by a *HI16 as a match. +static bool isFreeLo(const MCAssembler &Asm, uint32_t Index, + std::vector<MipsRelocationEntry> &MipsRelocs) { + return Index < MipsRelocs.size() && !MipsRelocs[Index].HasMatchingHi && + !isPrecededByMatchingHi(Asm, Index, MipsRelocs); +} + +// Lo is chosen as a match for Hi, set their fields accordingly. +// Mips instructions have fixed length of at least two bytes (two for +// micromips/mips16, four for mips32/64), so we can set HI's SortOffset to +// matching LO's Offset minus one to simplify the sorting function. +static void setMatch(MipsRelocationEntry &Hi, MipsRelocationEntry &Lo) { + Lo.HasMatchingHi = true; + Hi.SortOffset = Lo.R.Offset - 1; +} + +// We sort relocation table entries by offset, except for one additional rule +// required by MIPS ABI: every *HI16 relocation must be immediately followed by +// the corresponding *LO16 relocation. We also support a GNU extension that +// allows more *HI16s paired with one *LO16. +// +// *HI16 relocations and their matching *LO16 are: +// +// +---------------------------------------------+-------------------+ +// | *HI16 | matching *LO16 | +// |---------------------------------------------+-------------------| +// | R_MIPS_HI16, local R_MIPS_GOT16 | R_MIPS_LO16 | +// | R_MICROMIPS_HI16, local R_MICROMIPS_GOT16 | R_MICROMIPS_LO16 | +// | R_MIPS16_HI16, local R_MIPS16_GOT16 | R_MIPS16_LO16 | +// +---------------------------------------------+-------------------+ +// +// (local R_*_GOT16 meaning R_*_GOT16 against the local symbol.) +// +// To handle *HI16 and *LO16 relocations, the linker needs a combined addend +// ("AHL") calculated from both *HI16 ("AHI") and *LO16 ("ALO") relocations: +// AHL = (AHI << 16) + (short)ALO; +// +// We are reusing gnu as sorting algorithm so we are emitting the relocation +// table sorted the same way as gnu as would sort it, for easier comparison of +// the generated .o files. +// +// The logic is: +// search the table (starting from the highest offset and going back to zero) +// for all *HI16 relocations that don't have a matching *LO16. +// For every such HI, find a matching LO with highest offset that isn't already +// matched with another HI. If there are no free LOs, match it with the first +// found (starting from lowest offset). +// When there are more HIs matched with one LO, sort them in descending order by +// offset. +// +// In other words, when searching for a matching LO: +// - don't look for a 'better' match for the HIs that are already followed by a +// matching LO; +// - prefer LOs without a pair; +// - prefer LOs with higher offset; + +static int cmpRel(const ELFRelocationEntry *AP, const ELFRelocationEntry *BP) { + const ELFRelocationEntry &A = *AP; + const ELFRelocationEntry &B = *BP; + if (A.Offset != B.Offset) + return B.Offset - A.Offset; + if (B.Type != A.Type) + return A.Type - B.Type; + return 0; +} + +void MipsELFObjectWriter::sortRelocs(const MCAssembler &Asm, + std::vector<ELFRelocationEntry> &Relocs) { + if (Relocs.size() < 2) + return; + + // Sorts entries by Offset in descending order. + array_pod_sort(Relocs.begin(), Relocs.end(), cmpRel); + + // Init MipsRelocs from Relocs. + std::vector<MipsRelocationEntry> MipsRelocs; + for (unsigned I = 0, E = Relocs.size(); I != E; ++I) + MipsRelocs.push_back(MipsRelocationEntry(Relocs[I])); + + // Find a matching LO for all HIs that need it. + for (int32_t I = 0, E = MipsRelocs.size(); I != E; ++I) { + if (getMatchingLoType(Asm, MipsRelocs[I].R) == ELF::R_MIPS_NONE || + (I > 0 && isPrecededByMatchingHi(Asm, I - 1, MipsRelocs))) + continue; + + int32_t MatchedLoIndex = -1; + + // Search the list in the ascending order of Offset. + for (int32_t J = MipsRelocs.size() - 1, N = -1; J != N; --J) { + // check for a match + if (areMatchingHiAndLo(Asm, MipsRelocs[I].R, MipsRelocs[J].R) && + (MatchedLoIndex == -1 || // first match + // or we already have a match, + // but this one is with higher offset and it's free + (MatchedLoIndex > J && isFreeLo(Asm, J, MipsRelocs)))) + MatchedLoIndex = J; + } + + if (MatchedLoIndex != -1) + // We have a match. + setMatch(MipsRelocs[I], MipsRelocs[MatchedLoIndex]); + } + + // SortOffsets are calculated, call the sorting function. + array_pod_sort(MipsRelocs.begin(), MipsRelocs.end(), cmpRelMips); + + // Copy sorted MipsRelocs back to Relocs. + for (unsigned I = 0, E = MipsRelocs.size(); I != E; ++I) + Relocs[I] = MipsRelocs[I].R; +} + +bool MipsELFObjectWriter::needsRelocateWithSymbol(const MCSymbol &Sym, + unsigned Type) const { + // FIXME: This is extremely 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_32: + if (cast<MCSymbolELF>(Sym).getOther() & ELF::STO_MIPS_MICROMIPS) + return true; + // falltrough + case ELF::R_MIPS_26: + case ELF::R_MIPS_64: + case ELF::R_MIPS_GPREL16: + return false; + } +} + +MCObjectWriter *llvm::createMipsELFObjectWriter(raw_pwrite_stream &OS, + uint8_t OSABI, + bool IsLittleEndian, + bool Is64Bit) { + MCELFObjectTargetWriter *MOTW = + new MipsELFObjectWriter(Is64Bit, OSABI, Is64Bit, IsLittleEndian); + return createELFObjectWriter(MOTW, OS, IsLittleEndian); +} diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp new file mode 100644 index 0000000..e7d687e --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp @@ -0,0 +1,82 @@ +//===-------- MipsELFStreamer.cpp - ELF Object Output ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsELFStreamer.h" +#include "MipsTargetStreamer.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSymbolELF.h" +#include "llvm/Support/ELF.h" + +using namespace llvm; + +void MipsELFStreamer::EmitInstruction(const MCInst &Inst, + const MCSubtargetInfo &STI) { + MCELFStreamer::EmitInstruction(Inst, STI); + + MCContext &Context = getContext(); + const MCRegisterInfo *MCRegInfo = Context.getRegisterInfo(); + + for (unsigned OpIndex = 0; OpIndex < Inst.getNumOperands(); ++OpIndex) { + const MCOperand &Op = Inst.getOperand(OpIndex); + + if (!Op.isReg()) + continue; + + unsigned Reg = Op.getReg(); + RegInfoRecord->SetPhysRegUsed(Reg, MCRegInfo); + } + + createPendingLabelRelocs(); +} + +void MipsELFStreamer::createPendingLabelRelocs() { + MipsTargetELFStreamer *ELFTargetStreamer = + static_cast<MipsTargetELFStreamer *>(getTargetStreamer()); + + // FIXME: Also mark labels when in MIPS16 mode. + if (ELFTargetStreamer->isMicroMipsEnabled()) { + for (auto *L : Labels) { + auto *Label = cast<MCSymbolELF>(L); + getAssembler().registerSymbol(*Label); + Label->setOther(ELF::STO_MIPS_MICROMIPS); + } + } + + Labels.clear(); +} + +void MipsELFStreamer::EmitLabel(MCSymbol *Symbol) { + MCELFStreamer::EmitLabel(Symbol); + Labels.push_back(Symbol); +} + +void MipsELFStreamer::SwitchSection(MCSection *Section, + const MCExpr *Subsection) { + MCELFStreamer::SwitchSection(Section, Subsection); + Labels.clear(); +} + +void MipsELFStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, + SMLoc Loc) { + MCELFStreamer::EmitValueImpl(Value, Size, Loc); + Labels.clear(); +} + +void MipsELFStreamer::EmitMipsOptionRecords() { + for (const auto &I : MipsOptionRecords) + I->EmitMipsOptionRecord(); +} + +MCELFStreamer *llvm::createMipsELFStreamer(MCContext &Context, + MCAsmBackend &MAB, + raw_pwrite_stream &OS, + MCCodeEmitter *Emitter, + bool RelaxAll) { + return new MipsELFStreamer(Context, MAB, OS, Emitter); +} diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.h new file mode 100644 index 0000000..a241cde --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.h @@ -0,0 +1,76 @@ +//===-------- 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 LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSELFSTREAMER_H +#define LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSELFSTREAMER_H + +#include "MipsOptionRecord.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/MC/MCELFStreamer.h" +#include <memory> + +namespace llvm { +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCSubtargetInfo; + +class MipsELFStreamer : public MCELFStreamer { + SmallVector<std::unique_ptr<MipsOptionRecord>, 8> MipsOptionRecords; + MipsRegInfoRecord *RegInfoRecord; + SmallVector<MCSymbol*, 4> Labels; + + +public: + MipsELFStreamer(MCContext &Context, MCAsmBackend &MAB, raw_pwrite_stream &OS, + MCCodeEmitter *Emitter) + : MCELFStreamer(Context, MAB, OS, Emitter) { + + RegInfoRecord = new MipsRegInfoRecord(this, Context); + MipsOptionRecords.push_back( + std::unique_ptr<MipsRegInfoRecord>(RegInfoRecord)); + } + + /// Overriding this function allows us to add arbitrary behaviour before the + /// \p Inst is actually emitted. For example, we can inspect the operands and + /// gather sufficient information that allows us to reason about the register + /// usage for the translation unit. + void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override; + + /// Overriding this function allows us to record all labels that should be + /// marked as microMIPS. Based on this data marking is done in + /// EmitInstruction. + void EmitLabel(MCSymbol *Symbol) override; + + /// Overriding this function allows us to dismiss all labels that are + /// candidates for marking as microMIPS when .section directive is processed. + void SwitchSection(MCSection *Section, + const MCExpr *Subsection = nullptr) override; + + /// Overriding this function allows us to dismiss all labels that are + /// candidates for marking as microMIPS when .word directive is emitted. + void EmitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) override; + + /// Emits all the option records stored up until the point it's called. + void EmitMipsOptionRecords(); + + /// Mark labels as microMIPS, if necessary for the subtarget. + void createPendingLabelRelocs(); +}; + +MCELFStreamer *createMipsELFStreamer(MCContext &Context, MCAsmBackend &MAB, + raw_pwrite_stream &OS, + MCCodeEmitter *Emitter, bool RelaxAll); +} // namespace llvm. +#endif diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h new file mode 100644 index 0000000..3652f4b --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h @@ -0,0 +1,211 @@ +//===-- MipsFixupKinds.h - Mips Specific Fixup Entries ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSFIXUPKINDS_H +#define LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSFIXUPKINDS_H + +#include "llvm/MC/MCFixup.h" + +namespace llvm { +namespace Mips { + // Although most of the current fixup types reflect a unique relocation + // one can have multiple fixup types for a given relocation and thus need + // to be uniquely named. + // + // This table *must* be in the same order of + // MCFixupKindInfo Infos[Mips::NumTargetFixupKinds] + // in MipsAsmBackend.cpp. + // + enum Fixups { + // Branch fixups resulting in R_MIPS_NONE. + fixup_Mips_NONE = FirstTargetFixupKind, + + // Branch fixups resulting in R_MIPS_16. + fixup_Mips_16, + + // Pure 32 bit data fixup resulting in - R_MIPS_32. + fixup_Mips_32, + + // Full 32 bit data relative data fixup resulting in - R_MIPS_REL32. + fixup_Mips_REL32, + + // Jump 26 bit fixup resulting in - R_MIPS_26. + fixup_Mips_26, + + // Pure upper 16 bit fixup resulting in - R_MIPS_HI16. + fixup_Mips_HI16, + + // Pure lower 16 bit fixup resulting in - R_MIPS_LO16. + fixup_Mips_LO16, + + // 16 bit fixup for GP offest resulting in - R_MIPS_GPREL16. + fixup_Mips_GPREL16, + + // 16 bit literal fixup resulting in - R_MIPS_LITERAL. + fixup_Mips_LITERAL, + + // Global symbol fixup resulting in - R_MIPS_GOT16. + fixup_Mips_GOT_Global, + + // Local symbol fixup resulting in - R_MIPS_GOT16. + fixup_Mips_GOT_Local, + + // PC relative branch fixup resulting in - R_MIPS_PC16. + fixup_Mips_PC16, + + // resulting in - R_MIPS_CALL16. + fixup_Mips_CALL16, + + // resulting in - R_MIPS_GPREL32. + fixup_Mips_GPREL32, + + // resulting in - R_MIPS_SHIFT5. + fixup_Mips_SHIFT5, + + // resulting in - R_MIPS_SHIFT6. + fixup_Mips_SHIFT6, + + // Pure 64 bit data fixup resulting in - R_MIPS_64. + fixup_Mips_64, + + // resulting in - R_MIPS_TLS_GD. + fixup_Mips_TLSGD, + + // resulting in - R_MIPS_TLS_GOTTPREL. + fixup_Mips_GOTTPREL, + + // resulting in - R_MIPS_TLS_TPREL_HI16. + fixup_Mips_TPREL_HI, + + // resulting in - R_MIPS_TLS_TPREL_LO16. + fixup_Mips_TPREL_LO, + + // resulting in - R_MIPS_TLS_LDM. + fixup_Mips_TLSLDM, + + // resulting in - R_MIPS_TLS_DTPREL_HI16. + fixup_Mips_DTPREL_HI, + + // resulting in - R_MIPS_TLS_DTPREL_LO16. + fixup_Mips_DTPREL_LO, + + // PC relative branch fixup resulting in - R_MIPS_PC16 + fixup_Mips_Branch_PCRel, + + // resulting in - R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_HI16 + fixup_Mips_GPOFF_HI, + + // resulting in - R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_LO16 + fixup_Mips_GPOFF_LO, + + // resulting in - R_MIPS_PAGE + fixup_Mips_GOT_PAGE, + + // resulting in - R_MIPS_GOT_OFST + fixup_Mips_GOT_OFST, + + // resulting in - R_MIPS_GOT_DISP + fixup_Mips_GOT_DISP, + + // resulting in - R_MIPS_GOT_HIGHER + fixup_Mips_HIGHER, + + // resulting in - R_MIPS_HIGHEST + fixup_Mips_HIGHEST, + + // resulting in - R_MIPS_GOT_HI16 + fixup_Mips_GOT_HI16, + + // resulting in - R_MIPS_GOT_LO16 + fixup_Mips_GOT_LO16, + + // resulting in - R_MIPS_CALL_HI16 + fixup_Mips_CALL_HI16, + + // resulting in - R_MIPS_CALL_LO16 + fixup_Mips_CALL_LO16, + + // resulting in - R_MIPS_PC18_S3 + fixup_MIPS_PC18_S3, + + // resulting in - R_MIPS_PC19_S2 + fixup_MIPS_PC19_S2, + + // resulting in - R_MIPS_PC21_S2 + fixup_MIPS_PC21_S2, + + // resulting in - R_MIPS_PC26_S2 + fixup_MIPS_PC26_S2, + + // resulting in - R_MIPS_PCHI16 + fixup_MIPS_PCHI16, + + // resulting in - R_MIPS_PCLO16 + fixup_MIPS_PCLO16, + + // resulting in - R_MICROMIPS_26_S1 + fixup_MICROMIPS_26_S1, + + // resulting in - R_MICROMIPS_HI16 + fixup_MICROMIPS_HI16, + + // resulting in - R_MICROMIPS_LO16 + fixup_MICROMIPS_LO16, + + // resulting in - R_MICROMIPS_GOT16 + fixup_MICROMIPS_GOT16, + + // resulting in - R_MICROMIPS_PC7_S1 + fixup_MICROMIPS_PC7_S1, + + // resulting in - R_MICROMIPS_PC10_S1 + fixup_MICROMIPS_PC10_S1, + + // resulting in - R_MICROMIPS_PC16_S1 + fixup_MICROMIPS_PC16_S1, + + // resulting in - R_MICROMIPS_CALL16 + fixup_MICROMIPS_CALL16, + + // resulting in - R_MICROMIPS_GOT_DISP + fixup_MICROMIPS_GOT_DISP, + + // resulting in - R_MICROMIPS_GOT_PAGE + fixup_MICROMIPS_GOT_PAGE, + + // resulting in - R_MICROMIPS_GOT_OFST + fixup_MICROMIPS_GOT_OFST, + + // resulting in - R_MICROMIPS_TLS_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, + + // resulting in - R_MICROMIPS_TLS_DTPREL_LO16 + fixup_MICROMIPS_TLS_DTPREL_LO16, + + // resulting in - R_MICROMIPS_TLS_TPREL_HI16 + fixup_MICROMIPS_TLS_TPREL_HI16, + + // resulting in - R_MICROMIPS_TLS_TPREL_LO16 + fixup_MICROMIPS_TLS_TPREL_LO16, + + // Marker + LastTargetFixupKind, + NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind + }; +} // namespace Mips +} // namespace llvm + + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp new file mode 100644 index 0000000..4d55458 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp @@ -0,0 +1,45 @@ +//===-- MipsMCAsmInfo.cpp - Mips Asm Properties ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declarations of the MipsMCAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "MipsMCAsmInfo.h" +#include "llvm/ADT/Triple.h" + +using namespace llvm; + +void MipsMCAsmInfo::anchor() { } + +MipsMCAsmInfo::MipsMCAsmInfo(const Triple &TheTriple) { + if ((TheTriple.getArch() == Triple::mips) || + (TheTriple.getArch() == Triple::mips64)) + IsLittleEndian = false; + + if ((TheTriple.getArch() == Triple::mips64el) || + (TheTriple.getArch() == Triple::mips64)) { + PointerSize = CalleeSaveStackSlotSize = 8; + } + + AlignmentIsInBytes = false; + Data16bitsDirective = "\t.2byte\t"; + Data32bitsDirective = "\t.4byte\t"; + Data64bitsDirective = "\t.8byte\t"; + PrivateGlobalPrefix = "$"; + PrivateLabelPrefix = "$"; + CommentString = "#"; + ZeroDirective = "\t.space\t"; + GPRel32Directive = "\t.gpword\t"; + GPRel64Directive = "\t.gpdword\t"; + UseAssignmentForEHBegin = true; + SupportsDebugInformation = true; + ExceptionsType = ExceptionHandling::DwarfCFI; + DwarfRegNumForCFI = true; +} diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h new file mode 100644 index 0000000..d4ccf03 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h @@ -0,0 +1,31 @@ +//===-- MipsMCAsmInfo.h - Mips Asm Info ------------------------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the MipsMCAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSMCASMINFO_H +#define LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSMCASMINFO_H + +#include "llvm/MC/MCAsmInfoELF.h" + +namespace llvm { +class Triple; + +class MipsMCAsmInfo : public MCAsmInfoELF { + void anchor() override; + +public: + explicit MipsMCAsmInfo(const Triple &TheTriple); +}; + +} // namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp new file mode 100644 index 0000000..4b030eb --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -0,0 +1,1052 @@ +//===-- MipsMCCodeEmitter.cpp - Convert Mips Code to Machine Code ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the MipsMCCodeEmitter class. +// +//===----------------------------------------------------------------------===// +// + +#include "MipsMCCodeEmitter.h" +#include "MCTargetDesc/MipsFixupKinds.h" +#include "MCTargetDesc/MipsMCExpr.h" +#include "MCTargetDesc/MipsMCTargetDesc.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/raw_ostream.h" + +#define DEBUG_TYPE "mccodeemitter" + +#define GET_INSTRMAP_INFO +#include "MipsGenInstrInfo.inc" +#undef GET_INSTRMAP_INFO + +namespace llvm { +MCCodeEmitter *createMipsMCCodeEmitterEB(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + MCContext &Ctx) { + return new MipsMCCodeEmitter(MCII, Ctx, false); +} + +MCCodeEmitter *createMipsMCCodeEmitterEL(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + 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 +static void LowerLargeShift(MCInst& Inst) { + + assert(Inst.getNumOperands() == 3 && "Invalid no. of operands for shift!"); + assert(Inst.getOperand(2).isImm()); + + int64_t Shift = Inst.getOperand(2).getImm(); + if (Shift <= 31) + return; // Do nothing + Shift -= 32; + + // saminus32 + Inst.getOperand(2).setImm(Shift); + + switch (Inst.getOpcode()) { + default: + // Calling function is not synchronized + llvm_unreachable("Unexpected shift instruction"); + case Mips::DSLL: + Inst.setOpcode(Mips::DSLL32); + return; + case Mips::DSRL: + Inst.setOpcode(Mips::DSRL32); + return; + case Mips::DSRA: + Inst.setOpcode(Mips::DSRA32); + return; + case Mips::DROTR: + Inst.setOpcode(Mips::DROTR32); + return; + } +} + +// Pick a DEXT or DINS instruction variant based on the pos and size operands +static void LowerDextDins(MCInst& InstIn) { + int Opcode = InstIn.getOpcode(); + + if (Opcode == Mips::DEXT) + assert(InstIn.getNumOperands() == 4 && + "Invalid no. of machine operands for DEXT!"); + else // Only DEXT and DINS are possible + assert(InstIn.getNumOperands() == 5 && + "Invalid no. of machine operands for DINS!"); + + assert(InstIn.getOperand(2).isImm()); + int64_t pos = InstIn.getOperand(2).getImm(); + assert(InstIn.getOperand(3).isImm()); + int64_t size = InstIn.getOperand(3).getImm(); + + if (size <= 32) { + if (pos < 32) // DEXT/DINS, do nothing + return; + // DEXTU/DINSU + InstIn.getOperand(2).setImm(pos - 32); + InstIn.setOpcode((Opcode == Mips::DEXT) ? Mips::DEXTU : Mips::DINSU); + return; + } + // DEXTM/DINSM + assert(pos < 32 && "DEXT/DINS cannot have both size and pos > 32"); + InstIn.getOperand(3).setImm(size - 32); + InstIn.setOpcode((Opcode == Mips::DEXT) ? Mips::DEXTM : Mips::DINSM); + return; +} + +bool MipsMCCodeEmitter::isMicroMips(const MCSubtargetInfo &STI) const { + return STI.getFeatureBits()[Mips::FeatureMicroMips]; +} + +bool MipsMCCodeEmitter::isMips32r6(const MCSubtargetInfo &STI) const { + return STI.getFeatureBits()[Mips::FeatureMips32r6]; +} + +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 MCSubtargetInfo &STI) const +{ + + // Non-pseudo instructions that get changed for direct object + // only based on operand values. + // If this list of instructions get much longer we will move + // the check to a function call. Until then, this is more efficient. + MCInst TmpInst = MI; + switch (MI.getOpcode()) { + // If shift amount is >= 32 it the inst needs to be lowered further + case Mips::DSLL: + case Mips::DSRL: + case Mips::DSRA: + case Mips::DROTR: + LowerLargeShift(TmpInst); + break; + // Double extract instruction is chosen by pos and size operands + case Mips::DEXT: + case Mips::DINS: + LowerDextDins(TmpInst); + } + + unsigned long N = Fixups.size(); + uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI); + + // Check for unimplemented opcodes. + // Unfortunately in MIPS both NOP and SLL will come in with Binary == 0 + // so we have to special check for them. + unsigned Opcode = TmpInst.getOpcode(); + if ((Opcode != Mips::NOP) && (Opcode != Mips::SLL) && + (Opcode != Mips::SLL_MM) && !Binary) + llvm_unreachable("unimplemented opcode in encodeInstruction()"); + + int NewOpcode = -1; + if (isMicroMips(STI)) { + if (isMips32r6(STI)) { + NewOpcode = Mips::MipsR62MicroMipsR6(Opcode, Mips::Arch_micromipsr6); + if (NewOpcode == -1) + NewOpcode = Mips::Std2MicroMipsR6(Opcode, Mips::Arch_micromipsr6); + } + else + NewOpcode = Mips::Std2MicroMips(Opcode, Mips::Arch_micromips); + + // Check whether it is Dsp instruction. + if (NewOpcode == -1) + NewOpcode = Mips::Dsp2MicroMips(Opcode, Mips::Arch_mmdsp); + + if (NewOpcode != -1) { + if (Fixups.size() > N) + Fixups.pop_back(); + + Opcode = NewOpcode; + TmpInst.setOpcode (NewOpcode); + Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI); + } + } + + const MCInstrDesc &Desc = MCII.get(TmpInst.getOpcode()); + + // Get byte count of instruction + unsigned Size = Desc.getSize(); + if (!Size) + llvm_unreachable("Desc.getSize() returns 0"); + + EmitInstruction(Binary, Size, STI, OS); +} + +/// getBranchTargetOpValue - Return binary encoding of the branch +/// target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getBranchTargetOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + + const MCOperand &MO = MI.getOperand(OpNo); + + // If the destination is an immediate, divide by 4. + if (MO.isImm()) return MO.getImm() >> 2; + + assert(MO.isExpr() && + "getBranchTargetOpValue expects only expressions or immediates"); + + const MCExpr *FixupExpression = MCBinaryExpr::createAdd( + MO.getExpr(), MCConstantExpr::create(-4, Ctx), Ctx); + Fixups.push_back(MCFixup::create(0, FixupExpression, + MCFixupKind(Mips::fixup_Mips_PC16))); + return 0; +} + +/// getBranchTarget7OpValueMM - Return binary encoding of the microMIPS branch +/// target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getBranchTarget7OpValueMM(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + + const MCOperand &MO = MI.getOperand(OpNo); + + // If the destination is an immediate, divide by 2. + if (MO.isImm()) return MO.getImm() >> 1; + + assert(MO.isExpr() && + "getBranchTargetOpValueMM expects only expressions or immediates"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::create(0, Expr, + MCFixupKind(Mips::fixup_MICROMIPS_PC7_S1))); + return 0; +} + +/// getBranchTargetOpValueMMPC10 - Return binary encoding of the microMIPS +/// 10-bit branch target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getBranchTargetOpValueMMPC10(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + + const MCOperand &MO = MI.getOperand(OpNo); + + // If the destination is an immediate, divide by 2. + if (MO.isImm()) return MO.getImm() >> 1; + + assert(MO.isExpr() && + "getBranchTargetOpValuePC10 expects only expressions or immediates"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::create(0, Expr, + MCFixupKind(Mips::fixup_MICROMIPS_PC10_S1))); + return 0; +} + +/// getBranchTargetOpValue - Return binary encoding of the microMIPS branch +/// target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getBranchTargetOpValueMM(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + + const MCOperand &MO = MI.getOperand(OpNo); + + // If the destination is an immediate, divide by 2. + if (MO.isImm()) return MO.getImm() >> 1; + + assert(MO.isExpr() && + "getBranchTargetOpValueMM expects only expressions or immediates"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::create(0, Expr, + MCFixupKind(Mips:: + fixup_MICROMIPS_PC16_S1))); + return 0; +} + +/// getBranchTarget21OpValue - Return binary encoding of the branch +/// target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getBranchTarget21OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + + const MCOperand &MO = MI.getOperand(OpNo); + + // If the destination is an immediate, divide by 4. + if (MO.isImm()) return MO.getImm() >> 2; + + assert(MO.isExpr() && + "getBranchTarget21OpValue expects only expressions or immediates"); + + const MCExpr *FixupExpression = MCBinaryExpr::createAdd( + MO.getExpr(), MCConstantExpr::create(-4, Ctx), Ctx); + Fixups.push_back(MCFixup::create(0, FixupExpression, + MCFixupKind(Mips::fixup_MIPS_PC21_S2))); + return 0; +} + +/// getBranchTarget26OpValue - Return binary encoding of the branch +/// target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getBranchTarget26OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + + const MCOperand &MO = MI.getOperand(OpNo); + + // If the destination is an immediate, divide by 4. + if (MO.isImm()) return MO.getImm() >> 2; + + assert(MO.isExpr() && + "getBranchTarget26OpValue expects only expressions or immediates"); + + const MCExpr *FixupExpression = MCBinaryExpr::createAdd( + MO.getExpr(), MCConstantExpr::create(-4, Ctx), Ctx); + Fixups.push_back(MCFixup::create(0, FixupExpression, + MCFixupKind(Mips::fixup_MIPS_PC26_S2))); + return 0; +} + +/// getBranchTarget26OpValueMM - Return binary encoding of the branch +/// target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter::getBranchTarget26OpValueMM( + const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + + const MCOperand &MO = MI.getOperand(OpNo); + + // If the destination is an immediate, divide by 2. + if (MO.isImm()) + return MO.getImm() >> 1; + + // TODO: Push 26 PC fixup. + return 0; +} + +/// getJumpOffset16OpValue - Return binary encoding of the jump +/// target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getJumpOffset16OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + + const MCOperand &MO = MI.getOperand(OpNo); + + if (MO.isImm()) return MO.getImm(); + + assert(MO.isExpr() && + "getJumpOffset16OpValue expects only expressions or an immediate"); + + // TODO: Push fixup. + return 0; +} + +/// getJumpTargetOpValue - Return binary encoding of the jump +/// target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getJumpTargetOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + + const MCOperand &MO = MI.getOperand(OpNo); + // If the destination is an immediate, divide by 4. + if (MO.isImm()) return MO.getImm()>>2; + + assert(MO.isExpr() && + "getJumpTargetOpValue expects only expressions or an immediate"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::create(0, Expr, + MCFixupKind(Mips::fixup_Mips_26))); + return 0; +} + +unsigned MipsMCCodeEmitter:: +getJumpTargetOpValueMM(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + + const MCOperand &MO = MI.getOperand(OpNo); + // If the destination is an immediate, divide by 2. + if (MO.isImm()) return MO.getImm() >> 1; + + assert(MO.isExpr() && + "getJumpTargetOpValueMM expects only expressions or an immediate"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::create(0, Expr, + MCFixupKind(Mips::fixup_MICROMIPS_26_S1))); + return 0; +} + +unsigned MipsMCCodeEmitter:: +getUImm5Lsl2Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isImm()) { + // The immediate is encoded as 'immediate << 2'. + unsigned Res = getMachineOpValue(MI, MO, Fixups, STI); + assert((Res & 3) == 0); + return Res >> 2; + } + + assert(MO.isExpr() && + "getUImm5Lsl2Encoding expects only expressions or an immediate"); + + return 0; +} + +unsigned MipsMCCodeEmitter:: +getSImm3Lsa2Value(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isImm()) { + int Value = MO.getImm(); + return Value >> 2; + } + + return 0; +} + +unsigned MipsMCCodeEmitter:: +getUImm6Lsl2Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isImm()) { + unsigned Value = MO.getImm(); + return Value >> 2; + } + + return 0; +} + +unsigned MipsMCCodeEmitter:: +getSImm9AddiuspValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isImm()) { + unsigned Binary = (MO.getImm() >> 2) & 0x0000ffff; + return (((Binary & 0x8000) >> 7) | (Binary & 0x00ff)); + } + + return 0; +} + +unsigned MipsMCCodeEmitter:: +getExprOpValue(const MCExpr *Expr, SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + int64_t Res; + + if (Expr->evaluateAsAbsolute(Res)) + return Res; + + MCExpr::ExprKind Kind = Expr->getKind(); + if (Kind == MCExpr::Constant) { + return cast<MCConstantExpr>(Expr)->getValue(); + } + + if (Kind == MCExpr::Binary) { + unsigned Res = getExprOpValue(cast<MCBinaryExpr>(Expr)->getLHS(), Fixups, STI); + Res += getExprOpValue(cast<MCBinaryExpr>(Expr)->getRHS(), Fixups, STI); + return Res; + } + + if (Kind == MCExpr::Target) { + const MipsMCExpr *MipsExpr = cast<MipsMCExpr>(Expr); + + Mips::Fixups FixupKind = Mips::Fixups(0); + switch (MipsExpr->getKind()) { + default: llvm_unreachable("Unsupported fixup kind for target expression!"); + case MipsMCExpr::VK_Mips_HIGHEST: + FixupKind = Mips::fixup_Mips_HIGHEST; + break; + case MipsMCExpr::VK_Mips_HIGHER: + FixupKind = Mips::fixup_Mips_HIGHER; + break; + case MipsMCExpr::VK_Mips_HI: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_HI16 + : Mips::fixup_Mips_HI16; + break; + case MipsMCExpr::VK_Mips_LO: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_LO16 + : Mips::fixup_Mips_LO16; + break; + } + Fixups.push_back(MCFixup::create(0, MipsExpr, MCFixupKind(FixupKind))); + return 0; + } + + if (Kind == MCExpr::SymbolRef) { + Mips::Fixups FixupKind = Mips::Fixups(0); + + switch(cast<MCSymbolRefExpr>(Expr)->getKind()) { + default: llvm_unreachable("Unknown fixup kind!"); + break; + case MCSymbolRefExpr::VK_None: + FixupKind = Mips::fixup_Mips_32; // FIXME: This is ok for O32/N32 but not N64. + break; + case MCSymbolRefExpr::VK_Mips_GPOFF_HI : + FixupKind = Mips::fixup_Mips_GPOFF_HI; + break; + case MCSymbolRefExpr::VK_Mips_GPOFF_LO : + FixupKind = Mips::fixup_Mips_GPOFF_LO; + break; + case MCSymbolRefExpr::VK_Mips_GOT_PAGE : + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_GOT_PAGE + : Mips::fixup_Mips_GOT_PAGE; + break; + case MCSymbolRefExpr::VK_Mips_GOT_OFST : + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_GOT_OFST + : Mips::fixup_Mips_GOT_OFST; + break; + case MCSymbolRefExpr::VK_Mips_GOT_DISP : + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_GOT_DISP + : Mips::fixup_Mips_GOT_DISP; + break; + case MCSymbolRefExpr::VK_Mips_GPREL: + FixupKind = Mips::fixup_Mips_GPREL16; + break; + case MCSymbolRefExpr::VK_Mips_GOT_CALL: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_CALL16 + : Mips::fixup_Mips_CALL16; + break; + case MCSymbolRefExpr::VK_Mips_GOT16: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_GOT16 + : Mips::fixup_Mips_GOT_Global; + break; + case MCSymbolRefExpr::VK_Mips_GOT: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_GOT16 + : Mips::fixup_Mips_GOT_Local; + break; + case MCSymbolRefExpr::VK_Mips_ABS_HI: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_HI16 + : Mips::fixup_Mips_HI16; + break; + case MCSymbolRefExpr::VK_Mips_ABS_LO: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_LO16 + : Mips::fixup_Mips_LO16; + break; + case MCSymbolRefExpr::VK_Mips_TLSGD: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_GD + : Mips::fixup_Mips_TLSGD; + break; + case MCSymbolRefExpr::VK_Mips_TLSLDM: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_LDM + : Mips::fixup_Mips_TLSLDM; + break; + case MCSymbolRefExpr::VK_Mips_DTPREL_HI: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_DTPREL_HI16 + : Mips::fixup_Mips_DTPREL_HI; + break; + case MCSymbolRefExpr::VK_Mips_DTPREL_LO: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_DTPREL_LO16 + : Mips::fixup_Mips_DTPREL_LO; + break; + case MCSymbolRefExpr::VK_Mips_GOTTPREL: + FixupKind = Mips::fixup_Mips_GOTTPREL; + break; + case MCSymbolRefExpr::VK_Mips_TPREL_HI: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_TPREL_HI16 + : Mips::fixup_Mips_TPREL_HI; + break; + case MCSymbolRefExpr::VK_Mips_TPREL_LO: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_TPREL_LO16 + : Mips::fixup_Mips_TPREL_LO; + break; + case MCSymbolRefExpr::VK_Mips_HIGHER: + FixupKind = Mips::fixup_Mips_HIGHER; + break; + case MCSymbolRefExpr::VK_Mips_HIGHEST: + FixupKind = Mips::fixup_Mips_HIGHEST; + break; + case MCSymbolRefExpr::VK_Mips_GOT_HI16: + FixupKind = Mips::fixup_Mips_GOT_HI16; + break; + case MCSymbolRefExpr::VK_Mips_GOT_LO16: + FixupKind = Mips::fixup_Mips_GOT_LO16; + break; + case MCSymbolRefExpr::VK_Mips_CALL_HI16: + FixupKind = Mips::fixup_Mips_CALL_HI16; + break; + case MCSymbolRefExpr::VK_Mips_CALL_LO16: + FixupKind = Mips::fixup_Mips_CALL_LO16; + break; + case MCSymbolRefExpr::VK_Mips_PCREL_HI16: + FixupKind = Mips::fixup_MIPS_PCHI16; + break; + case MCSymbolRefExpr::VK_Mips_PCREL_LO16: + FixupKind = Mips::fixup_MIPS_PCLO16; + break; + } // switch + + Fixups.push_back(MCFixup::create(0, Expr, MCFixupKind(FixupKind))); + return 0; + } + return 0; +} + +/// getMachineOpValue - Return binary encoding of operand. If the machine +/// operand requires relocation, record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + if (MO.isReg()) { + unsigned Reg = MO.getReg(); + unsigned RegNo = Ctx.getRegisterInfo()->getEncodingValue(Reg); + return RegNo; + } else if (MO.isImm()) { + return static_cast<unsigned>(MO.getImm()); + } else if (MO.isFPImm()) { + return static_cast<unsigned>(APFloat(MO.getFPImm()) + .bitcastToAPInt().getHiBits(32).getLimitedValue()); + } + // MO must be an Expr. + assert(MO.isExpr()); + return getExprOpValue(MO.getExpr(),Fixups, 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 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); + + return (OffBits & 0xFFFF) | RegBits; +} + +unsigned MipsMCCodeEmitter:: +getMemEncodingMMImm4(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // Base register is encoded in bits 6-4, offset is encoded in bits 3-0. + assert(MI.getOperand(OpNo).isReg()); + unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo), + Fixups, STI) << 4; + unsigned OffBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), + Fixups, STI); + + return (OffBits & 0xF) | RegBits; +} + +unsigned MipsMCCodeEmitter:: +getMemEncodingMMImm4Lsl1(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // Base register is encoded in bits 6-4, offset is encoded in bits 3-0. + assert(MI.getOperand(OpNo).isReg()); + unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo), + Fixups, STI) << 4; + unsigned OffBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), + Fixups, STI) >> 1; + + return (OffBits & 0xF) | RegBits; +} + +unsigned MipsMCCodeEmitter:: +getMemEncodingMMImm4Lsl2(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // Base register is encoded in bits 6-4, offset is encoded in bits 3-0. + assert(MI.getOperand(OpNo).isReg()); + unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo), + Fixups, STI) << 4; + unsigned OffBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), + Fixups, STI) >> 2; + + return (OffBits & 0xF) | RegBits; +} + +unsigned MipsMCCodeEmitter:: +getMemEncodingMMSPImm5Lsl2(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // Register is encoded in bits 9-5, offset is encoded in bits 4-0. + assert(MI.getOperand(OpNo).isReg() && + (MI.getOperand(OpNo).getReg() == Mips::SP || + MI.getOperand(OpNo).getReg() == Mips::SP_64) && + "Unexpected base register!"); + unsigned OffBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), + Fixups, STI) >> 2; + + return OffBits & 0x1F; +} + +unsigned MipsMCCodeEmitter:: +getMemEncodingMMGPImm7Lsl2(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // Register is encoded in bits 9-7, offset is encoded in bits 6-0. + assert(MI.getOperand(OpNo).isReg() && + MI.getOperand(OpNo).getReg() == Mips::GP && + "Unexpected base register!"); + + unsigned OffBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), + Fixups, STI) >> 2; + + return OffBits & 0x7F; +} + +unsigned MipsMCCodeEmitter:: +getMemEncodingMMImm9(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 8-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); + + return (OffBits & 0x1FF) | RegBits; +} + +unsigned MipsMCCodeEmitter:: +getMemEncodingMMImm12(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // opNum can be invalid if instruction had reglist as operand. + // MemOperand is always last operand of instruction (base + offset). + switch (MI.getOpcode()) { + default: + break; + case Mips::SWM32_MM: + case Mips::LWM32_MM: + OpNo = MI.getNumOperands() - 2; + break; + } + + // 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, STI) << 16; + unsigned OffBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups, STI); + + return (OffBits & 0x0FFF) | RegBits; +} + +unsigned MipsMCCodeEmitter:: +getMemEncodingMMImm16(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); + + return (OffBits & 0xFFFF) | RegBits; +} + +unsigned MipsMCCodeEmitter:: +getMemEncodingMMImm4sp(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // opNum can be invalid if instruction had reglist as operand + // MemOperand is always last operand of instruction (base + offset) + switch (MI.getOpcode()) { + default: + break; + case Mips::SWM16_MM: + case Mips::SWM16_MMR6: + case Mips::LWM16_MM: + case Mips::LWM16_MMR6: + OpNo = MI.getNumOperands() - 2; + break; + } + + // Offset is encoded in bits 4-0. + assert(MI.getOperand(OpNo).isReg()); + // Base register is always SP - thus it is not encoded. + assert(MI.getOperand(OpNo+1).isImm()); + unsigned OffBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups, STI); + + return ((OffBits >> 2) & 0x0F); +} + +// FIXME: should be called getMSBEncoding +// +unsigned +MipsMCCodeEmitter::getSizeInsEncoding(const MCInst &MI, unsigned OpNo, + 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, STI); + unsigned Size = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI); + + return Position + Size - 1; +} + +template <unsigned Bits, int Offset> +unsigned +MipsMCCodeEmitter::getUImmWithOffsetEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + assert(MI.getOperand(OpNo).isImm()); + unsigned Value = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI); + Value -= Offset; + return Value; +} + +unsigned +MipsMCCodeEmitter::getSimm19Lsl2Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isImm()) { + // The immediate is encoded as 'immediate << 2'. + unsigned Res = getMachineOpValue(MI, MO, Fixups, STI); + assert((Res & 3) == 0); + return Res >> 2; + } + + assert(MO.isExpr() && + "getSimm19Lsl2Encoding expects only expressions or an immediate"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::create(0, Expr, + MCFixupKind(Mips::fixup_MIPS_PC19_S2))); + return 0; +} + +unsigned +MipsMCCodeEmitter::getSimm18Lsl3Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isImm()) { + // The immediate is encoded as 'immediate << 3'. + unsigned Res = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI); + assert((Res & 7) == 0); + return Res >> 3; + } + + assert(MO.isExpr() && + "getSimm18Lsl2Encoding expects only expressions or an immediate"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::create(0, Expr, + MCFixupKind(Mips::fixup_MIPS_PC18_S3))); + return 0; +} + +unsigned +MipsMCCodeEmitter::getUImm3Mod8Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + assert(MI.getOperand(OpNo).isImm()); + const MCOperand &MO = MI.getOperand(OpNo); + return MO.getImm() % 8; +} + +unsigned +MipsMCCodeEmitter::getUImm4AndValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + assert(MI.getOperand(OpNo).isImm()); + const MCOperand &MO = MI.getOperand(OpNo); + unsigned Value = MO.getImm(); + switch (Value) { + case 128: return 0x0; + case 1: return 0x1; + case 2: return 0x2; + case 3: return 0x3; + case 4: return 0x4; + case 7: return 0x5; + case 8: return 0x6; + case 15: return 0x7; + case 16: return 0x8; + case 31: return 0x9; + case 32: return 0xa; + case 63: return 0xb; + case 64: return 0xc; + case 255: return 0xd; + case 32768: return 0xe; + case 65535: return 0xf; + } + llvm_unreachable("Unexpected value"); +} + +unsigned +MipsMCCodeEmitter::getRegisterListOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + unsigned res = 0; + + // Register list operand is always first operand of instruction and it is + // placed before memory operand (register + imm). + + for (unsigned I = OpNo, E = MI.getNumOperands() - 2; I < E; ++I) { + unsigned Reg = MI.getOperand(I).getReg(); + unsigned RegNo = Ctx.getRegisterInfo()->getEncodingValue(Reg); + if (RegNo != 31) + res++; + else + res |= 0x10; + } + return res; +} + +unsigned +MipsMCCodeEmitter::getRegisterListOpValue16(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + return (MI.getNumOperands() - 4); +} + +unsigned +MipsMCCodeEmitter::getRegisterPairOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + return getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI); +} + +unsigned +MipsMCCodeEmitter::getMovePRegPairOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + unsigned res = 0; + + if (MI.getOperand(0).getReg() == Mips::A1 && + MI.getOperand(1).getReg() == Mips::A2) + res = 0; + else if (MI.getOperand(0).getReg() == Mips::A1 && + MI.getOperand(1).getReg() == Mips::A3) + res = 1; + else if (MI.getOperand(0).getReg() == Mips::A2 && + MI.getOperand(1).getReg() == Mips::A3) + res = 2; + else if (MI.getOperand(0).getReg() == Mips::A0 && + MI.getOperand(1).getReg() == Mips::S5) + res = 3; + else if (MI.getOperand(0).getReg() == Mips::A0 && + MI.getOperand(1).getReg() == Mips::S6) + res = 4; + else if (MI.getOperand(0).getReg() == Mips::A0 && + MI.getOperand(1).getReg() == Mips::A1) + res = 5; + else if (MI.getOperand(0).getReg() == Mips::A0 && + MI.getOperand(1).getReg() == Mips::A2) + res = 6; + else if (MI.getOperand(0).getReg() == Mips::A0 && + MI.getOperand(1).getReg() == Mips::A3) + res = 7; + + return res; +} + +unsigned +MipsMCCodeEmitter::getSimm23Lsl2Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + assert(MO.isImm() && "getSimm23Lsl2Encoding expects only an immediate"); + // The immediate is encoded as 'immediate >> 2'. + unsigned Res = static_cast<unsigned>(MO.getImm()); + assert((Res & 3) == 0); + return Res >> 2; +} + +#include "MipsGenMCCodeEmitter.inc" diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h new file mode 100644 index 0000000..fdacd17 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h @@ -0,0 +1,244 @@ +//===-- 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 LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSMCCODEEMITTER_H +#define LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSMCCODEEMITTER_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 &) = delete; + void operator=(const MipsMCCodeEmitter &) = delete; + const MCInstrInfo &MCII; + MCContext &Ctx; + bool IsLittleEndian; + + bool isMicroMips(const MCSubtargetInfo &STI) const; + bool isMips32r6(const MCSubtargetInfo &STI) const; + +public: + MipsMCCodeEmitter(const MCInstrInfo &mcii, MCContext &Ctx_, bool IsLittle) + : MCII(mcii), Ctx(Ctx_), IsLittleEndian(IsLittle) {} + + ~MipsMCCodeEmitter() override {} + + void EmitByte(unsigned char C, raw_ostream &OS) const; + + void EmitInstruction(uint64_t Val, unsigned Size, const MCSubtargetInfo &STI, + raw_ostream &OS) const; + + void encodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const override; + + // getBinaryCodeForInstr - TableGen'erated function for getting the + // binary encoding for an instruction. + uint64_t getBinaryCodeForInstr(const MCInst &MI, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + // getJumpTargetOpValue - 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; + + // getUImm5Lsl2Encoding - Return binary encoding of the microMIPS jump + // target operand. + unsigned getUImm5Lsl2Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getSImm3Lsa2Value(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getUImm6Lsl2Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + // getSImm9AddiuspValue - Return binary encoding of the microMIPS addiusp + // instruction immediate operand. + unsigned getSImm9AddiuspValue(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; + + // getBranchTarget7OpValue - Return binary encoding of the microMIPS branch + // target operand. If the machine operand requires relocation, + // record the relocation and return zero. + unsigned getBranchTarget7OpValueMM(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + // getBranchTargetOpValueMMPC10 - Return binary encoding of the microMIPS + // 10-bit branch target operand. If the machine operand requires relocation, + // record the relocation and return zero. + unsigned getBranchTargetOpValueMMPC10(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + // getBranchTargetOpValue - Return binary encoding of the microMIPS branch + // target operand. If the machine operand requires relocation, + // record the relocation and return zero. + unsigned getBranchTargetOpValueMM(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + // getBranchTarget21OpValue - Return binary encoding of the branch + // offset operand. If the machine operand requires relocation, + // record the relocation and return zero. + unsigned getBranchTarget21OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + // getBranchTarget26OpValue - Return binary encoding of the branch + // offset operand. If the machine operand requires relocation, + // record the relocation and return zero. + unsigned getBranchTarget26OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + // getBranchTarget26OpValueMM - Return binary encoding of the branch + // offset operand. If the machine operand requires relocation, + // record the relocation and return zero. + unsigned getBranchTarget26OpValueMM(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + // getJumpOffset16OpValue - Return binary encoding of the jump + // offset operand. If the machine operand requires relocation, + // record the relocation and return zero. + unsigned getJumpOffset16OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + // getMachineOpValue - Return binary encoding of operand. If the machin + // operand requires relocation, record the relocation and return zero. + unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getMSAMemEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getMemEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getMemEncodingMMImm4(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getMemEncodingMMImm4Lsl1(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getMemEncodingMMImm4Lsl2(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getMemEncodingMMSPImm5Lsl2(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getMemEncodingMMGPImm7Lsl2(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getMemEncodingMMImm9(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 getMemEncodingMMImm16(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getMemEncodingMMImm4sp(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; + + /// Subtract Offset then encode as a N-bit unsigned integer. + template <unsigned Bits, int Offset> + unsigned getUImmWithOffsetEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getSimm19Lsl2Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getSimm18Lsl3Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getUImm3Mod8Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getUImm4AndValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getRegisterPairOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getMovePRegPairOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getSimm23Lsl2Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getExprOpValue(const MCExpr *Expr, SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getRegisterListOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getRegisterListOpValue16(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; +}; // class MipsMCCodeEmitter +} // namespace llvm. + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp new file mode 100644 index 0000000..c85fc48 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp @@ -0,0 +1,90 @@ +//===-- MipsMCExpr.cpp - Mips specific MC expression classes --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsMCExpr.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectStreamer.h" + +using namespace llvm; + +#define DEBUG_TYPE "mipsmcexpr" + +bool MipsMCExpr::isSupportedBinaryExpr(MCSymbolRefExpr::VariantKind VK, + const MCBinaryExpr *BE) { + switch (VK) { + case MCSymbolRefExpr::VK_Mips_ABS_LO: + case MCSymbolRefExpr::VK_Mips_ABS_HI: + case MCSymbolRefExpr::VK_Mips_HIGHER: + case MCSymbolRefExpr::VK_Mips_HIGHEST: + break; + default: + return false; + } + + // We support expressions of the form "(sym1 binop1 sym2) binop2 const", + // where "binop2 const" is optional. + if (isa<MCBinaryExpr>(BE->getLHS())) { + if (!isa<MCConstantExpr>(BE->getRHS())) + return false; + BE = cast<MCBinaryExpr>(BE->getLHS()); + } + return (isa<MCSymbolRefExpr>(BE->getLHS()) + && isa<MCSymbolRefExpr>(BE->getRHS())); +} + +const MipsMCExpr* +MipsMCExpr::create(MCSymbolRefExpr::VariantKind VK, const MCExpr *Expr, + MCContext &Ctx) { + VariantKind Kind; + switch (VK) { + case MCSymbolRefExpr::VK_Mips_ABS_LO: + Kind = VK_Mips_LO; + break; + case MCSymbolRefExpr::VK_Mips_ABS_HI: + Kind = VK_Mips_HI; + break; + case MCSymbolRefExpr::VK_Mips_HIGHER: + Kind = VK_Mips_HIGHER; + break; + case MCSymbolRefExpr::VK_Mips_HIGHEST: + Kind = VK_Mips_HIGHEST; + break; + default: + llvm_unreachable("Invalid kind!"); + } + + return new (Ctx) MipsMCExpr(Kind, Expr); +} + +void MipsMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) 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, MAI); + OS << ')'; +} + +bool +MipsMCExpr::evaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout, + const MCFixup *Fixup) const { + return getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup); +} + +void MipsMCExpr::visitUsedExpr(MCStreamer &Streamer) const { + Streamer.visitUsedExpr(*getSubExpr()); +} diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h new file mode 100644 index 0000000..e889972 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h @@ -0,0 +1,67 @@ +//===-- 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 LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSMCEXPR_H +#define LLVM_LIB_TARGET_MIPS_MCTARGETDESC_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 MCAsmInfo *MAI) const override; + bool evaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout, + const MCFixup *Fixup) const override; + void visitUsedExpr(MCStreamer &Streamer) const override; + MCFragment *findAssociatedFragment() const override { + return getSubExpr()->findAssociatedFragment(); + } + + // There are no TLS MipsMCExprs at the moment. + void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {} + + static bool classof(const MCExpr *E) { + return E->getKind() == MCExpr::Target; + } +}; +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h new file mode 100644 index 0000000..687b800 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h @@ -0,0 +1,30 @@ +//===-- 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 LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSMCNACL_H +#define LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSMCNACL_H + +#include "llvm/MC/MCELFStreamer.h" + +namespace llvm { + +// Log2 of the NaCl MIPS sandbox's instruction bundle size. +static const unsigned MIPS_NACL_BUNDLE_ALIGN = 4u; + +bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx, + bool *IsStore = nullptr); +bool baseRegNeedsLoadStoreMask(unsigned Reg); + +// This function creates an MCELFStreamer for Mips NaCl. +MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, + raw_pwrite_stream &OS, + MCCodeEmitter *Emitter, bool RelaxAll); +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp new file mode 100644 index 0000000..949ee14 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp @@ -0,0 +1,183 @@ +//===-- MipsMCTargetDesc.cpp - Mips Target Descriptions -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides Mips specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#include "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/MCELFStreamer.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MachineLocation.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +#define GET_INSTRINFO_MC_DESC +#include "MipsGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_MC_DESC +#include "MipsGenSubtargetInfo.inc" + +#define GET_REGINFO_MC_DESC +#include "MipsGenRegisterInfo.inc" + +/// Select the Mips CPU for the given triple and cpu name. +/// FIXME: Merge with the copy in MipsSubtarget.cpp +StringRef MIPS_MC::selectMipsCPU(const Triple &TT, StringRef CPU) { + if (CPU.empty() || CPU == "generic") { + if (TT.getArch() == Triple::mips || TT.getArch() == Triple::mipsel) + CPU = "mips32"; + else + CPU = "mips64"; + } + return CPU; +} + +static MCInstrInfo *createMipsMCInstrInfo() { + MCInstrInfo *X = new MCInstrInfo(); + InitMipsMCInstrInfo(X); + return X; +} + +static MCRegisterInfo *createMipsMCRegisterInfo(const Triple &TT) { + MCRegisterInfo *X = new MCRegisterInfo(); + InitMipsMCRegisterInfo(X, Mips::RA); + return X; +} + +static MCSubtargetInfo *createMipsMCSubtargetInfo(const Triple &TT, + StringRef CPU, StringRef FS) { + CPU = MIPS_MC::selectMipsCPU(TT, CPU); + return createMipsMCSubtargetInfoImpl(TT, CPU, FS); +} + +static MCAsmInfo *createMipsMCAsmInfo(const MCRegisterInfo &MRI, + const Triple &TT) { + MCAsmInfo *MAI = new MipsMCAsmInfo(TT); + + unsigned SP = MRI.getDwarfRegNum(Mips::SP, true); + MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(nullptr, SP, 0); + MAI->addInitialFrameState(Inst); + + return MAI; +} + +static MCCodeGenInfo *createMipsMCCodeGenInfo(const Triple &TT, Reloc::Model RM, + CodeModel::Model CM, + CodeGenOpt::Level OL) { + MCCodeGenInfo *X = new MCCodeGenInfo(); + if (CM == CodeModel::JITDefault) + RM = Reloc::Static; + else if (RM == Reloc::Default) + RM = Reloc::PIC_; + X->initMCCodeGenInfo(RM, CM, OL); + return X; +} + +static MCInstPrinter *createMipsMCInstPrinter(const Triple &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI) { + return new MipsInstPrinter(MAI, MII, MRI); +} + +static MCStreamer *createMCStreamer(const Triple &T, MCContext &Context, + MCAsmBackend &MAB, raw_pwrite_stream &OS, + MCCodeEmitter *Emitter, bool RelaxAll) { + MCStreamer *S; + if (!T.isOSNaCl()) + S = createMipsELFStreamer(Context, MAB, OS, Emitter, RelaxAll); + else + S = createMipsNaClELFStreamer(Context, MAB, OS, Emitter, RelaxAll); + return S; +} + +static MCTargetStreamer *createMipsAsmTargetStreamer(MCStreamer &S, + formatted_raw_ostream &OS, + MCInstPrinter *InstPrint, + bool isVerboseAsm) { + return new MipsTargetAsmStreamer(S, OS); +} + +static MCTargetStreamer *createMipsNullTargetStreamer(MCStreamer &S) { + return new MipsTargetStreamer(S); +} + +static MCTargetStreamer * +createMipsObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) { + return new MipsTargetELFStreamer(S, STI); +} + +extern "C" void LLVMInitializeMipsTargetMC() { + for (Target *T : {&TheMipsTarget, &TheMipselTarget, &TheMips64Target, + &TheMips64elTarget}) { + // Register the MC asm info. + RegisterMCAsmInfoFn X(*T, createMipsMCAsmInfo); + + // Register the MC codegen info. + TargetRegistry::RegisterMCCodeGenInfo(*T, createMipsMCCodeGenInfo); + + // Register the MC instruction info. + TargetRegistry::RegisterMCInstrInfo(*T, createMipsMCInstrInfo); + + // Register the MC register info. + TargetRegistry::RegisterMCRegInfo(*T, createMipsMCRegisterInfo); + + // Register the elf streamer. + TargetRegistry::RegisterELFStreamer(*T, createMCStreamer); + + // Register the asm target streamer. + TargetRegistry::RegisterAsmTargetStreamer(*T, createMipsAsmTargetStreamer); + + TargetRegistry::RegisterNullTargetStreamer(*T, + createMipsNullTargetStreamer); + + // Register the MC subtarget info. + TargetRegistry::RegisterMCSubtargetInfo(*T, createMipsMCSubtargetInfo); + + // Register the MCInstPrinter. + TargetRegistry::RegisterMCInstPrinter(*T, createMipsMCInstPrinter); + + TargetRegistry::RegisterObjectTargetStreamer( + *T, createMipsObjectTargetStreamer); + } + + // Register the MC Code Emitter + for (Target *T : {&TheMipsTarget, &TheMips64Target}) + TargetRegistry::RegisterMCCodeEmitter(*T, createMipsMCCodeEmitterEB); + + for (Target *T : {&TheMipselTarget, &TheMips64elTarget}) + TargetRegistry::RegisterMCCodeEmitter(*T, createMipsMCCodeEmitterEL); + + // Register the asm backend. + TargetRegistry::RegisterMCAsmBackend(TheMipsTarget, + createMipsAsmBackendEB32); + TargetRegistry::RegisterMCAsmBackend(TheMipselTarget, + createMipsAsmBackendEL32); + TargetRegistry::RegisterMCAsmBackend(TheMips64Target, + createMipsAsmBackendEB64); + TargetRegistry::RegisterMCAsmBackend(TheMips64elTarget, + createMipsAsmBackendEL64); + +} diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h new file mode 100644 index 0000000..4069d7d --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h @@ -0,0 +1,79 @@ +//===-- MipsMCTargetDesc.h - Mips Target Descriptions -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides Mips specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSMCTARGETDESC_H +#define LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSMCTARGETDESC_H + +#include "llvm/Support/DataTypes.h" + +namespace llvm { +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCInstrInfo; +class MCObjectWriter; +class MCRegisterInfo; +class MCSubtargetInfo; +class StringRef; +class Target; +class Triple; +class raw_ostream; +class raw_pwrite_stream; + +extern Target TheMipsTarget; +extern Target TheMipselTarget; +extern Target TheMips64Target; +extern Target TheMips64elTarget; + +MCCodeEmitter *createMipsMCCodeEmitterEB(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + MCContext &Ctx); +MCCodeEmitter *createMipsMCCodeEmitterEL(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + MCContext &Ctx); + +MCAsmBackend *createMipsAsmBackendEB32(const Target &T, + const MCRegisterInfo &MRI, + const Triple &TT, StringRef CPU); +MCAsmBackend *createMipsAsmBackendEL32(const Target &T, + const MCRegisterInfo &MRI, + const Triple &TT, StringRef CPU); +MCAsmBackend *createMipsAsmBackendEB64(const Target &T, + const MCRegisterInfo &MRI, + const Triple &TT, StringRef CPU); +MCAsmBackend *createMipsAsmBackendEL64(const Target &T, + const MCRegisterInfo &MRI, + const Triple &TT, StringRef CPU); + +MCObjectWriter *createMipsELFObjectWriter(raw_pwrite_stream &OS, uint8_t OSABI, + bool IsLittleEndian, bool Is64Bit); + +namespace MIPS_MC { +StringRef selectMipsCPU(const Triple &TT, StringRef CPU); +} + +} // End llvm namespace + +// Defines symbolic names for Mips registers. This defines a mapping from +// register name to register number. +#define GET_REGINFO_ENUM +#include "MipsGenRegisterInfo.inc" + +// Defines symbolic names for the Mips instructions. +#define GET_INSTRINFO_ENUM +#include "MipsGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_ENUM +#include "MipsGenSubtargetInfo.inc" + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp new file mode 100644 index 0000000..aef9bd3 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp @@ -0,0 +1,268 @@ +//===-- MipsNaClELFStreamer.cpp - ELF Object Output for Mips NaCl ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements MCELFStreamer for Mips NaCl. It emits .o object files +// as required by NaCl's SFI sandbox. It inserts address-masking instructions +// before dangerous control-flow and memory access instructions. It inserts +// address-masking instructions after instructions that change the stack +// pointer. It ensures that the mask and the dangerous instruction are always +// emitted in the same bundle. It aligns call + branch delay to the bundle end, +// so that return address is always aligned to the start of next bundle. +// +//===----------------------------------------------------------------------===// + +#include "Mips.h" +#include "MipsELFStreamer.h" +#include "MipsMCNaCl.h" +#include "llvm/MC/MCELFStreamer.h" + +using namespace llvm; + +#define DEBUG_TYPE "mips-mc-nacl" + +namespace { + +const unsigned IndirectBranchMaskReg = Mips::T6; +const unsigned LoadStoreStackMaskReg = Mips::T7; + +/// Extend the generic MCELFStreamer class so that it can mask dangerous +/// instructions. + +class MipsNaClELFStreamer : public MipsELFStreamer { +public: + MipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, + raw_pwrite_stream &OS, MCCodeEmitter *Emitter) + : MipsELFStreamer(Context, TAB, OS, Emitter), PendingCall(false) {} + + ~MipsNaClELFStreamer() override {} + +private: + // Whether we started the sandboxing sequence for calls. Calls are bundled + // with branch delays and aligned to the bundle end. + bool PendingCall; + + bool isIndirectJump(const MCInst &MI) { + if (MI.getOpcode() == Mips::JALR) { + // MIPS32r6/MIPS64r6 doesn't have a JR instruction and uses JALR instead. + // JALR is an indirect branch if the link register is $0. + assert(MI.getOperand(0).isReg()); + return MI.getOperand(0).getReg() == Mips::ZERO; + } + return MI.getOpcode() == Mips::JR; + } + + bool isStackPointerFirstOperand(const MCInst &MI) { + return (MI.getNumOperands() > 0 && MI.getOperand(0).isReg() + && MI.getOperand(0).getReg() == Mips::SP); + } + + bool isCall(const MCInst &MI, bool *IsIndirectCall) { + unsigned Opcode = MI.getOpcode(); + + *IsIndirectCall = false; + + switch (Opcode) { + default: + return false; + + case Mips::JAL: + case Mips::BAL: + case Mips::BAL_BR: + case Mips::BLTZAL: + case Mips::BGEZAL: + return true; + + case Mips::JALR: + // JALR is only a call if the link register is not $0. Otherwise it's an + // indirect branch. + assert(MI.getOperand(0).isReg()); + if (MI.getOperand(0).getReg() == Mips::ZERO) + return false; + + *IsIndirectCall = true; + return true; + } + } + + void emitMask(unsigned AddrReg, unsigned MaskReg, + const MCSubtargetInfo &STI) { + MCInst MaskInst; + MaskInst.setOpcode(Mips::AND); + MaskInst.addOperand(MCOperand::createReg(AddrReg)); + MaskInst.addOperand(MCOperand::createReg(AddrReg)); + MaskInst.addOperand(MCOperand::createReg(MaskReg)); + MipsELFStreamer::EmitInstruction(MaskInst, STI); + } + + // Sandbox indirect branch or return instruction by inserting mask operation + // before it. + void sandboxIndirectJump(const MCInst &MI, const MCSubtargetInfo &STI) { + unsigned AddrReg = MI.getOperand(0).getReg(); + + EmitBundleLock(false); + emitMask(AddrReg, IndirectBranchMaskReg, STI); + MipsELFStreamer::EmitInstruction(MI, STI); + EmitBundleUnlock(); + } + + // Sandbox memory access or SP change. Insert mask operation before and/or + // after the instruction. + void sandboxLoadStoreStackChange(const MCInst &MI, unsigned AddrIdx, + const MCSubtargetInfo &STI, bool MaskBefore, + bool MaskAfter) { + EmitBundleLock(false); + if (MaskBefore) { + // Sandbox memory access. + unsigned BaseReg = MI.getOperand(AddrIdx).getReg(); + emitMask(BaseReg, LoadStoreStackMaskReg, STI); + } + MipsELFStreamer::EmitInstruction(MI, STI); + if (MaskAfter) { + // Sandbox SP change. + unsigned SPReg = MI.getOperand(0).getReg(); + assert((Mips::SP == SPReg) && "Unexpected stack-pointer register."); + emitMask(SPReg, LoadStoreStackMaskReg, STI); + } + EmitBundleUnlock(); + } + +public: + /// This function is the one used to emit instruction data into the ELF + /// streamer. We override it to mask dangerous instructions. + void EmitInstruction(const MCInst &Inst, + const MCSubtargetInfo &STI) override { + // Sandbox indirect jumps. + if (isIndirectJump(Inst)) { + if (PendingCall) + report_fatal_error("Dangerous instruction in branch delay slot!"); + sandboxIndirectJump(Inst, STI); + return; + } + + // Sandbox loads, stores and SP changes. + unsigned AddrIdx; + bool IsStore; + bool IsMemAccess = isBasePlusOffsetMemoryAccess(Inst.getOpcode(), &AddrIdx, + &IsStore); + bool IsSPFirstOperand = isStackPointerFirstOperand(Inst); + if (IsMemAccess || IsSPFirstOperand) { + bool MaskBefore = (IsMemAccess + && baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx) + .getReg())); + bool MaskAfter = IsSPFirstOperand && !IsStore; + if (MaskBefore || MaskAfter) { + if (PendingCall) + report_fatal_error("Dangerous instruction in branch delay slot!"); + sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter); + return; + } + // fallthrough + } + + // Sandbox calls by aligning call and branch delay to the bundle end. + // For indirect calls, emit the mask before the call. + bool IsIndirectCall; + if (isCall(Inst, &IsIndirectCall)) { + if (PendingCall) + report_fatal_error("Dangerous instruction in branch delay slot!"); + + // Start the sandboxing sequence by emitting call. + EmitBundleLock(true); + if (IsIndirectCall) { + unsigned TargetReg = Inst.getOperand(1).getReg(); + emitMask(TargetReg, IndirectBranchMaskReg, STI); + } + MipsELFStreamer::EmitInstruction(Inst, STI); + PendingCall = true; + return; + } + if (PendingCall) { + // Finish the sandboxing sequence by emitting branch delay. + MipsELFStreamer::EmitInstruction(Inst, STI); + EmitBundleUnlock(); + PendingCall = false; + return; + } + + // None of the sandboxing applies, just emit the instruction. + MipsELFStreamer::EmitInstruction(Inst, STI); + } +}; + +} // end anonymous namespace + +namespace llvm { + +bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx, + bool *IsStore) { + if (IsStore) + *IsStore = false; + + switch (Opcode) { + default: + return false; + + // Load instructions with base address register in position 1. + case Mips::LB: + case Mips::LBu: + case Mips::LH: + case Mips::LHu: + case Mips::LW: + case Mips::LWC1: + case Mips::LDC1: + case Mips::LL: + case Mips::LL_R6: + case Mips::LWL: + case Mips::LWR: + *AddrIdx = 1; + return true; + + // Store instructions with base address register in position 1. + case Mips::SB: + case Mips::SH: + case Mips::SW: + case Mips::SWC1: + case Mips::SDC1: + case Mips::SWL: + case Mips::SWR: + *AddrIdx = 1; + if (IsStore) + *IsStore = true; + return true; + + // Store instructions with base address register in position 2. + case Mips::SC: + case Mips::SC_R6: + *AddrIdx = 2; + if (IsStore) + *IsStore = true; + return true; + } +} + +bool baseRegNeedsLoadStoreMask(unsigned Reg) { + // The contents of SP and thread pointer register do not require masking. + return Reg != Mips::SP && Reg != Mips::T8; +} + +MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, + raw_pwrite_stream &OS, + MCCodeEmitter *Emitter, + bool RelaxAll) { + MipsNaClELFStreamer *S = new MipsNaClELFStreamer(Context, TAB, OS, Emitter); + if (RelaxAll) + S->getAssembler().setRelaxAll(true); + + // Set bundle-alignment as required by the NaCl ABI for the target. + S->EmitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN); + + return S; +} + +} diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsOptionRecord.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsOptionRecord.cpp new file mode 100644 index 0000000..24b6028 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsOptionRecord.cpp @@ -0,0 +1,95 @@ +//===-- MipsOptionRecord.cpp - Abstraction for storing information --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsOptionRecord.h" +#include "MipsELFStreamer.h" +#include "MipsTargetStreamer.h" +#include "llvm/MC/MCSectionELF.h" + +using namespace llvm; + +void MipsRegInfoRecord::EmitMipsOptionRecord() { + MCAssembler &MCA = Streamer->getAssembler(); + MipsTargetStreamer *MTS = + static_cast<MipsTargetStreamer *>(Streamer->getTargetStreamer()); + + Streamer->PushSection(); + + // We need to distinguish between N64 and the rest because at the moment + // we don't emit .Mips.options for other ELFs other than N64. + // Since .reginfo has the same information as .Mips.options (ODK_REGINFO), + // we can use the same abstraction (MipsRegInfoRecord class) to handle both. + if (MTS->getABI().IsN64()) { + // The EntrySize value of 1 seems strange since the records are neither + // 1-byte long nor fixed length but it matches the value GAS emits. + MCSectionELF *Sec = + Context.getELFSection(".MIPS.options", ELF::SHT_MIPS_OPTIONS, + ELF::SHF_ALLOC | ELF::SHF_MIPS_NOSTRIP, 1, ""); + MCA.registerSection(*Sec); + Sec->setAlignment(8); + Streamer->SwitchSection(Sec); + + Streamer->EmitIntValue(ELF::ODK_REGINFO, 1); // kind + Streamer->EmitIntValue(40, 1); // size + Streamer->EmitIntValue(0, 2); // section + Streamer->EmitIntValue(0, 4); // info + Streamer->EmitIntValue(ri_gprmask, 4); + Streamer->EmitIntValue(0, 4); // pad + Streamer->EmitIntValue(ri_cprmask[0], 4); + Streamer->EmitIntValue(ri_cprmask[1], 4); + Streamer->EmitIntValue(ri_cprmask[2], 4); + Streamer->EmitIntValue(ri_cprmask[3], 4); + Streamer->EmitIntValue(ri_gp_value, 8); + } else { + MCSectionELF *Sec = Context.getELFSection(".reginfo", ELF::SHT_MIPS_REGINFO, + ELF::SHF_ALLOC, 24, ""); + MCA.registerSection(*Sec); + Sec->setAlignment(MTS->getABI().IsN32() ? 8 : 4); + Streamer->SwitchSection(Sec); + + Streamer->EmitIntValue(ri_gprmask, 4); + Streamer->EmitIntValue(ri_cprmask[0], 4); + Streamer->EmitIntValue(ri_cprmask[1], 4); + Streamer->EmitIntValue(ri_cprmask[2], 4); + Streamer->EmitIntValue(ri_cprmask[3], 4); + assert((ri_gp_value & 0xffffffff) == ri_gp_value); + Streamer->EmitIntValue(ri_gp_value, 4); + } + + Streamer->PopSection(); +} + +void MipsRegInfoRecord::SetPhysRegUsed(unsigned Reg, + const MCRegisterInfo *MCRegInfo) { + unsigned Value = 0; + + for (MCSubRegIterator SubRegIt(Reg, MCRegInfo, true); SubRegIt.isValid(); + ++SubRegIt) { + unsigned CurrentSubReg = *SubRegIt; + + unsigned EncVal = MCRegInfo->getEncodingValue(CurrentSubReg); + Value |= 1 << EncVal; + + if (GPR32RegClass->contains(CurrentSubReg) || + GPR64RegClass->contains(CurrentSubReg)) + ri_gprmask |= Value; + else if (COP0RegClass->contains(CurrentSubReg)) + ri_cprmask[0] |= Value; + // MIPS COP1 is the FPU. + else if (FGR32RegClass->contains(CurrentSubReg) || + FGR64RegClass->contains(CurrentSubReg) || + AFGR64RegClass->contains(CurrentSubReg) || + MSA128BRegClass->contains(CurrentSubReg)) + ri_cprmask[1] |= Value; + else if (COP2RegClass->contains(CurrentSubReg)) + ri_cprmask[2] |= Value; + else if (COP3RegClass->contains(CurrentSubReg)) + ri_cprmask[3] |= Value; + } +} diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp new file mode 100644 index 0000000..e5fa755 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -0,0 +1,900 @@ +//===-- MipsTargetStreamer.cpp - Mips Target Streamer Methods -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides Mips specific target streamer methods. +// +//===----------------------------------------------------------------------===// + +#include "InstPrinter/MipsInstPrinter.h" +#include "MipsELFStreamer.h" +#include "MipsMCTargetDesc.h" +#include "MipsTargetObjectFile.h" +#include "MipsTargetStreamer.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbolELF.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" + +using namespace llvm; + +MipsTargetStreamer::MipsTargetStreamer(MCStreamer &S) + : MCTargetStreamer(S), ModuleDirectiveAllowed(true) { + GPRInfoSet = FPRInfoSet = FrameInfoSet = false; +} +void MipsTargetStreamer::emitDirectiveSetMicroMips() {} +void MipsTargetStreamer::emitDirectiveSetNoMicroMips() {} +void MipsTargetStreamer::emitDirectiveSetMips16() {} +void MipsTargetStreamer::emitDirectiveSetNoMips16() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetReorder() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetNoReorder() {} +void MipsTargetStreamer::emitDirectiveSetMacro() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetNoMacro() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetMsa() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetNoMsa() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetAt() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetAtWithArg(unsigned RegNo) { + forbidModuleDirective(); +} +void MipsTargetStreamer::emitDirectiveSetNoAt() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveEnd(StringRef Name) {} +void MipsTargetStreamer::emitDirectiveEnt(const MCSymbol &Symbol) {} +void MipsTargetStreamer::emitDirectiveAbiCalls() {} +void MipsTargetStreamer::emitDirectiveNaN2008() {} +void MipsTargetStreamer::emitDirectiveNaNLegacy() {} +void MipsTargetStreamer::emitDirectiveOptionPic0() {} +void MipsTargetStreamer::emitDirectiveOptionPic2() {} +void MipsTargetStreamer::emitDirectiveInsn() { forbidModuleDirective(); } +void MipsTargetStreamer::emitFrame(unsigned StackReg, unsigned StackSize, + unsigned ReturnReg) {} +void MipsTargetStreamer::emitMask(unsigned CPUBitmask, int CPUTopSavedRegOff) {} +void MipsTargetStreamer::emitFMask(unsigned FPUBitmask, int FPUTopSavedRegOff) { +} +void MipsTargetStreamer::emitDirectiveSetArch(StringRef Arch) { + forbidModuleDirective(); +} +void MipsTargetStreamer::emitDirectiveSetMips0() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetMips1() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetMips2() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetMips3() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetMips4() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetMips5() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetMips32() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetMips32R2() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetMips32R3() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetMips32R5() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetMips32R6() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetMips64() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetMips64R2() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetMips64R3() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetMips64R5() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetMips64R6() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetPop() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetPush() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetSoftFloat() { + forbidModuleDirective(); +} +void MipsTargetStreamer::emitDirectiveSetHardFloat() { + forbidModuleDirective(); +} +void MipsTargetStreamer::emitDirectiveSetDsp() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetNoDsp() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveCpLoad(unsigned RegNo) {} +void MipsTargetStreamer::emitDirectiveCpRestore( + SmallVector<MCInst, 3> &StoreInsts, int Offset) { + forbidModuleDirective(); +} +void MipsTargetStreamer::emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, + const MCSymbol &Sym, bool IsReg) { +} +void MipsTargetStreamer::emitDirectiveCpreturn(unsigned SaveLocation, + bool SaveLocationIsRegister) {} + +void MipsTargetStreamer::emitDirectiveModuleFP() {} + +void MipsTargetStreamer::emitDirectiveModuleOddSPReg() { + if (!ABIFlagsSection.OddSPReg && !ABIFlagsSection.Is32BitABI) + report_fatal_error("+nooddspreg is only valid for O32"); +} +void MipsTargetStreamer::emitDirectiveModuleSoftFloat() {} +void MipsTargetStreamer::emitDirectiveModuleHardFloat() {} +void MipsTargetStreamer::emitDirectiveSetFp( + MipsABIFlagsSection::FpABIKind Value) { + forbidModuleDirective(); +} +void MipsTargetStreamer::emitDirectiveSetOddSPReg() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetNoOddSPReg() { + forbidModuleDirective(); +} + +MipsTargetAsmStreamer::MipsTargetAsmStreamer(MCStreamer &S, + formatted_raw_ostream &OS) + : MipsTargetStreamer(S), OS(OS) {} + +void MipsTargetAsmStreamer::emitDirectiveSetMicroMips() { + OS << "\t.set\tmicromips\n"; + forbidModuleDirective(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoMicroMips() { + OS << "\t.set\tnomicromips\n"; + forbidModuleDirective(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips16() { + OS << "\t.set\tmips16\n"; + forbidModuleDirective(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoMips16() { + OS << "\t.set\tnomips16\n"; + MipsTargetStreamer::emitDirectiveSetNoMips16(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetReorder() { + OS << "\t.set\treorder\n"; + MipsTargetStreamer::emitDirectiveSetReorder(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoReorder() { + OS << "\t.set\tnoreorder\n"; + forbidModuleDirective(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMacro() { + OS << "\t.set\tmacro\n"; + MipsTargetStreamer::emitDirectiveSetMacro(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoMacro() { + OS << "\t.set\tnomacro\n"; + MipsTargetStreamer::emitDirectiveSetNoMacro(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMsa() { + OS << "\t.set\tmsa\n"; + MipsTargetStreamer::emitDirectiveSetMsa(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoMsa() { + OS << "\t.set\tnomsa\n"; + MipsTargetStreamer::emitDirectiveSetNoMsa(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetAt() { + OS << "\t.set\tat\n"; + MipsTargetStreamer::emitDirectiveSetAt(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetAtWithArg(unsigned RegNo) { + OS << "\t.set\tat=$" << Twine(RegNo) << "\n"; + MipsTargetStreamer::emitDirectiveSetAtWithArg(RegNo); +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoAt() { + OS << "\t.set\tnoat\n"; + MipsTargetStreamer::emitDirectiveSetNoAt(); +} + +void MipsTargetAsmStreamer::emitDirectiveEnd(StringRef Name) { + OS << "\t.end\t" << Name << '\n'; +} + +void MipsTargetAsmStreamer::emitDirectiveEnt(const MCSymbol &Symbol) { + OS << "\t.ent\t" << Symbol.getName() << '\n'; +} + +void MipsTargetAsmStreamer::emitDirectiveAbiCalls() { OS << "\t.abicalls\n"; } + +void MipsTargetAsmStreamer::emitDirectiveNaN2008() { OS << "\t.nan\t2008\n"; } + +void MipsTargetAsmStreamer::emitDirectiveNaNLegacy() { + OS << "\t.nan\tlegacy\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveOptionPic0() { + OS << "\t.option\tpic0\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveOptionPic2() { + OS << "\t.option\tpic2\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveInsn() { + MipsTargetStreamer::emitDirectiveInsn(); + OS << "\t.insn\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::emitDirectiveSetArch(StringRef Arch) { + OS << "\t.set arch=" << Arch << "\n"; + MipsTargetStreamer::emitDirectiveSetArch(Arch); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips0() { + OS << "\t.set\tmips0\n"; + MipsTargetStreamer::emitDirectiveSetMips0(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips1() { + OS << "\t.set\tmips1\n"; + MipsTargetStreamer::emitDirectiveSetMips1(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips2() { + OS << "\t.set\tmips2\n"; + MipsTargetStreamer::emitDirectiveSetMips2(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips3() { + OS << "\t.set\tmips3\n"; + MipsTargetStreamer::emitDirectiveSetMips3(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips4() { + OS << "\t.set\tmips4\n"; + MipsTargetStreamer::emitDirectiveSetMips4(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips5() { + OS << "\t.set\tmips5\n"; + MipsTargetStreamer::emitDirectiveSetMips5(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips32() { + OS << "\t.set\tmips32\n"; + MipsTargetStreamer::emitDirectiveSetMips32(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips32R2() { + OS << "\t.set\tmips32r2\n"; + MipsTargetStreamer::emitDirectiveSetMips32R2(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips32R3() { + OS << "\t.set\tmips32r3\n"; + MipsTargetStreamer::emitDirectiveSetMips32R3(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips32R5() { + OS << "\t.set\tmips32r5\n"; + MipsTargetStreamer::emitDirectiveSetMips32R5(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips32R6() { + OS << "\t.set\tmips32r6\n"; + MipsTargetStreamer::emitDirectiveSetMips32R6(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips64() { + OS << "\t.set\tmips64\n"; + MipsTargetStreamer::emitDirectiveSetMips64(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips64R2() { + OS << "\t.set\tmips64r2\n"; + MipsTargetStreamer::emitDirectiveSetMips64R2(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips64R3() { + OS << "\t.set\tmips64r3\n"; + MipsTargetStreamer::emitDirectiveSetMips64R3(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips64R5() { + OS << "\t.set\tmips64r5\n"; + MipsTargetStreamer::emitDirectiveSetMips64R5(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips64R6() { + OS << "\t.set\tmips64r6\n"; + MipsTargetStreamer::emitDirectiveSetMips64R6(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetDsp() { + OS << "\t.set\tdsp\n"; + MipsTargetStreamer::emitDirectiveSetDsp(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoDsp() { + OS << "\t.set\tnodsp\n"; + MipsTargetStreamer::emitDirectiveSetNoDsp(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetPop() { + OS << "\t.set\tpop\n"; + MipsTargetStreamer::emitDirectiveSetPop(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetPush() { + OS << "\t.set\tpush\n"; + MipsTargetStreamer::emitDirectiveSetPush(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetSoftFloat() { + OS << "\t.set\tsoftfloat\n"; + MipsTargetStreamer::emitDirectiveSetSoftFloat(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetHardFloat() { + OS << "\t.set\thardfloat\n"; + MipsTargetStreamer::emitDirectiveSetHardFloat(); +} + +// 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'; +} + +void MipsTargetAsmStreamer::emitDirectiveCpLoad(unsigned RegNo) { + OS << "\t.cpload\t$" + << StringRef(MipsInstPrinter::getRegisterName(RegNo)).lower() << "\n"; + forbidModuleDirective(); +} + +void MipsTargetAsmStreamer::emitDirectiveCpRestore( + SmallVector<MCInst, 3> &StoreInsts, int Offset) { + MipsTargetStreamer::emitDirectiveCpRestore(StoreInsts, Offset); + OS << "\t.cprestore\t" << Offset << "\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveCpsetup(unsigned RegNo, + int RegOrOffset, + const MCSymbol &Sym, + bool IsReg) { + OS << "\t.cpsetup\t$" + << StringRef(MipsInstPrinter::getRegisterName(RegNo)).lower() << ", "; + + if (IsReg) + OS << "$" + << StringRef(MipsInstPrinter::getRegisterName(RegOrOffset)).lower(); + else + OS << RegOrOffset; + + OS << ", "; + + OS << Sym.getName(); + forbidModuleDirective(); +} + +void MipsTargetAsmStreamer::emitDirectiveCpreturn(unsigned SaveLocation, + bool SaveLocationIsRegister) { + OS << "\t.cpreturn"; + forbidModuleDirective(); +} + +void MipsTargetAsmStreamer::emitDirectiveModuleFP() { + OS << "\t.module\tfp="; + OS << ABIFlagsSection.getFpABIString(ABIFlagsSection.getFpABI()) << "\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveSetFp( + MipsABIFlagsSection::FpABIKind Value) { + MipsTargetStreamer::emitDirectiveSetFp(Value); + + OS << "\t.set\tfp="; + OS << ABIFlagsSection.getFpABIString(Value) << "\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveModuleOddSPReg() { + MipsTargetStreamer::emitDirectiveModuleOddSPReg(); + + OS << "\t.module\t" << (ABIFlagsSection.OddSPReg ? "" : "no") << "oddspreg\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveSetOddSPReg() { + MipsTargetStreamer::emitDirectiveSetOddSPReg(); + OS << "\t.set\toddspreg\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoOddSPReg() { + MipsTargetStreamer::emitDirectiveSetNoOddSPReg(); + OS << "\t.set\tnooddspreg\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveModuleSoftFloat() { + OS << "\t.module\tsoftfloat\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveModuleHardFloat() { + OS << "\t.module\thardfloat\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(); + Pic = MCA.getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_; + + const FeatureBitset &Features = STI.getFeatureBits(); + + // Set the header flags that we can in the constructor. + // FIXME: This is a fairly terrible hack. We set the rest + // of these in the destructor. The problem here is two-fold: + // + // a: Some of the eflags can be set/reset by directives. + // b: There aren't any usage paths that initialize the ABI + // pointer until after we initialize either an assembler + // or the target machine. + // We can fix this by making the target streamer construct + // the ABI, but this is fraught with wide ranging dependency + // issues as well. + unsigned EFlags = MCA.getELFHeaderEFlags(); + + // Architecture + if (Features[Mips::FeatureMips64r6]) + EFlags |= ELF::EF_MIPS_ARCH_64R6; + else if (Features[Mips::FeatureMips64r2] || + Features[Mips::FeatureMips64r3] || + Features[Mips::FeatureMips64r5]) + EFlags |= ELF::EF_MIPS_ARCH_64R2; + else if (Features[Mips::FeatureMips64]) + EFlags |= ELF::EF_MIPS_ARCH_64; + else if (Features[Mips::FeatureMips5]) + EFlags |= ELF::EF_MIPS_ARCH_5; + else if (Features[Mips::FeatureMips4]) + EFlags |= ELF::EF_MIPS_ARCH_4; + else if (Features[Mips::FeatureMips3]) + EFlags |= ELF::EF_MIPS_ARCH_3; + else if (Features[Mips::FeatureMips32r6]) + EFlags |= ELF::EF_MIPS_ARCH_32R6; + else if (Features[Mips::FeatureMips32r2] || + Features[Mips::FeatureMips32r3] || + Features[Mips::FeatureMips32r5]) + EFlags |= ELF::EF_MIPS_ARCH_32R2; + else if (Features[Mips::FeatureMips32]) + EFlags |= ELF::EF_MIPS_ARCH_32; + else if (Features[Mips::FeatureMips2]) + EFlags |= ELF::EF_MIPS_ARCH_2; + else + EFlags |= ELF::EF_MIPS_ARCH_1; + + // Other options. + if (Features[Mips::FeatureNaN2008]) + EFlags |= ELF::EF_MIPS_NAN2008; + + // -mabicalls and -mplt are not implemented but we should act as if they were + // given. + EFlags |= ELF::EF_MIPS_CPIC; + + MCA.setELFHeaderEFlags(EFlags); +} + +void MipsTargetELFStreamer::emitLabel(MCSymbol *S) { + auto *Symbol = cast<MCSymbolELF>(S); + if (!isMicroMipsEnabled()) + return; + getStreamer().getAssembler().registerSymbol(*Symbol); + uint8_t Type = Symbol->getType(); + if (Type != ELF::STT_FUNC) + return; + + Symbol->setOther(ELF::STO_MIPS_MICROMIPS); +} + +void MipsTargetELFStreamer::finish() { + MCAssembler &MCA = getStreamer().getAssembler(); + const MCObjectFileInfo &OFI = *MCA.getContext().getObjectFileInfo(); + + // .bss, .text and .data are always at least 16-byte aligned. + MCSection &TextSection = *OFI.getTextSection(); + MCA.registerSection(TextSection); + MCSection &DataSection = *OFI.getDataSection(); + MCA.registerSection(DataSection); + MCSection &BSSSection = *OFI.getBSSSection(); + MCA.registerSection(BSSSection); + + TextSection.setAlignment(std::max(16u, TextSection.getAlignment())); + DataSection.setAlignment(std::max(16u, DataSection.getAlignment())); + BSSSection.setAlignment(std::max(16u, BSSSection.getAlignment())); + + const FeatureBitset &Features = STI.getFeatureBits(); + + // Update e_header flags. See the FIXME and comment above in + // the constructor for a full rundown on this. + unsigned EFlags = MCA.getELFHeaderEFlags(); + + // ABI + // N64 does not require any ABI bits. + if (getABI().IsO32()) + EFlags |= ELF::EF_MIPS_ABI_O32; + else if (getABI().IsN32()) + EFlags |= ELF::EF_MIPS_ABI2; + + if (Features[Mips::FeatureGP64Bit]) { + if (getABI().IsO32()) + EFlags |= ELF::EF_MIPS_32BITMODE; /* Compatibility Mode */ + } else if (Features[Mips::FeatureMips64r2] || Features[Mips::FeatureMips64]) + EFlags |= ELF::EF_MIPS_32BITMODE; + + // If we've set the cpic eflag and we're n64, go ahead and set the pic + // one as well. + if (EFlags & ELF::EF_MIPS_CPIC && getABI().IsN64()) + EFlags |= ELF::EF_MIPS_PIC; + + MCA.setELFHeaderEFlags(EFlags); + + // Emit all the option records. + // At the moment we are only emitting .Mips.options (ODK_REGINFO) and + // .reginfo. + MipsELFStreamer &MEF = static_cast<MipsELFStreamer &>(Streamer); + MEF.EmitMipsOptionRecords(); + + emitMipsAbiFlags(); +} + +void MipsTargetELFStreamer::emitAssignment(MCSymbol *S, const MCExpr *Value) { + auto *Symbol = cast<MCSymbolELF>(S); + // If on rhs is micromips symbol then mark Symbol as microMips. + if (Value->getKind() != MCExpr::SymbolRef) + return; + const auto &RhsSym = cast<MCSymbolELF>( + static_cast<const MCSymbolRefExpr *>(Value)->getSymbol()); + + if (!(RhsSym.getOther() & ELF::STO_MIPS_MICROMIPS)) + return; + + Symbol->setOther(ELF::STO_MIPS_MICROMIPS); +} + +MCELFStreamer &MipsTargetELFStreamer::getStreamer() { + return static_cast<MCELFStreamer &>(Streamer); +} + +void MipsTargetELFStreamer::emitDirectiveSetMicroMips() { + MicroMipsEnabled = true; + + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags |= ELF::EF_MIPS_MICROMIPS; + MCA.setELFHeaderEFlags(Flags); + forbidModuleDirective(); +} + +void MipsTargetELFStreamer::emitDirectiveSetNoMicroMips() { + MicroMipsEnabled = false; + forbidModuleDirective(); +} + +void MipsTargetELFStreamer::emitDirectiveSetMips16() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags |= ELF::EF_MIPS_ARCH_ASE_M16; + MCA.setELFHeaderEFlags(Flags); + forbidModuleDirective(); +} + +void MipsTargetELFStreamer::emitDirectiveSetNoReorder() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags |= ELF::EF_MIPS_NOREORDER; + MCA.setELFHeaderEFlags(Flags); + forbidModuleDirective(); +} + +void MipsTargetELFStreamer::emitDirectiveEnd(StringRef Name) { + MCAssembler &MCA = getStreamer().getAssembler(); + MCContext &Context = MCA.getContext(); + MCStreamer &OS = getStreamer(); + + MCSectionELF *Sec = Context.getELFSection(".pdr", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHT_REL); + + MCSymbol *Sym = Context.getOrCreateSymbol(Name); + const MCSymbolRefExpr *ExprRef = + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Context); + + MCA.registerSection(*Sec); + Sec->setAlignment(4); + + OS.PushSection(); + + OS.SwitchSection(Sec); + + OS.EmitValueImpl(ExprRef, 4); + + OS.EmitIntValue(GPRInfoSet ? GPRBitMask : 0, 4); // reg_mask + OS.EmitIntValue(GPRInfoSet ? GPROffset : 0, 4); // reg_offset + + OS.EmitIntValue(FPRInfoSet ? FPRBitMask : 0, 4); // fpreg_mask + OS.EmitIntValue(FPRInfoSet ? FPROffset : 0, 4); // fpreg_offset + + OS.EmitIntValue(FrameInfoSet ? FrameOffset : 0, 4); // frame_offset + OS.EmitIntValue(FrameInfoSet ? FrameReg : 0, 4); // frame_reg + OS.EmitIntValue(FrameInfoSet ? ReturnReg : 0, 4); // return_reg + + // The .end directive marks the end of a procedure. Invalidate + // the information gathered up until this point. + GPRInfoSet = FPRInfoSet = FrameInfoSet = false; + + OS.PopSection(); + + // .end also implicitly sets the size. + MCSymbol *CurPCSym = Context.createTempSymbol(); + OS.EmitLabel(CurPCSym); + const MCExpr *Size = MCBinaryExpr::createSub( + MCSymbolRefExpr::create(CurPCSym, MCSymbolRefExpr::VK_None, Context), + ExprRef, Context); + int64_t AbsSize; + if (!Size->evaluateAsAbsolute(AbsSize, MCA)) + llvm_unreachable("Function size must be evaluatable as absolute"); + Size = MCConstantExpr::create(AbsSize, Context); + static_cast<MCSymbolELF *>(Sym)->setSize(Size); +} + +void MipsTargetELFStreamer::emitDirectiveEnt(const MCSymbol &Symbol) { + GPRInfoSet = FPRInfoSet = FrameInfoSet = false; + + // .ent also acts like an implicit '.type symbol, STT_FUNC' + static_cast<const MCSymbolELF &>(Symbol).setType(ELF::STT_FUNC); +} + +void MipsTargetELFStreamer::emitDirectiveAbiCalls() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags |= ELF::EF_MIPS_CPIC | ELF::EF_MIPS_PIC; + MCA.setELFHeaderEFlags(Flags); +} + +void MipsTargetELFStreamer::emitDirectiveNaN2008() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags |= ELF::EF_MIPS_NAN2008; + MCA.setELFHeaderEFlags(Flags); +} + +void MipsTargetELFStreamer::emitDirectiveNaNLegacy() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags &= ~ELF::EF_MIPS_NAN2008; + MCA.setELFHeaderEFlags(Flags); +} + +void MipsTargetELFStreamer::emitDirectiveOptionPic0() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + // This option overrides other PIC options like -KPIC. + Pic = false; + Flags &= ~ELF::EF_MIPS_PIC; + MCA.setELFHeaderEFlags(Flags); +} + +void MipsTargetELFStreamer::emitDirectiveOptionPic2() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Pic = true; + // NOTE: We are following the GAS behaviour here which means the directive + // 'pic2' also sets the CPIC bit in the ELF header. This is different from + // what is stated in the SYSV ABI which consider the bits EF_MIPS_PIC and + // EF_MIPS_CPIC to be mutually exclusive. + Flags |= ELF::EF_MIPS_PIC | ELF::EF_MIPS_CPIC; + MCA.setELFHeaderEFlags(Flags); +} + +void MipsTargetELFStreamer::emitDirectiveInsn() { + MipsTargetStreamer::emitDirectiveInsn(); + MipsELFStreamer &MEF = static_cast<MipsELFStreamer &>(Streamer); + MEF.createPendingLabelRelocs(); +} + +void MipsTargetELFStreamer::emitFrame(unsigned StackReg, unsigned StackSize, + unsigned ReturnReg_) { + MCContext &Context = getStreamer().getAssembler().getContext(); + const MCRegisterInfo *RegInfo = Context.getRegisterInfo(); + + FrameInfoSet = true; + FrameReg = RegInfo->getEncodingValue(StackReg); + FrameOffset = StackSize; + ReturnReg = RegInfo->getEncodingValue(ReturnReg_); +} + +void MipsTargetELFStreamer::emitMask(unsigned CPUBitmask, + int CPUTopSavedRegOff) { + GPRInfoSet = true; + GPRBitMask = CPUBitmask; + GPROffset = CPUTopSavedRegOff; +} + +void MipsTargetELFStreamer::emitFMask(unsigned FPUBitmask, + int FPUTopSavedRegOff) { + FPRInfoSet = true; + FPRBitMask = FPUBitmask; + FPROffset = FPUTopSavedRegOff; +} + +void MipsTargetELFStreamer::emitDirectiveCpLoad(unsigned RegNo) { + // .cpload $reg + // This directive expands to: + // lui $gp, %hi(_gp_disp) + // addui $gp, $gp, %lo(_gp_disp) + // addu $gp, $gp, $reg + // when support for position independent code is enabled. + if (!Pic || (getABI().IsN32() || getABI().IsN64())) + return; + + // There's a GNU extension controlled by -mno-shared that allows + // locally-binding symbols to be accessed using absolute addresses. + // This is currently not supported. When supported -mno-shared makes + // .cpload expand to: + // lui $gp, %hi(__gnu_local_gp) + // addiu $gp, $gp, %lo(__gnu_local_gp) + + StringRef SymName("_gp_disp"); + MCAssembler &MCA = getStreamer().getAssembler(); + MCSymbol *GP_Disp = MCA.getContext().getOrCreateSymbol(SymName); + MCA.registerSymbol(*GP_Disp); + + MCInst TmpInst; + TmpInst.setOpcode(Mips::LUi); + TmpInst.addOperand(MCOperand::createReg(Mips::GP)); + const MCSymbolRefExpr *HiSym = MCSymbolRefExpr::create( + "_gp_disp", MCSymbolRefExpr::VK_Mips_ABS_HI, MCA.getContext()); + TmpInst.addOperand(MCOperand::createExpr(HiSym)); + getStreamer().EmitInstruction(TmpInst, STI); + + TmpInst.clear(); + + TmpInst.setOpcode(Mips::ADDiu); + TmpInst.addOperand(MCOperand::createReg(Mips::GP)); + TmpInst.addOperand(MCOperand::createReg(Mips::GP)); + const MCSymbolRefExpr *LoSym = MCSymbolRefExpr::create( + "_gp_disp", MCSymbolRefExpr::VK_Mips_ABS_LO, MCA.getContext()); + TmpInst.addOperand(MCOperand::createExpr(LoSym)); + getStreamer().EmitInstruction(TmpInst, STI); + + TmpInst.clear(); + + TmpInst.setOpcode(Mips::ADDu); + TmpInst.addOperand(MCOperand::createReg(Mips::GP)); + TmpInst.addOperand(MCOperand::createReg(Mips::GP)); + TmpInst.addOperand(MCOperand::createReg(RegNo)); + getStreamer().EmitInstruction(TmpInst, STI); + + forbidModuleDirective(); +} + +void MipsTargetELFStreamer::emitDirectiveCpRestore( + SmallVector<MCInst, 3> &StoreInsts, int Offset) { + MipsTargetStreamer::emitDirectiveCpRestore(StoreInsts, Offset); + // .cprestore offset + // When PIC mode is enabled and the O32 ABI is used, this directive expands + // to: + // sw $gp, offset($sp) + // and adds a corresponding LW after every JAL. + + // Note that .cprestore is ignored if used with the N32 and N64 ABIs or if it + // is used in non-PIC mode. + if (!Pic || (getABI().IsN32() || getABI().IsN64())) + return; + + for (const MCInst &Inst : StoreInsts) + getStreamer().EmitInstruction(Inst, STI); +} + +void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo, + int RegOrOffset, + const MCSymbol &Sym, + bool IsReg) { + // Only N32 and N64 emit anything for .cpsetup iff PIC is set. + if (!Pic || !(getABI().IsN32() || getABI().IsN64())) + return; + + MCAssembler &MCA = getStreamer().getAssembler(); + MCInst Inst; + + // Either store the old $gp in a register or on the stack + if (IsReg) { + // move $save, $gpreg + Inst.setOpcode(Mips::OR64); + Inst.addOperand(MCOperand::createReg(RegOrOffset)); + Inst.addOperand(MCOperand::createReg(Mips::GP)); + Inst.addOperand(MCOperand::createReg(Mips::ZERO)); + } else { + // sd $gpreg, offset($sp) + Inst.setOpcode(Mips::SD); + Inst.addOperand(MCOperand::createReg(Mips::GP)); + Inst.addOperand(MCOperand::createReg(Mips::SP)); + Inst.addOperand(MCOperand::createImm(RegOrOffset)); + } + getStreamer().EmitInstruction(Inst, STI); + Inst.clear(); + + const MCSymbolRefExpr *HiExpr = MCSymbolRefExpr::create( + &Sym, MCSymbolRefExpr::VK_Mips_GPOFF_HI, MCA.getContext()); + const MCSymbolRefExpr *LoExpr = MCSymbolRefExpr::create( + &Sym, MCSymbolRefExpr::VK_Mips_GPOFF_LO, MCA.getContext()); + + // lui $gp, %hi(%neg(%gp_rel(funcSym))) + Inst.setOpcode(Mips::LUi); + Inst.addOperand(MCOperand::createReg(Mips::GP)); + Inst.addOperand(MCOperand::createExpr(HiExpr)); + getStreamer().EmitInstruction(Inst, STI); + Inst.clear(); + + // addiu $gp, $gp, %lo(%neg(%gp_rel(funcSym))) + Inst.setOpcode(Mips::ADDiu); + Inst.addOperand(MCOperand::createReg(Mips::GP)); + Inst.addOperand(MCOperand::createReg(Mips::GP)); + Inst.addOperand(MCOperand::createExpr(LoExpr)); + getStreamer().EmitInstruction(Inst, STI); + Inst.clear(); + + // daddu $gp, $gp, $funcreg + Inst.setOpcode(Mips::DADDu); + Inst.addOperand(MCOperand::createReg(Mips::GP)); + Inst.addOperand(MCOperand::createReg(Mips::GP)); + Inst.addOperand(MCOperand::createReg(RegNo)); + getStreamer().EmitInstruction(Inst, STI); + + forbidModuleDirective(); +} + +void MipsTargetELFStreamer::emitDirectiveCpreturn(unsigned SaveLocation, + bool SaveLocationIsRegister) { + // Only N32 and N64 emit anything for .cpreturn iff PIC is set. + if (!Pic || !(getABI().IsN32() || getABI().IsN64())) + return; + + MCInst Inst; + // Either restore the old $gp from a register or on the stack + if (SaveLocationIsRegister) { + Inst.setOpcode(Mips::OR); + Inst.addOperand(MCOperand::createReg(Mips::GP)); + Inst.addOperand(MCOperand::createReg(SaveLocation)); + Inst.addOperand(MCOperand::createReg(Mips::ZERO)); + } else { + Inst.setOpcode(Mips::LD); + Inst.addOperand(MCOperand::createReg(Mips::GP)); + Inst.addOperand(MCOperand::createReg(Mips::SP)); + Inst.addOperand(MCOperand::createImm(SaveLocation)); + } + getStreamer().EmitInstruction(Inst, STI); + + forbidModuleDirective(); +} + +void MipsTargetELFStreamer::emitMipsAbiFlags() { + MCAssembler &MCA = getStreamer().getAssembler(); + MCContext &Context = MCA.getContext(); + MCStreamer &OS = getStreamer(); + MCSectionELF *Sec = Context.getELFSection( + ".MIPS.abiflags", ELF::SHT_MIPS_ABIFLAGS, ELF::SHF_ALLOC, 24, ""); + MCA.registerSection(*Sec); + Sec->setAlignment(8); + OS.SwitchSection(Sec); + + OS << ABIFlagsSection; +} diff --git a/contrib/llvm/lib/Target/Mips/MSA.txt b/contrib/llvm/lib/Target/Mips/MSA.txt new file mode 100644 index 0000000..113375f --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MSA.txt @@ -0,0 +1,83 @@ +Code Generation Notes for MSA +============================= + +Intrinsics are lowered to SelectionDAG nodes where possible in order to enable +optimisation, reduce the size of the ISel matcher, and reduce repetition in +the implementation. In a small number of cases, this can cause different +(semantically equivalent) instructions to be used in place of the requested +instruction, even when no optimisation has taken place. + +Instructions +============ + +This section describes any quirks of instruction selection for MSA. For +example, two instructions might be equally valid for some given IR and one is +chosen in preference to the other. + +bclri.b: + It is not possible to emit bclri.b since andi.b covers exactly the + same cases. andi.b should use fractionally less power than bclri.b in + most hardware implementations so it is used in preference to bclri.b. + +vshf.w: + It is not possible to emit vshf.w when the shuffle description is + constant since shf.w covers exactly the same cases. shf.w is used + instead. It is also impossible for the shuffle description to be + unknown at compile-time due to the definition of shufflevector in + LLVM IR. + +vshf.[bhwd] + When the shuffle description describes a splat operation, splat.[bhwd] + instructions will be selected instead of vshf.[bhwd]. Unlike the ilv*, + and pck* instructions, this is matched from MipsISD::VSHF instead of + a special-case MipsISD node. + +ilvl.d, pckev.d: + It is not possible to emit ilvl.d, or pckev.d since ilvev.d covers the + same shuffle. ilvev.d will be emitted instead. + +ilvr.d, ilvod.d, pckod.d: + It is not possible to emit ilvr.d, or pckod.d since ilvod.d covers the + same shuffle. ilvod.d will be emitted instead. + +splat.[bhwd] + The intrinsic will work as expected. However, unlike other intrinsics + it lowers directly to MipsISD::VSHF instead of using common IR. + +splati.w: + It is not possible to emit splati.w since shf.w covers the same cases. + shf.w will be emitted instead. + +copy_s.w: + On MIPS32, the copy_u.d intrinsic will emit this instruction instead of + copy_u.w. This is semantically equivalent since the general-purpose + register file is 32-bits wide. + +binsri.[bhwd], binsli.[bhwd]: + These two operations are equivalent to each other with the operands + swapped and condition inverted. The compiler may use either one as + appropriate. + Furthermore, the compiler may use bsel.[bhwd] for some masks that do + not survive the legalization process (this is a bug and will be fixed). + +bmnz.v, bmz.v, bsel.v: + These three operations differ only in the operand that is tied to the + result 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 + operation with the operands swapped. bmnzi.v will (currently) be emitted + for both cases. + +bseli.v: + Unlike the non-immediate versions, bseli.v is distinguishable from + bmnzi.b and bmzi.b and can be emitted. diff --git a/contrib/llvm/lib/Target/Mips/MicroMips32r6InstrFormats.td b/contrib/llvm/lib/Target/Mips/MicroMips32r6InstrFormats.td new file mode 100644 index 0000000..400f6eef --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MicroMips32r6InstrFormats.td @@ -0,0 +1,862 @@ +//=- MicroMips32r6InstrFormats.td - Mips32r6 Instruction Formats -*- tablegen -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes microMIPS32r6 instruction formats. +// +//===----------------------------------------------------------------------===// + +class MMR6Arch<string opstr> { + string Arch = "micromipsr6"; + string BaseOpcode = opstr; +} + +// Class used for microMIPS32r6 and microMIPS64r6 instructions. +class MicroMipsR6Inst16 : PredicateControl { + string DecoderNamespace = "MicroMipsR6"; + let InsnPredicates = [HasMicroMips32r6]; +} + +class BC16_FM_MM16R6 { + bits<10> offset; + + bits<16> Inst; + + let Inst{15-10} = 0x33; + let Inst{9-0} = offset; +} + +class BEQZC_BNEZC_FM_MM16R6<bits<6> op> : MicroMipsR6Inst16 { + bits<3> rs; + bits<7> offset; + + bits<16> Inst; + + let Inst{15-10} = op; + let Inst{9-7} = rs; + let Inst{6-0} = offset; +} + +class POOL16C_JALRC_FM_MM16R6<bits<5> op> { + bits<5> rs; + + bits<16> Inst; + + let Inst{15-10} = 0x11; + let Inst{9-5} = rs; + let Inst{4-0} = op; +} + +class POOL16C_JRCADDIUSP_FM_MM16R6<bits<5> op> { + bits<5> imm; + + bits<16> Inst; + + let Inst{15-10} = 0x11; + let Inst{9-5} = imm; + let Inst{4-0} = op; +} + +class POOL16C_LWM_SWM_FM_MM16R6<bits<4> funct> { + bits<2> rt; + bits<4> addr; + + bits<16> Inst; + + let Inst{15-10} = 0x11; + let Inst{9-8} = rt; + let Inst{7-4} = addr; + let Inst{3-0} = funct; +} + +class POOL32A_BITSWAP_FM_MMR6<bits<6> funct> : MipsR6Inst { + bits<5> rd; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rt; + let Inst{20-16} = rd; + let Inst{15-12} = 0b0000; + let Inst{11-6} = funct; + let Inst{5-0} = 0b111100; +} + +class CACHE_PREF_FM_MMR6<bits<6> opgroup, bits<4> funct> : MipsR6Inst { + bits<21> addr; + bits<5> hint; + + bits<32> Inst; + + let Inst{31-26} = opgroup; + let Inst{25-21} = hint; + let Inst{20-16} = addr{20-16}; + let Inst{15-12} = funct; + let Inst{11-0} = addr{11-0}; +} + +class ARITH_FM_MMR6<string instr_asm, bits<10> funct> : MMR6Arch<instr_asm> { + bits<5> rd; + bits<5> rt; + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-11} = rd; + let Inst{10} = 0; + let Inst{9-0} = funct; +} + +class ADDI_FM_MMR6<string instr_asm, bits<6> op> : MMR6Arch<instr_asm> { + bits<5> rt; + bits<5> rs; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-0} = imm16; +} + +class POOL32C_ST_EVA_FM_MMR6<bits<6> op, bits<3> funct> : MipsR6Inst { + bits<21> addr; + bits<5> hint; + bits<5> base = addr{20-16}; + bits<9> offset = addr{8-0}; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = hint; + let Inst{20-16} = base; + let Inst{15-12} = 0b1010; + let Inst{11-9} = funct; + let Inst{8-0} = offset; +} + +class LB32_FM_MMR6 : MipsR6Inst { + bits<21> addr; + bits<5> rt; + bits<5> base = addr{20-16}; + bits<16> offset = addr{15-0}; + + bits<32> Inst; + + let Inst{31-26} = 0b000111; + let Inst{25-21} = rt; + let Inst{20-16} = base; + let Inst{15-0} = offset; +} + +class LBU32_FM_MMR6 : MipsR6Inst { + bits<21> addr; + bits<5> rt; + bits<5> base = addr{20-16}; + bits<16> offset = addr{15-0}; + + bits<32> Inst; + + let Inst{31-26} = 0b000101; + let Inst{25-21} = rt; + let Inst{20-16} = base; + let Inst{15-0} = offset; +} + +class POOL32C_LB_LBU_FM_MMR6<bits<3> funct> : MipsR6Inst { + bits<21> addr; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0b011000; + let Inst{25-21} = rt; + let Inst{20-16} = addr{20-16}; + let Inst{15-12} = 0b0110; + let Inst{11-9} = funct; + let Inst{8-0} = addr{8-0}; +} + +class SIGN_EXTEND_FM_MMR6<string instr_asm, bits<10> funct> + : MMR6Arch<instr_asm> { + bits<5> rd; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rd; + let Inst{20-16} = rt; + let Inst{15-6} = funct; + let Inst{5-0} = 0b111100; +} + +class PCREL19_FM_MMR6<bits<2> funct> : MipsR6Inst { + bits<5> rt; + bits<19> imm; + + bits<32> Inst; + + let Inst{31-26} = 0b011110; + let Inst{25-21} = rt; + let Inst{20-19} = funct; + let Inst{18-0} = imm; +} + +class PCREL16_FM_MMR6<bits<5> funct> : MipsR6Inst { + bits<5> rt; + bits<16> imm; + + bits<32> Inst; + + let Inst{31-26} = 0b011110; + let Inst{25-21} = rt; + let Inst{20-16} = funct; + let Inst{15-0} = imm; +} + +class POOL32A_FM_MMR6<bits<10> funct> : MipsR6Inst { + bits<5> rd; + bits<5> rs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-11} = rd; + let Inst{10} = 0; + let Inst{9-0} = funct; +} + +class POOL32A_PAUSE_FM_MMR6<string instr_asm, bits<5> op> : MMR6Arch<instr_asm> { + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = 0; + let Inst{20-16} = 0; + let Inst{15-11} = op; + let Inst{10-6} = 0; + let Inst{5-0} = 0; +} + +class POOL32A_RDPGPR_FM_MMR6<bits<10> funct> { + bits<5> rt; + bits<5> rd; + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rt; + let Inst{20-16} = rd; + let Inst{15-6} = funct; + let Inst{5-0} = 0b111100; +} + +class POOL32A_RDHWR_FM_MMR6 { + bits<5> rt; + bits<5> rs; + bits<3> sel; + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-14} = 0; + let Inst{13-11} = sel; + let Inst{10} = 0; + let Inst{9-0} = 0b0111000000; +} + +class POOL32A_SYNC_FM_MMR6 { + bits<5> stype; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = 0; + let Inst{20-16} = stype; + let Inst{15-6} = 0b0110101101; + let Inst{5-0} = 0b111100; +} + +class POOL32I_SYNCI_FM_MMR6 { + bits<21> addr; + bits<5> base = addr{20-16}; + bits<16> immediate = addr{15-0}; + + bits<32> Inst; + + let Inst{31-26} = 0b010000; + let Inst{25-21} = 0b01100; + let Inst{20-16} = base; + let Inst{15-0} = immediate; +} + +class POOL32A_2R_FM_MMR6<bits<10> funct> : MipsR6Inst { + bits<5> rs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-6} = funct; + let Inst{5-0} = 0b111100; +} + +class SPECIAL_2R_FM_MMR6<bits<6> funct> : MipsR6Inst { + bits<5> rs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rs; + let Inst{20-16} = 0b00000; + let Inst{15-11} = rt; + let Inst{10-6} = 0b00001; + let Inst{5-0} = funct; +} + +class POOL32A_ALIGN_FM_MMR6<bits<6> funct> : MipsR6Inst { + bits<5> rd; + bits<5> rs; + bits<5> rt; + bits<2> bp; + + bits<32> Inst; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-9} = bp; + let Inst{8-6} = 0b000; + let Inst{5-0} = funct; +} + +class AUI_FM_MMR6 : MipsR6Inst { + bits<5> rs; + bits<5> rt; + bits<16> imm; + + bits<32> Inst; + + let Inst{31-26} = 0b000100; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-0} = imm; +} + +class POOL32A_LSA_FM<bits<6> funct> : MipsR6Inst { + bits<5> rd; + bits<5> rs; + bits<5> rt; + bits<2> imm2; + + bits<32> Inst; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-11} = rd; + let Inst{10-9} = imm2; + let Inst{8-6} = 0b000; + let Inst{5-0} = funct; +} + +class SB32_SH32_STORE_FM_MMR6<bits<6> op> { + bits<5> rt; + bits<21> addr; + bits<5> base = addr{20-16}; + bits<16> offset = addr{15-0}; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rt; + let Inst{20-16} = base; + let Inst{15-0} = offset; +} + +class POOL32C_STORE_EVA_FM_MMR6<bits<3> funct> { + bits<5> rt; + bits<21> addr; + bits<5> base = addr{20-16}; + bits<9> offset = addr{8-0}; + + bits<32> Inst; + + let Inst{31-26} = 0b011000; + let Inst{25-21} = rt; + let Inst{20-16} = base; + let Inst{15-12} = 0b1010; + let Inst{11-9} = funct; + let Inst{8-0} = offset; +} + +class LOAD_WORD_EVA_FM_MMR6<bits<3> funct> { + bits<5> rt; + bits<21> addr; + bits<5> base = addr{20-16}; + bits<9> offset = addr{8-0}; + + bits<32> Inst; + + let Inst{31-26} = 0b011000; + let Inst{25-21} = rt; + let Inst{20-16} = base; + let Inst{15-12} = 0b0110; + let Inst{11-9} = funct; + let Inst{8-0} = offset; +} + +class LOAD_WORD_FM_MMR6 { + bits<5> rt; + bits<21> addr; + bits<5> base = addr{20-16}; + bits<16> offset = addr{15-0}; + + bits<32> Inst; + + let Inst{31-26} = 0b111111; + let Inst{25-21} = rt; + let Inst{20-16} = base; + let Inst{15-0} = offset; +} + +class LOAD_UPPER_IMM_FM_MMR6 { + bits<5> rt; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = 0b000100; + let Inst{25-21} = rt; + let Inst{20-16} = 0; + let Inst{15-0} = imm16; +} + +class CMP_BRANCH_1R_RT_OFF16_FM_MMR6<bits<6> funct> : MipsR6Inst { + bits<5> rt; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = funct; + let Inst{25-21} = rt; + let Inst{20-16} = 0b00000; + let Inst{15-0} = offset; +} + +class CMP_BRANCH_1R_BOTH_OFF16_FM_MMR6<bits<6> funct> : MipsR6Inst { + bits<5> rt; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = funct; + let Inst{25-21} = rt; + let Inst{20-16} = rt; + let Inst{15-0} = offset; +} + +class POOL32A_ERET_FM_MMR6<string instr_asm, bits<10> funct> + : MMR6Arch<instr_asm> { + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-16} = 0x00; + let Inst{15-6} = funct; + let Inst{5-0} = 0x3c; +} + +class ERETNC_FM_MMR6<string instr_asm> : MMR6Arch<instr_asm> { + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-17} = 0x00; + let Inst{16-16} = 0x01; + let Inst{15-6} = 0x3cd; + let Inst{5-0} = 0x3c; +} + +class BREAK_MMR6_ENC<string instr_asm> : MMR6Arch<instr_asm> { + 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 BARRIER_MMR6_ENC<string instr_asm, bits<5> op> : MMR6Arch<instr_asm> { + bits<32> Inst; + + let Inst{31-26} = 0x0; + let Inst{25-21} = 0x0; + let Inst{20-16} = 0x0; + let Inst{15-11} = op; + let Inst{10-6} = 0x0; + let Inst{5-0} = 0x0; +} + +class POOL32A_EIDI_MMR6_ENC<string instr_asm, bits<10> funct> + : MMR6Arch<instr_asm> { + bits<32> Inst; + bits<5> rt; // Actually rs but we're sharing code with the standard encodings which call it 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 SHIFT_MMR6_ENC<string instr_asm, bits<10> funct, bit rotate> : MMR6Arch<instr_asm> { + bits<5> rd; + bits<5> rt; + bits<5> shamt; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rd; + let Inst{20-16} = rt; + let Inst{15-11} = shamt; + let Inst{10} = rotate; + let Inst{9-0} = funct; +} + +class SW32_FM_MMR6<string instr_asm, bits<6> op> : MMR6Arch<instr_asm> { + bits<5> rt; + bits<21> addr; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rt; + let Inst{20-16} = addr{20-16}; + let Inst{15-0} = addr{15-0}; +} + +class POOL32C_SWE_FM_MMR6<string instr_asm, bits<6> op, bits<4> fmt, + bits<3> funct> : MMR6Arch<instr_asm> { + bits<5> rt; + bits<21> addr; + bits<5> base = addr{20-16}; + bits<9> offset = addr{8-0}; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rt; + let Inst{20-16} = base; + let Inst{15-12} = fmt; + let Inst{11-9} = funct; + let Inst{8-0} = offset; +} + +class POOL32F_ARITH_FM_MMR6<string instr_asm, bits<2> fmt, bits<8> funct> + : MMR6Arch<instr_asm>, MipsR6Inst { + bits<5> ft; + bits<5> fs; + bits<5> fd; + + bits<32> Inst; + + let Inst{31-26} = 0b010101; + 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; +} + +class POOL32F_ARITHF_FM_MMR6<string instr_asm, bits<2> fmt, bits<9> funct> + : MMR6Arch<instr_asm>, MipsR6Inst { + bits<5> ft; + bits<5> fs; + bits<5> fd; + + bits<32> Inst; + + let Inst{31-26} = 0b010101; + let Inst{25-21} = ft; + let Inst{20-16} = fs; + let Inst{15-11} = fd; + let Inst{10-9} = fmt; + let Inst{8-0} = funct; +} + +class POOL32F_MOV_NEG_FM_MMR6<string instr_asm, bits<2> fmt, bits<7> funct> + : MMR6Arch<instr_asm>, MipsR6Inst { + bits<5> ft; + bits<5> fs; + + bits<32> Inst; + + let Inst{31-26} = 0b010101; + let Inst{25-21} = ft; + let Inst{20-16} = fs; + let Inst{15} = 0; + let Inst{14-13} = fmt; + let Inst{12-6} = funct; + let Inst{5-0} = 0b111011; +} + +class POOL32F_MINMAX_FM<string instr_asm, bits<2> fmt, bits<9> funct> + : MMR6Arch<instr_asm>, MipsR6Inst { + bits<5> ft; + bits<5> fs; + bits<5> fd; + + bits<32> Inst; + + let Inst{31-26} = 0b010101; + let Inst{25-21} = ft; + let Inst{20-16} = fs; + let Inst{15-11} = fd; + let Inst{10-9} = fmt; + let Inst{8-0} = funct; +} + +class POOL32F_CMP_FM<string instr_asm, bits<6> format, FIELD_CMP_COND Cond> + : MMR6Arch<instr_asm>, MipsR6Inst { + bits<5> ft; + bits<5> fs; + bits<5> fd; + + bits<32> Inst; + + let Inst{31-26} = 0b010101; + let Inst{25-21} = ft; + let Inst{20-16} = fs; + let Inst{15-11} = fd; + let Inst{10-6} = Cond.Value; + let Inst{5-0} = format; +} + +class POOL32F_CVT_LW_FM<string instr_asm, bit fmt, bits<8> funct> + : MMR6Arch<instr_asm>, MipsR6Inst { + bits<5> ft; + bits<5> fs; + + bits<32> Inst; + let Inst{31-26} = 0b010101; + let Inst{25-21} = ft; + let Inst{20-16} = fs; + let Inst{15} = 0; + let Inst{14} = fmt; + let Inst{13-6} = funct; + let Inst{5-0} = 0b111011; +} + +class POOL32F_CVT_DS_FM<string instr_asm, bits<2> fmt, bits<7> funct> + : MMR6Arch<instr_asm>, MipsR6Inst { + bits<5> ft; + bits<5> fs; + + bits<32> Inst; + let Inst{31-26} = 0b010101; + let Inst{25-21} = ft; + let Inst{20-16} = fs; + let Inst{15} = 0; + let Inst{14-13} = fmt; + let Inst{12-6} = funct; + let Inst{5-0} = 0b111011; +} + +class POOL32F_ABS_FM_MMR6<string instr_asm, bits<2> fmt, bits<7> funct> + : MMR6Arch<instr_asm>, MipsR6Inst { + bits<5> ft; + bits<5> fs; + + bits<32> Inst; + + let Inst{31-26} = 0b010101; + let Inst{25-21} = ft; + let Inst{20-16} = fs; + let Inst{15} = 0; + let Inst{14-13} = fmt; + let Inst{12-6} = funct; + let Inst{5-0} = 0b111011; +} + +class POOL32F_MATH_FM_MMR6<string instr_asm, bits<1> fmt, bits<8> funct> + : MMR6Arch<instr_asm>, MipsR6Inst { + bits<5> ft; + bits<5> fs; + + bits<32> Inst; + + let Inst{31-26} = 0b010101; + let Inst{25-21} = ft; + let Inst{20-16} = fs; + let Inst{15} = 0; + let Inst{14} = fmt; + let Inst{13-6} = funct; + let Inst{5-0} = 0b111011; +} + +class POOL16A_ADDU16_FM_MMR6 : MicroMipsR6Inst16 { + bits<3> rs; + bits<3> rt; + bits<3> rd; + + bits<16> Inst; + + let Inst{15-10} = 0b000001; + let Inst{9-7} = rs; + let Inst{6-4} = rt; + let Inst{3-1} = rd; + let Inst{0} = 0; +} + +class POOL16C_AND16_FM_MMR6 : MicroMipsR6Inst16 { + bits<3> rt; + bits<3> rs; + + bits<16> Inst; + + let Inst{15-10} = 0b010001; + let Inst{9-7} = rt; + let Inst{6-4} = rs; + let Inst{3-0} = 0b0001; +} + +class POOL16C_NOT16_FM_MMR6 : MicroMipsR6Inst16 { + bits<3> rt; + bits<3> rs; + + bits<16> Inst; + + let Inst{15-10} = 0x11; + let Inst{9-7} = rt; + let Inst{6-4} = rs; + let Inst{3-0} = 0b0000; +} + +class POOL16C_OR16_XOR16_FM_MMR6<bits<4> op> { + bits<3> rt; + bits<3> rs; + + bits<16> Inst; + + let Inst{15-10} = 0b010001; + let Inst{9-7} = rt; + let Inst{6-4} = rs; + let Inst{3-0} = op; +} + +class POOL16C_BREAKPOINT_FM_MMR6<bits<6> op> { + bits<4> code_; + bits<16> Inst; + + let Inst{15-10} = 0b010001; + let Inst{9-6} = code_; + let Inst{5-0} = op; +} + +class POOL16A_SUBU16_FM_MMR6 { + bits<3> rs; + bits<3> rt; + bits<3> rd; + + bits<16> Inst; + + let Inst{15-10} = 0b000001; + let Inst{9-7} = rs; + let Inst{6-4} = rt; + let Inst{3-1} = rd; + let Inst{0} = 0b1; +} + +class POOL32A_WRPGPR_WSBH_FM_MMR6<bits<10> funct> : MipsR6Inst { + bits<5> rt; + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-6} = funct; + let Inst{5-0} = 0x3c; +} + +class POOL32F_RECIP_ROUND_FM_MMR6<string instr_asm, bits<1> fmt, bits<8> funct> + : MMR6Arch<instr_asm>, MipsR6Inst { + bits<5> ft; + bits<5> fs; + + bits<32> Inst; + + let Inst{31-26} = 0b010101; + let Inst{25-21} = ft; + let Inst{20-16} = fs; + let Inst{15} = 0; + let Inst{14} = fmt; + let Inst{13-6} = funct; + let Inst{5-0} = 0b111011; +} + +class POOL32F_RINT_FM_MMR6<string instr_asm, bits<2> fmt> + : MMR6Arch<instr_asm>, MipsR6Inst { + bits<5> fs; + bits<5> fd; + + bits<32> Inst; + + let Inst{31-26} = 0b010101; + let Inst{25-21} = fs; + let Inst{20-16} = fd; + let Inst{15-11} = 0; + let Inst{10-9} = fmt; + let Inst{8-0} = 0b000100000; +} + +class POOL32F_SEL_FM_MMR6<string instr_asm, bits<2> fmt, bits<9> funct> + : MMR6Arch<instr_asm>, MipsR6Inst { + bits<5> ft; + bits<5> fs; + bits<5> fd; + + bits<32> Inst; + + let Inst{31-26} = 0b010101; + let Inst{25-21} = ft; + let Inst{20-16} = fs; + let Inst{15-11} = fd; + let Inst{10-9} = fmt; + let Inst{8-0} = funct; +} + +class POOL32F_CLASS_FM_MMR6<string instr_asm, bits<2> fmt, bits<9> funct> + : MMR6Arch<instr_asm>, MipsR6Inst { + bits<5> fs; + bits<5> fd; + + bits<32> Inst; + + let Inst{31-26} = 0b010101; + let Inst{25-21} = fs; + let Inst{20-16} = fd; + let Inst{15-11} = 0b00000; + let Inst{10-9} = fmt; + let Inst{8-0} = funct; +} diff --git a/contrib/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td b/contrib/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td new file mode 100644 index 0000000..31b5db0 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td @@ -0,0 +1,1233 @@ +//=- MicroMips32r6InstrInfo.td - MicroMips r6 Instruction Information -*- tablegen -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes microMIPSr6 instructions. +// +//===----------------------------------------------------------------------===// + +def brtarget26_mm : Operand<OtherVT> { + let EncoderMethod = "getBranchTarget26OpValueMM"; + let OperandType = "OPERAND_PCREL"; + let DecoderMethod = "DecodeBranchTarget26MM"; + let ParserMatchClass = MipsJumpTargetAsmOperand; +} + +//===----------------------------------------------------------------------===// +// +// Instruction Encodings +// +//===----------------------------------------------------------------------===// +class ADD_MMR6_ENC : ARITH_FM_MMR6<"add", 0x110>; +class ADDIU_MMR6_ENC : ADDI_FM_MMR6<"addiu", 0xc>; +class ADDU_MMR6_ENC : ARITH_FM_MMR6<"addu", 0x150>; +class ADDIUPC_MMR6_ENC : PCREL19_FM_MMR6<0b00>; +class ALUIPC_MMR6_ENC : PCREL16_FM_MMR6<0b11111>; +class AND_MMR6_ENC : ARITH_FM_MMR6<"and", 0x250>; +class ANDI_MMR6_ENC : ADDI_FM_MMR6<"andi", 0x34>; +class AUIPC_MMR6_ENC : PCREL16_FM_MMR6<0b11110>; +class ALIGN_MMR6_ENC : POOL32A_ALIGN_FM_MMR6<0b011111>; +class AUI_MMR6_ENC : AUI_FM_MMR6; +class BALC_MMR6_ENC : BRANCH_OFF26_FM<0b101101>; +class BC_MMR6_ENC : BRANCH_OFF26_FM<0b100101>; +class BC16_MMR6_ENC : BC16_FM_MM16R6; +class BEQZC16_MMR6_ENC : BEQZC_BNEZC_FM_MM16R6<0x23>; +class BNEZC16_MMR6_ENC : BEQZC_BNEZC_FM_MM16R6<0x2b>; +class BITSWAP_MMR6_ENC : POOL32A_BITSWAP_FM_MMR6<0b101100>; +class BRK_MMR6_ENC : BREAK_MMR6_ENC<"break">; +class BEQZALC_MMR6_ENC : CMP_BRANCH_1R_RT_OFF16_FM_MMR6<0b011101>; +class BNEZALC_MMR6_ENC : CMP_BRANCH_1R_RT_OFF16_FM_MMR6<0b011111>; +class BGTZALC_MMR6_ENC : CMP_BRANCH_1R_RT_OFF16_FM_MMR6<0b111000>; +class BLTZALC_MMR6_ENC : CMP_BRANCH_1R_BOTH_OFF16_FM_MMR6<0b111000>; +class BGEZALC_MMR6_ENC : CMP_BRANCH_1R_BOTH_OFF16_FM_MMR6<0b110000>; +class BLEZALC_MMR6_ENC : CMP_BRANCH_1R_RT_OFF16_FM_MMR6<0b110000>; +class CACHE_MMR6_ENC : CACHE_PREF_FM_MMR6<0b001000, 0b0110>; +class CLO_MMR6_ENC : POOL32A_2R_FM_MMR6<0b0100101100>; +class CLZ_MMR6_ENC : SPECIAL_2R_FM_MMR6<0b010000>; +class DIV_MMR6_ENC : ARITH_FM_MMR6<"div", 0x118>; +class DIVU_MMR6_ENC : ARITH_FM_MMR6<"divu", 0x198>; +class EHB_MMR6_ENC : BARRIER_MMR6_ENC<"ehb", 0x3>; +class EI_MMR6_ENC : POOL32A_EIDI_MMR6_ENC<"ei", 0x15d>; +class DI_MMR6_ENC : POOL32A_EIDI_MMR6_ENC<"di", 0b0100011101>; +class ERET_MMR6_ENC : POOL32A_ERET_FM_MMR6<"eret", 0x3cd>; +class DERET_MMR6_ENC : POOL32A_ERET_FM_MMR6<"eret", 0b1110001101>; +class ERETNC_MMR6_ENC : ERETNC_FM_MMR6<"eretnc">; +class JALRC16_MMR6_ENC : POOL16C_JALRC_FM_MM16R6<0xb>; +class JIALC_MMR6_ENC : JMP_IDX_COMPACT_FM<0b100000>; +class JIC_MMR6_ENC : JMP_IDX_COMPACT_FM<0b101000>; +class JRC16_MMR6_ENC: POOL16C_JALRC_FM_MM16R6<0x3>; +class JRCADDIUSP_MMR6_ENC : POOL16C_JRCADDIUSP_FM_MM16R6<0x13>; +class LSA_MMR6_ENC : POOL32A_LSA_FM<0b001111>; +class LWPC_MMR6_ENC : PCREL19_FM_MMR6<0b01>; +class LWM16_MMR6_ENC : POOL16C_LWM_SWM_FM_MM16R6<0x2>; +class MOD_MMR6_ENC : ARITH_FM_MMR6<"mod", 0x158>; +class MODU_MMR6_ENC : ARITH_FM_MMR6<"modu", 0x1d8>; +class MUL_MMR6_ENC : ARITH_FM_MMR6<"mul", 0x18>; +class MUH_MMR6_ENC : ARITH_FM_MMR6<"muh", 0x58>; +class MULU_MMR6_ENC : ARITH_FM_MMR6<"mulu", 0x98>; +class MUHU_MMR6_ENC : ARITH_FM_MMR6<"muhu", 0xd8>; +class NOR_MMR6_ENC : ARITH_FM_MMR6<"nor", 0x2d0>; +class OR_MMR6_ENC : ARITH_FM_MMR6<"or", 0x290>; +class ORI_MMR6_ENC : ADDI_FM_MMR6<"ori", 0x14>; +class PREF_MMR6_ENC : CACHE_PREF_FM_MMR6<0b011000, 0b0010>; +class SB16_MMR6_ENC : LOAD_STORE_FM_MM16<0x22>; +class SEB_MMR6_ENC : SIGN_EXTEND_FM_MMR6<"seb", 0b0010101100>; +class SEH_MMR6_ENC : SIGN_EXTEND_FM_MMR6<"seh", 0b0011101100>; +class SELEQZ_MMR6_ENC : POOL32A_FM_MMR6<0b0101000000>; +class SELNEZ_MMR6_ENC : POOL32A_FM_MMR6<0b0110000000>; +class SH16_MMR6_ENC : LOAD_STORE_FM_MM16<0x2a>; +class SLL_MMR6_ENC : SHIFT_MMR6_ENC<"sll", 0x00, 0b0>; +class SUB_MMR6_ENC : ARITH_FM_MMR6<"sub", 0x190>; +class SUBU_MMR6_ENC : ARITH_FM_MMR6<"subu", 0x1d0>; +class SW_MMR6_ENC : SW32_FM_MMR6<"sw", 0x3e>; +class SWE_MMR6_ENC : POOL32C_SWE_FM_MMR6<"swe", 0x18, 0xa, 0x7>; +class SW16_MMR6_ENC : LOAD_STORE_FM_MM16<0x3a>; +class SWM16_MMR6_ENC : POOL16C_LWM_SWM_FM_MM16R6<0xa>; +class SWSP_MMR6_ENC : LOAD_STORE_SP_FM_MM16<0x32>; +class PREFE_MMR6_ENC : POOL32C_ST_EVA_FM_MMR6<0b011000, 0b010>; +class CACHEE_MMR6_ENC : POOL32C_ST_EVA_FM_MMR6<0b011000, 0b011>; +class WRPGPR_MMR6_ENC : POOL32A_WRPGPR_WSBH_FM_MMR6<0x3c5>; +class WSBH_MMR6_ENC : POOL32A_WRPGPR_WSBH_FM_MMR6<0x1ec>; +class LB_MMR6_ENC : LB32_FM_MMR6; +class LBU_MMR6_ENC : LBU32_FM_MMR6; +class LBE_MMR6_ENC : POOL32C_LB_LBU_FM_MMR6<0b100>; +class LBUE_MMR6_ENC : POOL32C_LB_LBU_FM_MMR6<0b000>; +class PAUSE_MMR6_ENC : POOL32A_PAUSE_FM_MMR6<"pause", 0b00101>; +class RDHWR_MMR6_ENC : POOL32A_RDHWR_FM_MMR6; +class WAIT_MMR6_ENC : WAIT_FM_MM, MMR6Arch<"wait">; +class SSNOP_MMR6_ENC : BARRIER_FM_MM<0x1>, MMR6Arch<"ssnop">; +class SYNC_MMR6_ENC : POOL32A_SYNC_FM_MMR6; +class SYNCI_MMR6_ENC : POOL32I_SYNCI_FM_MMR6, MMR6Arch<"synci">; +class RDPGPR_MMR6_ENC : POOL32A_RDPGPR_FM_MMR6<0b1110000101>; +class SDBBP_MMR6_ENC : SDBBP_FM_MM, MMR6Arch<"sdbbp">; +class XOR_MMR6_ENC : ARITH_FM_MMR6<"xor", 0x310>; +class XORI_MMR6_ENC : ADDI_FM_MMR6<"xori", 0x1c>; +class ABS_S_MMR6_ENC : POOL32F_ABS_FM_MMR6<"abs.s", 0, 0b0001101>; +class ABS_D_MMR6_ENC : POOL32F_ABS_FM_MMR6<"abs.d", 1, 0b0001101>; +class FLOOR_L_S_MMR6_ENC : POOL32F_MATH_FM_MMR6<"floor.l.s", 0, 0b00001100>; +class FLOOR_L_D_MMR6_ENC : POOL32F_MATH_FM_MMR6<"floor.l.d", 1, 0b00001100>; +class FLOOR_W_S_MMR6_ENC : POOL32F_MATH_FM_MMR6<"floor.w.s", 0, 0b00101100>; +class FLOOR_W_D_MMR6_ENC : POOL32F_MATH_FM_MMR6<"floor.w.d", 1, 0b00101100>; +class CEIL_L_S_MMR6_ENC : POOL32F_MATH_FM_MMR6<"ceil.l.s", 0, 0b01001100>; +class CEIL_L_D_MMR6_ENC : POOL32F_MATH_FM_MMR6<"ceil.l.d", 1, 0b01001100>; +class CEIL_W_S_MMR6_ENC : POOL32F_MATH_FM_MMR6<"ceil.w.s", 0, 0b01101100>; +class CEIL_W_D_MMR6_ENC : POOL32F_MATH_FM_MMR6<"ceil.w.d", 1, 0b01101100>; +class TRUNC_L_S_MMR6_ENC : POOL32F_MATH_FM_MMR6<"trunc.l.s", 0, 0b10001100>; +class TRUNC_L_D_MMR6_ENC : POOL32F_MATH_FM_MMR6<"trunc.l.d", 1, 0b10001100>; +class TRUNC_W_S_MMR6_ENC : POOL32F_MATH_FM_MMR6<"trunc.w.s", 0, 0b10101100>; +class TRUNC_W_D_MMR6_ENC : POOL32F_MATH_FM_MMR6<"trunc.w.d", 1, 0b10101100>; +class SQRT_S_MMR6_ENC : POOL32F_MATH_FM_MMR6<"sqrt.s", 0, 0b00101000>; +class SQRT_D_MMR6_ENC : POOL32F_MATH_FM_MMR6<"sqrt.d", 1, 0b00101000>; +class RSQRT_S_MMR6_ENC : POOL32F_MATH_FM_MMR6<"rsqrt.s", 0, 0b00001000>; +class RSQRT_D_MMR6_ENC : POOL32F_MATH_FM_MMR6<"rsqrt.d", 1, 0b00001000>; +class SB_MMR6_ENC : SB32_SH32_STORE_FM_MMR6<0b000110>; +class SBE_MMR6_ENC : POOL32C_STORE_EVA_FM_MMR6<0b100>; +class SCE_MMR6_ENC : POOL32C_STORE_EVA_FM_MMR6<0b110>; +class SH_MMR6_ENC : SB32_SH32_STORE_FM_MMR6<0b001110>; +class SHE_MMR6_ENC : POOL32C_STORE_EVA_FM_MMR6<0b101>; +class LLE_MMR6_ENC : LOAD_WORD_EVA_FM_MMR6<0b110>; +class LWE_MMR6_ENC : LOAD_WORD_EVA_FM_MMR6<0b111>; +class LW_MMR6_ENC : LOAD_WORD_FM_MMR6; +class LUI_MMR6_ENC : LOAD_UPPER_IMM_FM_MMR6; +class RECIP_S_MMR6_ENC : POOL32F_RECIP_ROUND_FM_MMR6<"recip.s", 0, 0b01001000>; +class RECIP_D_MMR6_ENC : POOL32F_RECIP_ROUND_FM_MMR6<"recip.d", 1, 0b01001000>; +class RINT_S_MMR6_ENC : POOL32F_RINT_FM_MMR6<"rint.s", 0>; +class RINT_D_MMR6_ENC : POOL32F_RINT_FM_MMR6<"rint.d", 1>; +class ROUND_L_S_MMR6_ENC : POOL32F_RECIP_ROUND_FM_MMR6<"round.l.s", 0, + 0b11001100>; +class ROUND_L_D_MMR6_ENC : POOL32F_RECIP_ROUND_FM_MMR6<"round.l.d", 1, + 0b11001100>; +class ROUND_W_S_MMR6_ENC : POOL32F_RECIP_ROUND_FM_MMR6<"round.w.s", 0, + 0b11101100>; +class ROUND_W_D_MMR6_ENC : POOL32F_RECIP_ROUND_FM_MMR6<"round.w.d", 1, + 0b11101100>; +class SEL_S_MMR6_ENC : POOL32F_SEL_FM_MMR6<"sel.s", 0, 0b010111000>; +class SEL_D_MMR6_ENC : POOL32F_SEL_FM_MMR6<"sel.d", 1, 0b010111000>; +class SELEQZ_S_MMR6_ENC : POOL32F_SEL_FM_MMR6<"seleqz.s", 0, 0b000111000>; +class SELEQZ_D_MMR6_ENC : POOL32F_SEL_FM_MMR6<"seleqz.d", 1, 0b000111000>; +class SELENZ_S_MMR6_ENC : POOL32F_SEL_FM_MMR6<"selenz.s", 0, 0b001111000>; +class SELENZ_D_MMR6_ENC : POOL32F_SEL_FM_MMR6<"selenz.d", 1, 0b001111000>; +class CLASS_S_MMR6_ENC : POOL32F_CLASS_FM_MMR6<"class.s", 0, 0b001100000>; +class CLASS_D_MMR6_ENC : POOL32F_CLASS_FM_MMR6<"class.d", 1, 0b001100000>; + +class ADDU16_MMR6_ENC : POOL16A_ADDU16_FM_MMR6; +class AND16_MMR6_ENC : POOL16C_AND16_FM_MMR6; +class ANDI16_MMR6_ENC : ANDI_FM_MM16<0b001011>, MicroMipsR6Inst16; +class NOT16_MMR6_ENC : POOL16C_NOT16_FM_MMR6; +class OR16_MMR6_ENC : POOL16C_OR16_XOR16_FM_MMR6<0b1001>; +class SLL16_MMR6_ENC : SHIFT_FM_MM16<0>, MicroMipsR6Inst16; +class SRL16_MMR6_ENC : SHIFT_FM_MM16<1>, MicroMipsR6Inst16; +class BREAK16_MMR6_ENC : POOL16C_BREAKPOINT_FM_MMR6<0b011011>; +class LI16_MMR6_ENC : LI_FM_MM16; +class MOVE16_MMR6_ENC : MOVE_FM_MM16<0b000011>; +class SDBBP16_MMR6_ENC : POOL16C_BREAKPOINT_FM_MMR6<0b111011>; +class SUBU16_MMR6_ENC : POOL16A_SUBU16_FM_MMR6; +class XOR16_MMR6_ENC : POOL16C_OR16_XOR16_FM_MMR6<0b1000>; + +class CMP_CBR_RT_Z_MMR6_DESC_BASE<string instr_asm, DAGOperand opnd, + RegisterOperand GPROpnd> + : BRANCH_DESC_BASE, MMR6Arch<instr_asm> { + dag InOperandList = (ins GPROpnd:$rt, opnd:$offset); + dag OutOperandList = (outs); + string AsmString = !strconcat(instr_asm, "\t$rt, $offset"); + list<Register> Defs = [AT]; +} + +class BEQZALC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"beqzalc", brtarget_mm, + GPR32Opnd> { + list<Register> Defs = [RA]; +} + +class BGEZALC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"bgezalc", brtarget_mm, + GPR32Opnd> { + list<Register> Defs = [RA]; +} + +class BGTZALC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"bgtzalc", brtarget_mm, + GPR32Opnd> { + list<Register> Defs = [RA]; +} + +class BLEZALC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"blezalc", brtarget_mm, + GPR32Opnd> { + list<Register> Defs = [RA]; +} + +class BLTZALC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"bltzalc", brtarget_mm, + GPR32Opnd> { + list<Register> Defs = [RA]; +} + +class BNEZALC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"bnezalc", brtarget_mm, + GPR32Opnd> { + list<Register> Defs = [RA]; +} + +/// Floating Point Instructions +class FADD_S_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"add.s", 0, 0b00110000>; +class FADD_D_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"add.d", 1, 0b00110000>; +class FSUB_S_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"sub.s", 0, 0b01110000>; +class FSUB_D_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"sub.d", 1, 0b01110000>; +class FMUL_S_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"mul.s", 0, 0b10110000>; +class FMUL_D_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"mul.d", 1, 0b10110000>; +class FDIV_S_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"div.s", 0, 0b11110000>; +class FDIV_D_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"div.d", 1, 0b11110000>; +class MADDF_S_MMR6_ENC : POOL32F_ARITHF_FM_MMR6<"maddf.s", 0, 0b110111000>; +class MADDF_D_MMR6_ENC : POOL32F_ARITHF_FM_MMR6<"maddf.d", 1, 0b110111000>; +class MSUBF_S_MMR6_ENC : POOL32F_ARITHF_FM_MMR6<"msubf.s", 0, 0b111111000>; +class MSUBF_D_MMR6_ENC : POOL32F_ARITHF_FM_MMR6<"msubf.d", 1, 0b111111000>; +class FMOV_S_MMR6_ENC : POOL32F_MOV_NEG_FM_MMR6<"mov.s", 0, 0b0000001>; +class FMOV_D_MMR6_ENC : POOL32F_MOV_NEG_FM_MMR6<"mov.d", 1, 0b0000001>; +class FNEG_S_MMR6_ENC : POOL32F_MOV_NEG_FM_MMR6<"neg.s", 0, 0b0101101>; +class FNEG_D_MMR6_ENC : POOL32F_MOV_NEG_FM_MMR6<"neg.d", 1, 0b0101101>; +class MAX_S_MMR6_ENC : POOL32F_MINMAX_FM<"max.s", 0, 0b000001011>; +class MAX_D_MMR6_ENC : POOL32F_MINMAX_FM<"max.d", 1, 0b000001011>; +class MAXA_S_MMR6_ENC : POOL32F_MINMAX_FM<"maxa.s", 0, 0b000101011>; +class MAXA_D_MMR6_ENC : POOL32F_MINMAX_FM<"maxa.d", 1, 0b000101011>; +class MIN_S_MMR6_ENC : POOL32F_MINMAX_FM<"min.s", 0, 0b000000011>; +class MIN_D_MMR6_ENC : POOL32F_MINMAX_FM<"min.d", 1, 0b000000011>; +class MINA_S_MMR6_ENC : POOL32F_MINMAX_FM<"mina.s", 0, 0b000100011>; +class MINA_D_MMR6_ENC : POOL32F_MINMAX_FM<"mina.d", 1, 0b000100011>; + +class CVT_L_S_MMR6_ENC : POOL32F_CVT_LW_FM<"cvt.l.s", 0, 0b00000100>; +class CVT_L_D_MMR6_ENC : POOL32F_CVT_LW_FM<"cvt.l.d", 1, 0b00000100>; +class CVT_W_S_MMR6_ENC : POOL32F_CVT_LW_FM<"cvt.w.s", 0, 0b00100100>; +class CVT_W_D_MMR6_ENC : POOL32F_CVT_LW_FM<"cvt.w.d", 1, 0b00100100>; +class CVT_D_S_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.d.s", 0, 0b1001101>; +class CVT_D_W_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.d.w", 1, 0b1001101>; +class CVT_D_L_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.d.l", 2, 0b1001101>; +class CVT_S_D_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.s.d", 0, 0b1101101>; +class CVT_S_W_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.s.w", 1, 0b1101101>; +class CVT_S_L_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.s.l", 2, 0b1101101>; + +//===----------------------------------------------------------------------===// +// +// Instruction Descriptions +// +//===----------------------------------------------------------------------===// + +class ADD_MMR6_DESC : ArithLogicR<"add", GPR32Opnd>; +class ADDIU_MMR6_DESC : ArithLogicI<"addiu", simm16, GPR32Opnd>; +class ADDU_MMR6_DESC : ArithLogicR<"addu", GPR32Opnd>; +class MUL_MMR6_DESC : ArithLogicR<"mul", GPR32Opnd>; +class MUH_MMR6_DESC : ArithLogicR<"muh", GPR32Opnd>; +class MULU_MMR6_DESC : ArithLogicR<"mulu", GPR32Opnd>; +class MUHU_MMR6_DESC : ArithLogicR<"muhu", GPR32Opnd>; + +class BC_MMR6_DESC_BASE<string instr_asm, DAGOperand opnd> + : BRANCH_DESC_BASE, MMR6Arch<instr_asm> { + dag InOperandList = (ins opnd:$offset); + dag OutOperandList = (outs); + string AsmString = !strconcat(instr_asm, "\t$offset"); + bit isBarrier = 1; +} + +class BALC_MMR6_DESC : BC_MMR6_DESC_BASE<"balc", brtarget26_mm> { + bit isCall = 1; + list<Register> Defs = [RA]; +} +class BC_MMR6_DESC : BC_MMR6_DESC_BASE<"bc", brtarget26_mm>; + +class BC16_MMR6_DESC : MicroMipsInst16<(outs), (ins brtarget10_mm:$offset), + !strconcat("bc16", "\t$offset"), [], + II_BC, FrmI>, + MMR6Arch<"bc16">, MicroMipsR6Inst16 { + let isBranch = 1; + let isTerminator = 1; + let isBarrier = 1; + let hasDelaySlot = 0; + let AdditionalPredicates = [RelocPIC]; + let Defs = [AT]; +} + +class BEQZC_BNEZC_MM16R6_DESC_BASE<string instr_asm> + : CBranchZeroMM<instr_asm, brtarget7_mm, GPRMM16Opnd>, MMR6Arch<instr_asm> { + let isBranch = 1; + let isTerminator = 1; + let hasDelaySlot = 0; + let Defs = [AT]; +} +class BEQZC16_MMR6_DESC : BEQZC_BNEZC_MM16R6_DESC_BASE<"beqzc16">; +class BNEZC16_MMR6_DESC : BEQZC_BNEZC_MM16R6_DESC_BASE<"bnezc16">; + +class SUB_MMR6_DESC : ArithLogicR<"sub", GPR32Opnd>; +class SUBU_MMR6_DESC : ArithLogicR<"subu", GPR32Opnd>; + +class BITSWAP_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> + : MMR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rt"); + list<dag> Pattern = []; +} + +class BITSWAP_MMR6_DESC : BITSWAP_MMR6_DESC_BASE<"bitswap", GPR32Opnd>; + +class BRK_MMR6_DESC : BRK_FT<"break">; + +class CACHE_HINT_MMR6_DESC<string instr_asm, Operand MemOpnd, + RegisterOperand GPROpnd> : MMR6Arch<instr_asm> { + dag OutOperandList = (outs); + dag InOperandList = (ins MemOpnd:$addr, uimm5:$hint); + string AsmString = !strconcat(instr_asm, "\t$hint, $addr"); + list<dag> Pattern = []; + string DecoderMethod = "DecodeCacheOpMM"; +} + +class CACHE_MMR6_DESC : CACHE_HINT_MMR6_DESC<"cache", mem_mm_12, GPR32Opnd>; +class PREF_MMR6_DESC : CACHE_HINT_MMR6_DESC<"pref", mem_mm_12, GPR32Opnd>; + +class PREFE_CACHEE_MMR6_DESC_BASE<string instr_asm, Operand MemOpnd, + RegisterOperand GPROpnd> : + CACHE_HINT_MMR6_DESC<instr_asm, MemOpnd, + GPROpnd> { + string DecoderMethod = "DecodePrefeOpMM"; +} + +class PREFE_MMR6_DESC : PREFE_CACHEE_MMR6_DESC_BASE<"prefe", mem_mm_9, GPR32Opnd>; +class CACHEE_MMR6_DESC : PREFE_CACHEE_MMR6_DESC_BASE<"cachee", mem_mm_9, GPR32Opnd>; + +class LB_LBU_MMR6_DESC_BASE<string instr_asm, Operand MemOpnd, + RegisterOperand GPROpnd> : MMR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rt); + dag InOperandList = (ins MemOpnd:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + string DecoderMethod = "DecodeLoadByte15"; + bit mayLoad = 1; +} +class LB_MMR6_DESC : LB_LBU_MMR6_DESC_BASE<"lb", mem_mm_16, GPR32Opnd>; +class LBU_MMR6_DESC : LB_LBU_MMR6_DESC_BASE<"lbu", mem_mm_16, GPR32Opnd>; + +class LBE_LBUE_MMR6_DESC_BASE<string instr_asm, Operand MemOpnd, + RegisterOperand GPROpnd> + : LB_LBU_MMR6_DESC_BASE<instr_asm, MemOpnd, GPROpnd> { + let DecoderMethod = "DecodeLoadByte9"; +} +class LBE_MMR6_DESC : LBE_LBUE_MMR6_DESC_BASE<"lbe", mem_mm_9, GPR32Opnd>; +class LBUE_MMR6_DESC : LBE_LBUE_MMR6_DESC_BASE<"lbue", mem_mm_9, GPR32Opnd>; + +class CLO_CLZ_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> + : MMR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rt); + dag InOperandList = (ins GPROpnd:$rs); + string AsmString = !strconcat(instr_asm, "\t$rt, $rs"); +} + +class CLO_MMR6_DESC : CLO_CLZ_MMR6_DESC_BASE<"clo", GPR32Opnd>; +class CLZ_MMR6_DESC : CLO_CLZ_MMR6_DESC_BASE<"clz", GPR32Opnd>; + +class EHB_MMR6_DESC : Barrier<"ehb">; +class EI_MMR6_DESC : DEI_FT<"ei", GPR32Opnd>; +class DI_MMR6_DESC : DEI_FT<"di", GPR32Opnd>; + +class ERET_MMR6_DESC : ER_FT<"eret">; +class DERET_MMR6_DESC : ER_FT<"deret">; +class ERETNC_MMR6_DESC : ER_FT<"eretnc">; + +class JALRC16_MMR6_DESC_BASE<string opstr, RegisterOperand RO> + : MicroMipsInst16<(outs), (ins RO:$rs), !strconcat(opstr, "\t$rs"), + [(MipsJmpLink RO:$rs)], II_JALR, FrmR>, + MMR6Arch<opstr>, MicroMipsR6Inst16 { + let isCall = 1; + let hasDelaySlot = 0; + let Defs = [RA]; +} +class JALRC16_MMR6_DESC : JALRC16_MMR6_DESC_BASE<"jalr", GPR32Opnd>; + +class JMP_MMR6_IDX_COMPACT_DESC_BASE<string opstr, DAGOperand opnd, + RegisterOperand GPROpnd> + : MMR6Arch<opstr> { + dag InOperandList = (ins GPROpnd:$rt, opnd:$offset); + string AsmString = !strconcat(opstr, "\t$rt, $offset"); + list<dag> Pattern = []; + bit isTerminator = 1; + bit hasDelaySlot = 0; +} + +class JIALC_MMR6_DESC : JMP_MMR6_IDX_COMPACT_DESC_BASE<"jialc", calloffset16, + GPR32Opnd> { + bit isCall = 1; + list<Register> Defs = [RA]; +} + +class JIC_MMR6_DESC : JMP_MMR6_IDX_COMPACT_DESC_BASE<"jic", jmpoffset16, + GPR32Opnd> { + bit isBarrier = 1; + list<Register> Defs = [AT]; +} + +class JRC16_MMR6_DESC_BASE<string opstr, RegisterOperand RO> + : MicroMipsInst16<(outs), (ins RO:$rs), !strconcat(opstr, "\t$rs"), + [], II_JR, FrmR>, + MMR6Arch<opstr>, MicroMipsR6Inst16 { + let hasDelaySlot = 0; + let isBranch = 1; + let isIndirectBranch = 1; +} +class JRC16_MMR6_DESC : JRC16_MMR6_DESC_BASE<"jrc16", GPR32Opnd>; + +class JRCADDIUSP_MMR6_DESC + : MicroMipsInst16<(outs), (ins uimm5_lsl2:$imm), "jrcaddiusp\t$imm", + [], II_JRADDIUSP, FrmR>, + MMR6Arch<"jrcaddiusp">, MicroMipsR6Inst16 { + let hasDelaySlot = 0; + let isTerminator = 1; + let isBarrier = 1; + let isBranch = 1; + let isIndirectBranch = 1; +} + +class ALIGN_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + Operand ImmOpnd> : MMR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, ImmOpnd:$bp); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt, $bp"); + list<dag> Pattern = []; +} + +class ALIGN_MMR6_DESC : ALIGN_MMR6_DESC_BASE<"align", GPR32Opnd, uimm2>; + +class AUI_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> + : MMR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rt); + dag InOperandList = (ins GPROpnd:$rs, simm16:$imm); + string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $imm"); + list<dag> Pattern = []; +} + +class AUI_MMR6_DESC : AUI_MMR6_DESC_BASE<"aui", GPR32Opnd>; + +class SEB_MMR6_DESC : SignExtInReg<"seb", i8, GPR32Opnd, II_SEB>; +class SEH_MMR6_DESC : SignExtInReg<"seh", i16, GPR32Opnd, II_SEH>; +class ALUIPC_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> + : MMR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rt); + dag InOperandList = (ins simm16:$imm); + string AsmString = !strconcat(instr_asm, "\t$rt, $imm"); + list<dag> Pattern = []; +} + +class ALUIPC_MMR6_DESC : ALUIPC_MMR6_DESC_BASE<"aluipc", GPR32Opnd>; +class AUIPC_MMR6_DESC : ALUIPC_MMR6_DESC_BASE<"auipc", GPR32Opnd>; + +class LSA_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + Operand ImmOpnd> : MMR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, ImmOpnd:$imm2); + string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $rd, $imm2"); + list<dag> Pattern = []; +} + +class LSA_MMR6_DESC : LSA_MMR6_DESC_BASE<"lsa", GPR32Opnd, uimm2_plus1>; + +class PCREL_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + Operand ImmOpnd> : MMR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rt); + dag InOperandList = (ins ImmOpnd:$imm); + string AsmString = !strconcat(instr_asm, "\t$rt, $imm"); + list<dag> Pattern = []; +} + +class ADDIUPC_MMR6_DESC : PCREL_MMR6_DESC_BASE<"addiupc", GPR32Opnd, simm19_lsl2>; +class LWPC_MMR6_DESC: PCREL_MMR6_DESC_BASE<"lwpc", GPR32Opnd, simm19_lsl2>; + +class SELEQNE_Z_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> + : MMR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt"); + list<dag> Pattern = []; +} + +class SELEQZ_MMR6_DESC : SELEQNE_Z_MMR6_DESC_BASE<"seleqz", GPR32Opnd>; +class SELNEZ_MMR6_DESC : SELEQNE_Z_MMR6_DESC_BASE<"selnez", GPR32Opnd>; +class PAUSE_MMR6_DESC : Barrier<"pause">; +class RDHWR_MMR6_DESC : MMR6Arch<"rdhwr">, MipsR6Inst { + dag OutOperandList = (outs GPR32Opnd:$rt); + dag InOperandList = (ins HWRegsOpnd:$rs, uimm3:$sel); + string AsmString = !strconcat("rdhwr", "\t$rt, $rs, $sel"); + list<dag> Pattern = []; + InstrItinClass Itinerary = II_RDHWR; + Format Form = FrmR; +} + +class WAIT_MMR6_DESC : WaitMM<"wait">; +class SSNOP_MMR6_DESC : Barrier<"ssnop">; +class SLL_MMR6_DESC : shift_rotate_imm<"sll", uimm5, GPR32Opnd, II_SLL>; +class DIV_MMR6_DESC : ArithLogicR<"div", GPR32Opnd>; +class DIVU_MMR6_DESC : ArithLogicR<"divu", GPR32Opnd>; +class MOD_MMR6_DESC : ArithLogicR<"mod", GPR32Opnd>; +class MODU_MMR6_DESC : ArithLogicR<"modu", GPR32Opnd>; +class AND_MMR6_DESC : ArithLogicR<"and", GPR32Opnd>; +class ANDI_MMR6_DESC : ArithLogicI<"andi", simm16, GPR32Opnd>; +class NOR_MMR6_DESC : ArithLogicR<"nor", GPR32Opnd>; +class OR_MMR6_DESC : ArithLogicR<"or", GPR32Opnd>; +class ORI_MMR6_DESC : ArithLogicI<"ori", simm16, GPR32Opnd>; +class XOR_MMR6_DESC : ArithLogicR<"xor", GPR32Opnd>; +class XORI_MMR6_DESC : ArithLogicI<"xori", simm16, GPR32Opnd>; + +class SWE_MMR6_DESC_BASE<string opstr, DAGOperand RO, DAGOperand MO, + SDPatternOperator OpNode = null_frag, + InstrItinClass Itin = NoItinerary, + ComplexPattern Addr = addr> : + InstSE<(outs), (ins RO:$rt, MO:$addr), !strconcat(opstr, "\t$rt, $addr"), + [(OpNode RO:$rt, Addr:$addr)], Itin, FrmI, opstr> { + let DecoderMethod = "DecodeMem"; + let mayStore = 1; +} +class SW_MMR6_DESC : Store<"sw", GPR32Opnd>; +class SWE_MMR6_DESC : SWE_MMR6_DESC_BASE<"swe", GPR32Opnd, mem_simm9>; + +class WRPGPR_WSBH_MMR6_DESC_BASE<string instr_asm, RegisterOperand RO> + : MMR6Arch<instr_asm> { + dag InOperandList = (ins RO:$rs); + dag OutOperandList = (outs RO:$rt); + string AsmString = !strconcat(instr_asm, "\t$rt, $rs"); + list<dag> Pattern = []; + Format f = FrmR; + string BaseOpcode = instr_asm; + bit hasSideEffects = 0; +} +class WRPGPR_MMR6_DESC : WRPGPR_WSBH_MMR6_DESC_BASE<"wrpgpr", GPR32Opnd>; +class WSBH_MMR6_DESC : WRPGPR_WSBH_MMR6_DESC_BASE<"wsbh", GPR32Opnd>; + +/// Floating Point Instructions +class FARITH_MMR6_DESC_BASE<string instr_asm, RegisterOperand RC, + InstrItinClass Itin, bit isComm, + SDPatternOperator OpNode = null_frag> : HARDFLOAT { + dag OutOperandList = (outs RC:$fd); + dag InOperandList = (ins RC:$ft, RC:$fs); + string AsmString = !strconcat(instr_asm, "\t$fd, $fs, $ft"); + list<dag> Pattern = [(set RC:$fd, (OpNode RC:$fs, RC:$ft))]; + InstrItinClass Itinerary = Itin; + bit isCommutable = isComm; +} +class FADD_S_MMR6_DESC + : FARITH_MMR6_DESC_BASE<"add.s", FGR32Opnd, II_ADD_S, 1, fadd>; +class FADD_D_MMR6_DESC + : FARITH_MMR6_DESC_BASE<"add.d", AFGR64Opnd, II_ADD_D, 1, fadd>; +class FSUB_S_MMR6_DESC + : FARITH_MMR6_DESC_BASE<"sub.s", FGR32Opnd, II_SUB_S, 0, fsub>; +class FSUB_D_MMR6_DESC + : FARITH_MMR6_DESC_BASE<"sub.d", AFGR64Opnd, II_SUB_D, 0, fsub>; +class FMUL_S_MMR6_DESC + : FARITH_MMR6_DESC_BASE<"mul.s", FGR32Opnd, II_MUL_S, 1, fmul>; +class FMUL_D_MMR6_DESC + : FARITH_MMR6_DESC_BASE<"mul.d", AFGR64Opnd, II_MUL_D, 1, fmul>; +class FDIV_S_MMR6_DESC + : FARITH_MMR6_DESC_BASE<"div.s", FGR32Opnd, II_DIV_S, 0, fdiv>; +class FDIV_D_MMR6_DESC + : FARITH_MMR6_DESC_BASE<"div.d", AFGR64Opnd, II_DIV_D, 0, fdiv>; +class MADDF_S_MMR6_DESC : COP1_4R_DESC_BASE<"maddf.s", FGR32Opnd>, HARDFLOAT; +class MADDF_D_MMR6_DESC : COP1_4R_DESC_BASE<"maddf.d", FGR64Opnd>, HARDFLOAT; +class MSUBF_S_MMR6_DESC : COP1_4R_DESC_BASE<"msubf.s", FGR32Opnd>, HARDFLOAT; +class MSUBF_D_MMR6_DESC : COP1_4R_DESC_BASE<"msubf.d", FGR64Opnd>, HARDFLOAT; + +class FMOV_FNEG_MMR6_DESC_BASE<string instr_asm, RegisterOperand DstRC, + RegisterOperand SrcRC, InstrItinClass Itin, + SDPatternOperator OpNode = null_frag> + : HARDFLOAT, NeverHasSideEffects { + dag OutOperandList = (outs DstRC:$ft); + dag InOperandList = (ins SrcRC:$fs); + string AsmString = !strconcat(instr_asm, "\t$ft, $fs"); + list<dag> Pattern = [(set DstRC:$ft, (OpNode SrcRC:$fs))]; + InstrItinClass Itinerary = Itin; + Format Form = FrmFR; +} +class FMOV_S_MMR6_DESC + : FMOV_FNEG_MMR6_DESC_BASE<"mov.s", FGR32Opnd, FGR32Opnd, II_MOV_S>; +class FMOV_D_MMR6_DESC + : FMOV_FNEG_MMR6_DESC_BASE<"mov.d", AFGR64Opnd, AFGR64Opnd, II_MOV_D>; +class FNEG_S_MMR6_DESC + : FMOV_FNEG_MMR6_DESC_BASE<"neg.s", FGR32Opnd, FGR32Opnd, II_NEG, fneg>; +class FNEG_D_MMR6_DESC + : FMOV_FNEG_MMR6_DESC_BASE<"neg.d", AFGR64Opnd, AFGR64Opnd, II_NEG, fneg>; + +class MAX_S_MMR6_DESC : MAX_MIN_DESC_BASE<"max.s", FGR32Opnd>, HARDFLOAT; +class MAX_D_MMR6_DESC : MAX_MIN_DESC_BASE<"max.d", FGR64Opnd>, HARDFLOAT; +class MIN_S_MMR6_DESC : MAX_MIN_DESC_BASE<"min.s", FGR32Opnd>, HARDFLOAT; +class MIN_D_MMR6_DESC : MAX_MIN_DESC_BASE<"min.d", FGR64Opnd>, HARDFLOAT; + +class MAXA_S_MMR6_DESC : MAX_MIN_DESC_BASE<"maxa.s", FGR32Opnd>, HARDFLOAT; +class MAXA_D_MMR6_DESC : MAX_MIN_DESC_BASE<"maxa.d", FGR64Opnd>, HARDFLOAT; +class MINA_S_MMR6_DESC : MAX_MIN_DESC_BASE<"mina.s", FGR32Opnd>, HARDFLOAT; +class MINA_D_MMR6_DESC : MAX_MIN_DESC_BASE<"mina.d", FGR64Opnd>, HARDFLOAT; + +class CVT_MMR6_DESC_BASE< + string instr_asm, RegisterOperand DstRC, RegisterOperand SrcRC, + InstrItinClass Itin, SDPatternOperator OpNode = null_frag> + : HARDFLOAT, NeverHasSideEffects { + dag OutOperandList = (outs DstRC:$ft); + dag InOperandList = (ins SrcRC:$fs); + string AsmString = !strconcat(instr_asm, "\t$ft, $fs"); + list<dag> Pattern = [(set DstRC:$ft, (OpNode SrcRC:$fs))]; + InstrItinClass Itinerary = Itin; + Format Form = FrmFR; +} + +class CVT_L_S_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.l.s", FGR64Opnd, FGR32Opnd, + II_CVT>; +class CVT_L_D_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.l.d", FGR64Opnd, FGR64Opnd, + II_CVT>; +class CVT_W_S_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.w.s", FGR32Opnd, FGR32Opnd, + II_CVT>; +class CVT_W_D_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.w.d", FGR32Opnd, AFGR64Opnd, + II_CVT>; +class CVT_D_S_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.d.s", FGR32Opnd, AFGR64Opnd, + II_CVT>; +class CVT_D_W_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.d.w", FGR32Opnd, AFGR64Opnd, + II_CVT>; +class CVT_D_L_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.d.l", FGR64Opnd, FGR64Opnd, + II_CVT>, FGR_64; +class CVT_S_D_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.s.d", AFGR64Opnd, FGR32Opnd, + II_CVT>; +class CVT_S_W_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.s.w", FGR32Opnd, FGR32Opnd, + II_CVT>; +class CVT_S_L_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.s.l", FGR64Opnd, FGR32Opnd, + II_CVT>, FGR_64; + +multiclass CMP_CC_MMR6<bits<6> format, string Typestr, + RegisterOperand FGROpnd> { + def CMP_AF_#NAME : POOL32F_CMP_FM< + !strconcat("cmp.af.", Typestr), format, FIELD_CMP_COND_AF>, + CMP_CONDN_DESC_BASE<"af", Typestr, FGROpnd>, HARDFLOAT, R6MMR6Rel, + ISA_MICROMIPS32R6; + def CMP_UN_#NAME : POOL32F_CMP_FM< + !strconcat("cmp.un.", Typestr), format, FIELD_CMP_COND_UN>, + CMP_CONDN_DESC_BASE<"un", Typestr, FGROpnd>, HARDFLOAT, R6MMR6Rel, + ISA_MICROMIPS32R6; + def CMP_EQ_#NAME : POOL32F_CMP_FM< + !strconcat("cmp.eq.", Typestr), format, FIELD_CMP_COND_EQ>, + CMP_CONDN_DESC_BASE<"eq", Typestr, FGROpnd>, HARDFLOAT, R6MMR6Rel, + ISA_MICROMIPS32R6; + def CMP_UEQ_#NAME : POOL32F_CMP_FM< + !strconcat("cmp.ueq.", Typestr), format, FIELD_CMP_COND_UEQ>, + CMP_CONDN_DESC_BASE<"ueq", Typestr, FGROpnd>, HARDFLOAT, R6MMR6Rel, + ISA_MICROMIPS32R6; + def CMP_LT_#NAME : POOL32F_CMP_FM< + !strconcat("cmp.lt.", Typestr), format, FIELD_CMP_COND_LT>, + CMP_CONDN_DESC_BASE<"lt", Typestr, FGROpnd>, HARDFLOAT, R6MMR6Rel, + ISA_MICROMIPS32R6; + def CMP_ULT_#NAME : POOL32F_CMP_FM< + !strconcat("cmp.ult.", Typestr), format, FIELD_CMP_COND_ULT>, + CMP_CONDN_DESC_BASE<"ult", Typestr, FGROpnd>, HARDFLOAT, R6MMR6Rel, + ISA_MICROMIPS32R6; + def CMP_LE_#NAME : POOL32F_CMP_FM< + !strconcat("cmp.le.", Typestr), format, FIELD_CMP_COND_LE>, + CMP_CONDN_DESC_BASE<"le", Typestr, FGROpnd>, HARDFLOAT, R6MMR6Rel, + ISA_MICROMIPS32R6; + def CMP_ULE_#NAME : POOL32F_CMP_FM< + !strconcat("cmp.ule.", Typestr), format, FIELD_CMP_COND_ULE>, + CMP_CONDN_DESC_BASE<"ule", Typestr, FGROpnd>, HARDFLOAT, R6MMR6Rel, + ISA_MICROMIPS32R6; + def CMP_SAF_#NAME : POOL32F_CMP_FM< + !strconcat("cmp.saf.", Typestr), format, FIELD_CMP_COND_SAF>, + CMP_CONDN_DESC_BASE<"saf", Typestr, FGROpnd>, HARDFLOAT, R6MMR6Rel, + ISA_MICROMIPS32R6; + def CMP_SUN_#NAME : POOL32F_CMP_FM< + !strconcat("cmp.sun.", Typestr), format, FIELD_CMP_COND_SUN>, + CMP_CONDN_DESC_BASE<"sun", Typestr, FGROpnd>, HARDFLOAT, R6MMR6Rel, + ISA_MICROMIPS32R6; + def CMP_SEQ_#NAME : POOL32F_CMP_FM< + !strconcat("cmp.seq.", Typestr), format, FIELD_CMP_COND_SEQ>, + CMP_CONDN_DESC_BASE<"seq", Typestr, FGROpnd>, HARDFLOAT, R6MMR6Rel, + ISA_MICROMIPS32R6; + def CMP_SUEQ_#NAME : POOL32F_CMP_FM< + !strconcat("cmp.sueq.", Typestr), format, FIELD_CMP_COND_SUEQ>, + CMP_CONDN_DESC_BASE<"sueq", Typestr, FGROpnd>, HARDFLOAT, R6MMR6Rel, + ISA_MICROMIPS32R6; + def CMP_SLT_#NAME : POOL32F_CMP_FM< + !strconcat("cmp.slt.", Typestr), format, FIELD_CMP_COND_SLT>, + CMP_CONDN_DESC_BASE<"slt", Typestr, FGROpnd>, HARDFLOAT, R6MMR6Rel, + ISA_MICROMIPS32R6; + def CMP_SULT_#NAME : POOL32F_CMP_FM< + !strconcat("cmp.sult.", Typestr), format, FIELD_CMP_COND_SULT>, + CMP_CONDN_DESC_BASE<"sult", Typestr, FGROpnd>, HARDFLOAT, R6MMR6Rel, + ISA_MICROMIPS32R6; + def CMP_SLE_#NAME : POOL32F_CMP_FM< + !strconcat("cmp.sle.", Typestr), format, FIELD_CMP_COND_SLE>, + CMP_CONDN_DESC_BASE<"sle", Typestr, FGROpnd>, HARDFLOAT, R6MMR6Rel, + ISA_MICROMIPS32R6; + def CMP_SULE_#NAME : POOL32F_CMP_FM< + !strconcat("cmp.sule.", Typestr), format, FIELD_CMP_COND_SULE>, + CMP_CONDN_DESC_BASE<"sule", Typestr, FGROpnd>, HARDFLOAT, R6MMR6Rel, + ISA_MICROMIPS32R6; +} + +class ABSS_FT_MMR6_DESC_BASE<string instr_asm, RegisterOperand DstRC, + RegisterOperand SrcRC, InstrItinClass Itin, + SDPatternOperator OpNode = null_frag> + : HARDFLOAT, NeverHasSideEffects { + dag OutOperandList = (outs DstRC:$ft); + dag InOperandList = (ins SrcRC:$fs); + string AsmString = !strconcat(instr_asm, "\t$ft, $fs"); + list<dag> Pattern = [(set DstRC:$ft, (OpNode SrcRC:$fs))]; + InstrItinClass Itinerary = Itin; + Format Form = FrmFR; + list<Predicate> EncodingPredicates = [HasStdEnc]; +} + +class ABS_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"abs.s", FGR32Opnd, FGR32Opnd, + II_ABS, fabs>; +class ABS_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"abs.d", AFGR64Opnd, AFGR64Opnd, + II_ABS, fabs>; +class FLOOR_L_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"floor.l.s", FGR64Opnd, + FGR32Opnd, II_FLOOR>; +class FLOOR_L_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"floor.l.d", FGR64Opnd, + FGR64Opnd, II_FLOOR>; +class FLOOR_W_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"floor.w.s", FGR32Opnd, + FGR32Opnd, II_FLOOR>; +class FLOOR_W_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"floor.w.d", FGR32Opnd, + AFGR64Opnd, II_FLOOR>; +class CEIL_L_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"ceil.l.s", FGR64Opnd, + FGR32Opnd, II_CEIL>; +class CEIL_L_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"ceil.l.d", FGR64Opnd, + FGR64Opnd, II_CEIL>; +class CEIL_W_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"ceil.w.s", FGR32Opnd, + FGR32Opnd, II_CEIL>; +class CEIL_W_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"ceil.w.d", FGR32Opnd, + AFGR64Opnd, II_CEIL>; +class TRUNC_L_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"trunc.l.s", FGR64Opnd, + FGR32Opnd, II_TRUNC>; +class TRUNC_L_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"trunc.l.d", FGR64Opnd, + FGR64Opnd, II_TRUNC>; +class TRUNC_W_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"trunc.w.s", FGR32Opnd, + FGR32Opnd, II_TRUNC>; +class TRUNC_W_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"trunc.w.d", FGR32Opnd, + AFGR64Opnd, II_TRUNC>; +class SQRT_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"sqrt.s", FGR32Opnd, FGR32Opnd, + II_SQRT_S, fsqrt>; +class SQRT_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"sqrt.d", AFGR64Opnd, AFGR64Opnd, + II_SQRT_D, fsqrt>; +class RSQRT_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"rsqrt.s", FGR32Opnd, + FGR32Opnd, II_TRUNC>; +class RSQRT_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"rsqrt.d", FGR32Opnd, + AFGR64Opnd, II_TRUNC>; +class RECIP_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"recip.s", FGR32Opnd, + FGR32Opnd, II_ROUND>; +class RECIP_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"recip.d", FGR32Opnd, FGR32Opnd, + II_ROUND>; +class ROUND_L_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"round.l.s", FGR64Opnd, + FGR32Opnd, II_ROUND>; +class ROUND_L_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"round.l.d", FGR64Opnd, + FGR64Opnd, II_ROUND>; +class ROUND_W_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"round.w.s", FGR32Opnd, + FGR32Opnd, II_ROUND>; +class ROUND_W_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"round.w.d", FGR64Opnd, + FGR64Opnd, II_ROUND>; + +class SEL_S_MMR6_DESC : COP1_SEL_DESC_BASE<"sel.s", FGR32Opnd>; +class SEL_D_MMR6_DESC : COP1_SEL_DESC_BASE<"sel.d", FGR64Opnd> { + // We must insert a SUBREG_TO_REG around $fd_in + bit usesCustomInserter = 1; +} + +class SELEQZ_S_MMR6_DESC : SELEQNEZ_DESC_BASE<"seleqz.s", FGR32Opnd>; +class SELEQZ_D_MMR6_DESC : SELEQNEZ_DESC_BASE<"seleqz.d", FGR64Opnd>; +class SELENZ_S_MMR6_DESC : SELEQNEZ_DESC_BASE<"selnez.s", FGR32Opnd>; +class SELENZ_D_MMR6_DESC : SELEQNEZ_DESC_BASE<"selnez.d", FGR64Opnd>; +class RINT_S_MMR6_DESC : CLASS_RINT_DESC_BASE<"rint.s", FGR32Opnd>; +class RINT_D_MMR6_DESC : CLASS_RINT_DESC_BASE<"rint.d", FGR64Opnd>; +class CLASS_S_MMR6_DESC : CLASS_RINT_DESC_BASE<"class.s", FGR32Opnd>; +class CLASS_D_MMR6_DESC : CLASS_RINT_DESC_BASE<"class.d", FGR64Opnd>; + +class STORE_MMR6_DESC_BASE<string opstr, DAGOperand RO> + : Store<opstr, RO>, MMR6Arch<opstr> { + let DecoderMethod = "DecodeMemMMImm16"; +} +class SB_MMR6_DESC : STORE_MMR6_DESC_BASE<"sb", GPR32Opnd>; + +class STORE_EVA_MMR6_DESC_BASE<string instr_asm, RegisterOperand RO> + : MMR6Arch<instr_asm>, MipsR6Inst { + dag OutOperandList = (outs); + dag InOperandList = (ins RO:$rt, mem_mm_9:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + string DecoderMethod = "DecodeStoreEvaOpMM"; + bit mayStore = 1; +} +class SBE_MMR6_DESC : STORE_EVA_MMR6_DESC_BASE<"sbe", GPR32Opnd>; +class SCE_MMR6_DESC : STORE_EVA_MMR6_DESC_BASE<"sce", GPR32Opnd>; +class SH_MMR6_DESC : STORE_MMR6_DESC_BASE<"sh", GPR32Opnd>; +class SHE_MMR6_DESC : STORE_EVA_MMR6_DESC_BASE<"she", GPR32Opnd>; +class LOAD_WORD_EVA_MMR6_DESC_BASE<string instr_asm, RegisterOperand RO> : + MMR6Arch<instr_asm>, MipsR6Inst { + dag OutOperandList = (outs RO:$rt); + dag InOperandList = (ins mem_mm_12:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + string DecoderMethod = "DecodeMemMMImm9"; + bit mayLoad = 1; +} +class LLE_MMR6_DESC : LOAD_WORD_EVA_MMR6_DESC_BASE<"lle", GPR32Opnd>; +class LWE_MMR6_DESC : LOAD_WORD_EVA_MMR6_DESC_BASE<"lwe", GPR32Opnd>; +class ADDU16_MMR6_DESC : ArithRMM16<"addu16", GPRMM16Opnd, 1, II_ADDU, add>, + MMR6Arch<"addu16">; +class AND16_MMR6_DESC : LogicRMM16<"and16", GPRMM16Opnd, II_AND, and>, + MMR6Arch<"and16">; +class ANDI16_MMR6_DESC : AndImmMM16<"andi16", GPRMM16Opnd, II_AND>, + MMR6Arch<"andi16">; +class NOT16_MMR6_DESC : NotMM16<"not16", GPRMM16Opnd>, MMR6Arch<"not16">; +class OR16_MMR6_DESC : LogicRMM16<"or16", GPRMM16Opnd, II_OR, or>, + MMR6Arch<"or16">; +class SLL16_MMR6_DESC : ShiftIMM16<"sll16", uimm3_shift, GPRMM16Opnd, II_SLL>, + MMR6Arch<"sll16">; +class SRL16_MMR6_DESC : ShiftIMM16<"srl16", uimm3_shift, GPRMM16Opnd, II_SRL>, + MMR6Arch<"srl16">; +class BREAK16_MMR6_DESC : BrkSdbbp16MM<"break16">, MMR6Arch<"srl16">, + MicroMipsR6Inst16; +class LI16_MMR6_DESC : LoadImmMM16<"li16", li_simm7, GPRMM16Opnd>, + MMR6Arch<"srl16">, MicroMipsR6Inst16, IsAsCheapAsAMove; +class MOVE16_MMR6_DESC : MoveMM16<"move16", GPR32Opnd>, MMR6Arch<"srl16">, + MicroMipsR6Inst16; +class SDBBP16_MMR6_DESC : BrkSdbbp16MM<"sdbbp16">, MMR6Arch<"sdbbp16">, + MicroMipsR6Inst16; +class SUBU16_MMR6_DESC : ArithRMM16<"subu16", GPRMM16Opnd, 0, II_SUBU, sub>, + MMR6Arch<"sdbbp16">, MicroMipsR6Inst16; +class XOR16_MMR6_DESC : LogicRMM16<"xor16", GPRMM16Opnd, II_XOR, xor>, + MMR6Arch<"sdbbp16">, MicroMipsR6Inst16; + +class LW_MMR6_DESC : MMR6Arch<"lw">, MipsR6Inst { + dag OutOperandList = (outs GPR32Opnd:$rt); + dag InOperandList = (ins mem:$addr); + string AsmString = "lw\t$rt, $addr"; + let DecoderMethod = "DecodeMemMMImm16"; + let canFoldAsLoad = 1; + let mayLoad = 1; + list<dag> Pattern = [(set GPR32Opnd:$rt, (load addrDefault:$addr))]; + InstrItinClass Itinerary = II_LW; +} + +class LUI_MMR6_DESC : IsAsCheapAsAMove, MMR6Arch<"lui">, MipsR6Inst{ + dag OutOperandList = (outs GPR32Opnd:$rt); + dag InOperandList = (ins uimm16:$imm16); + string AsmString = "lui\t$rt, $imm16"; + list<dag> Pattern = []; + bit hasSideEffects = 0; + bit isReMaterializable = 1; + InstrItinClass Itinerary = II_LUI; + Format Form = FrmI; +} + +class SYNC_MMR6_DESC : MMR6Arch<"sync">, MipsR6Inst { + dag OutOperandList = (outs); + dag InOperandList = (ins i32imm:$stype); + string AsmString = !strconcat("sync", "\t$stype"); + list<dag> Pattern = [(MipsSync imm:$stype)]; + InstrItinClass Itinerary = NoItinerary; + bit HasSideEffects = 1; +} + +class SYNCI_MMR6_DESC : SYNCI_FT<"synci"> { + let DecoderMethod = "DecodeSynciR6"; +} + +class RDPGPR_MMR6_DESC : MMR6Arch<"rdpgpr">, MipsR6Inst { + dag OutOperandList = (outs GPR32Opnd:$rt); + dag InOperandList = (ins GPR32Opnd:$rd); + string AsmString = !strconcat("rdpgpr", "\t$rt, $rd"); +} + +class SDBBP_MMR6_DESC : MipsR6Inst { + dag OutOperandList = (outs); + dag InOperandList = (ins uimm20:$code_); + string AsmString = !strconcat("sdbbp", "\t$code_"); + list<dag> Pattern = []; +} + +class LWM16_MMR6_DESC + : MicroMipsInst16<(outs reglist16:$rt), (ins mem_mm_4sp:$addr), + !strconcat("lwm16", "\t$rt, $addr"), [], + NoItinerary, FrmI>, + MMR6Arch<"lwm16">, MicroMipsR6Inst16 { + let DecoderMethod = "DecodeMemMMReglistImm4Lsl2"; + let mayLoad = 1; + InstrItinClass Itin = NoItinerary; + ComplexPattern Addr = addr; +} + +class SWM16_MMR6_DESC + : MicroMipsInst16<(outs), (ins reglist16:$rt, mem_mm_4sp:$addr), + !strconcat("swm16", "\t$rt, $addr"), [], + NoItinerary, FrmI>, + MMR6Arch<"swm16">, MicroMipsR6Inst16 { + let DecoderMethod = "DecodeMemMMReglistImm4Lsl2"; + let mayStore = 1; + InstrItinClass Itin = NoItinerary; + ComplexPattern Addr = addr; +} + +class SB16_MMR6_DESC_BASE<string opstr, DAGOperand RTOpnd, DAGOperand RO, + SDPatternOperator OpNode, InstrItinClass Itin, + Operand MemOpnd> + : MicroMipsInst16<(outs), (ins RTOpnd:$rt, MemOpnd:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI>, + MMR6Arch<opstr>, MicroMipsR6Inst16 { + let DecoderMethod = "DecodeMemMMImm4"; + let mayStore = 1; +} +class SB16_MMR6_DESC : SB16_MMR6_DESC_BASE<"sb16", GPRMM16OpndZero, GPRMM16Opnd, + truncstorei8, II_SB, mem_mm_4>; +class SH16_MMR6_DESC : SB16_MMR6_DESC_BASE<"sh16", GPRMM16OpndZero, GPRMM16Opnd, + truncstorei16, II_SH, mem_mm_4_lsl1>; +class SW16_MMR6_DESC : SB16_MMR6_DESC_BASE<"sw16", GPRMM16OpndZero, GPRMM16Opnd, + store, II_SW, mem_mm_4_lsl2>; + +class SWSP_MMR6_DESC + : MicroMipsInst16<(outs), (ins GPR32Opnd:$rt, mem_mm_sp_imm5_lsl2:$offset), + !strconcat("sw", "\t$rt, $offset"), [], II_SW, FrmI>, + MMR6Arch<"sw">, MicroMipsR6Inst16 { + let DecoderMethod = "DecodeMemMMSPImm5Lsl2"; + let mayStore = 1; +} + +//===----------------------------------------------------------------------===// +// +// Instruction Definitions +// +//===----------------------------------------------------------------------===// + +let DecoderNamespace = "MicroMipsR6" in { +def ADD_MMR6 : StdMMR6Rel, ADD_MMR6_DESC, ADD_MMR6_ENC, ISA_MICROMIPS32R6; +def ADDIU_MMR6 : StdMMR6Rel, ADDIU_MMR6_DESC, ADDIU_MMR6_ENC, ISA_MICROMIPS32R6; +def ADDU_MMR6 : StdMMR6Rel, ADDU_MMR6_DESC, ADDU_MMR6_ENC, ISA_MICROMIPS32R6; +def ADDIUPC_MMR6 : R6MMR6Rel, ADDIUPC_MMR6_ENC, ADDIUPC_MMR6_DESC, + ISA_MICROMIPS32R6; +def ALUIPC_MMR6 : R6MMR6Rel, ALUIPC_MMR6_ENC, ALUIPC_MMR6_DESC, + ISA_MICROMIPS32R6; +def AND_MMR6 : StdMMR6Rel, AND_MMR6_DESC, AND_MMR6_ENC, ISA_MICROMIPS32R6; +def ANDI_MMR6 : StdMMR6Rel, ANDI_MMR6_DESC, ANDI_MMR6_ENC, ISA_MICROMIPS32R6; +def AUIPC_MMR6 : R6MMR6Rel, AUIPC_MMR6_ENC, AUIPC_MMR6_DESC, ISA_MICROMIPS32R6; +def ALIGN_MMR6 : R6MMR6Rel, ALIGN_MMR6_ENC, ALIGN_MMR6_DESC, ISA_MICROMIPS32R6; +def AUI_MMR6 : R6MMR6Rel, AUI_MMR6_ENC, AUI_MMR6_DESC, ISA_MICROMIPS32R6; +def BALC_MMR6 : R6MMR6Rel, BALC_MMR6_ENC, BALC_MMR6_DESC, ISA_MICROMIPS32R6; +def BC_MMR6 : R6MMR6Rel, BC_MMR6_ENC, BC_MMR6_DESC, ISA_MICROMIPS32R6; +def BC16_MMR6 : StdMMR6Rel, BC16_MMR6_DESC, BC16_MMR6_ENC, ISA_MICROMIPS32R6; +def BEQZC16_MMR6 : StdMMR6Rel, BEQZC16_MMR6_DESC, BEQZC16_MMR6_ENC, + ISA_MICROMIPS32R6; +def BNEZC16_MMR6 : StdMMR6Rel, BNEZC16_MMR6_DESC, BNEZC16_MMR6_ENC, + ISA_MICROMIPS32R6; +def BITSWAP_MMR6 : R6MMR6Rel, BITSWAP_MMR6_ENC, BITSWAP_MMR6_DESC, + ISA_MICROMIPS32R6; +def BEQZALC_MMR6 : R6MMR6Rel, BEQZALC_MMR6_ENC, BEQZALC_MMR6_DESC, + ISA_MICROMIPS32R6; +def BGEZALC_MMR6 : R6MMR6Rel, BGEZALC_MMR6_ENC, BGEZALC_MMR6_DESC, + ISA_MICROMIPS32R6; +def BGTZALC_MMR6 : R6MMR6Rel, BGTZALC_MMR6_ENC, BGTZALC_MMR6_DESC, + ISA_MICROMIPS32R6; +def BLEZALC_MMR6 : R6MMR6Rel, BLEZALC_MMR6_ENC, BLEZALC_MMR6_DESC, + ISA_MICROMIPS32R6; +def BLTZALC_MMR6 : R6MMR6Rel, BLTZALC_MMR6_ENC, BLTZALC_MMR6_DESC, + ISA_MICROMIPS32R6; +def BNEZALC_MMR6 : R6MMR6Rel, BNEZALC_MMR6_ENC, BNEZALC_MMR6_DESC, + ISA_MICROMIPS32R6; +def BREAK_MMR6 : StdMMR6Rel, BRK_MMR6_DESC, BRK_MMR6_ENC, ISA_MICROMIPS32R6; +def CACHE_MMR6 : R6MMR6Rel, CACHE_MMR6_ENC, CACHE_MMR6_DESC, ISA_MICROMIPS32R6; +def CLO_MMR6 : R6MMR6Rel, CLO_MMR6_ENC, CLO_MMR6_DESC, ISA_MICROMIPS32R6; +def CLZ_MMR6 : R6MMR6Rel, CLZ_MMR6_ENC, CLZ_MMR6_DESC, ISA_MICROMIPS32R6; +def DIV_MMR6 : R6MMR6Rel, DIV_MMR6_DESC, DIV_MMR6_ENC, ISA_MICROMIPS32R6; +def DIVU_MMR6 : R6MMR6Rel, DIVU_MMR6_DESC, DIVU_MMR6_ENC, ISA_MICROMIPS32R6; +def EHB_MMR6 : StdMMR6Rel, EHB_MMR6_DESC, EHB_MMR6_ENC, ISA_MICROMIPS32R6; +def EI_MMR6 : StdMMR6Rel, EI_MMR6_DESC, EI_MMR6_ENC, ISA_MICROMIPS32R6; +def DI_MMR6 : StdMMR6Rel, DI_MMR6_DESC, DI_MMR6_ENC, ISA_MICROMIPS32R6; +def ERET_MMR6 : StdMMR6Rel, ERET_MMR6_DESC, ERET_MMR6_ENC, ISA_MICROMIPS32R6; +def DERET_MMR6 : StdMMR6Rel, DERET_MMR6_DESC, DERET_MMR6_ENC, ISA_MICROMIPS32R6; +def ERETNC_MMR6 : R6MMR6Rel, ERETNC_MMR6_DESC, ERETNC_MMR6_ENC, + ISA_MICROMIPS32R6; +def JALRC16_MMR6 : R6MMR6Rel, JALRC16_MMR6_DESC, JALRC16_MMR6_ENC, + ISA_MICROMIPS32R6; +def JIALC_MMR6 : R6MMR6Rel, JIALC_MMR6_ENC, JIALC_MMR6_DESC, ISA_MICROMIPS32R6; +def JIC_MMR6 : R6MMR6Rel, JIC_MMR6_ENC, JIC_MMR6_DESC, ISA_MICROMIPS32R6; +def JRC16_MMR6 : R6MMR6Rel, JRC16_MMR6_DESC, JRC16_MMR6_ENC, ISA_MICROMIPS32R6; +def JRCADDIUSP_MMR6 : R6MMR6Rel, JRCADDIUSP_MMR6_DESC, JRCADDIUSP_MMR6_ENC, + ISA_MICROMIPS32R6; +def LSA_MMR6 : R6MMR6Rel, LSA_MMR6_ENC, LSA_MMR6_DESC, ISA_MICROMIPS32R6; +def LWPC_MMR6 : R6MMR6Rel, LWPC_MMR6_ENC, LWPC_MMR6_DESC, ISA_MICROMIPS32R6; +def LWM16_MMR6 : StdMMR6Rel, LWM16_MMR6_DESC, LWM16_MMR6_ENC, ISA_MICROMIPS32R6; +def MOD_MMR6 : R6MMR6Rel, MOD_MMR6_DESC, MOD_MMR6_ENC, ISA_MICROMIPS32R6; +def MODU_MMR6 : R6MMR6Rel, MODU_MMR6_DESC, MODU_MMR6_ENC, ISA_MICROMIPS32R6; +def MUL_MMR6 : R6MMR6Rel, MUL_MMR6_DESC, MUL_MMR6_ENC, ISA_MICROMIPS32R6; +def MUH_MMR6 : R6MMR6Rel, MUH_MMR6_DESC, MUH_MMR6_ENC, ISA_MICROMIPS32R6; +def MULU_MMR6 : R6MMR6Rel, MULU_MMR6_DESC, MULU_MMR6_ENC, ISA_MICROMIPS32R6; +def MUHU_MMR6 : R6MMR6Rel, MUHU_MMR6_DESC, MUHU_MMR6_ENC, ISA_MICROMIPS32R6; +def NOR_MMR6 : StdMMR6Rel, NOR_MMR6_DESC, NOR_MMR6_ENC, ISA_MICROMIPS32R6; +def OR_MMR6 : StdMMR6Rel, OR_MMR6_DESC, OR_MMR6_ENC, ISA_MICROMIPS32R6; +def ORI_MMR6 : StdMMR6Rel, ORI_MMR6_DESC, ORI_MMR6_ENC, ISA_MICROMIPS32R6; +def PREF_MMR6 : R6MMR6Rel, PREF_MMR6_ENC, PREF_MMR6_DESC, ISA_MICROMIPS32R6; +def SB16_MMR6 : StdMMR6Rel, SB16_MMR6_DESC, SB16_MMR6_ENC, ISA_MICROMIPS32R6; +def SEB_MMR6 : StdMMR6Rel, SEB_MMR6_DESC, SEB_MMR6_ENC, ISA_MICROMIPS32R6; +def SEH_MMR6 : StdMMR6Rel, SEH_MMR6_DESC, SEH_MMR6_ENC, ISA_MICROMIPS32R6; +def SELEQZ_MMR6 : R6MMR6Rel, SELEQZ_MMR6_ENC, SELEQZ_MMR6_DESC, + ISA_MICROMIPS32R6; +def SELNEZ_MMR6 : R6MMR6Rel, SELNEZ_MMR6_ENC, SELNEZ_MMR6_DESC, + ISA_MICROMIPS32R6; +def SH16_MMR6 : StdMMR6Rel, SH16_MMR6_DESC, SH16_MMR6_ENC, ISA_MICROMIPS32R6; +def SLL_MMR6 : StdMMR6Rel, SLL_MMR6_DESC, SLL_MMR6_ENC, ISA_MICROMIPS32R6; +def SUB_MMR6 : StdMMR6Rel, SUB_MMR6_DESC, SUB_MMR6_ENC, ISA_MICROMIPS32R6; +def SUBU_MMR6 : StdMMR6Rel, SUBU_MMR6_DESC, SUBU_MMR6_ENC, ISA_MICROMIPS32R6; +def SW16_MMR6 : StdMMR6Rel, SW16_MMR6_DESC, SW16_MMR6_ENC, ISA_MICROMIPS32R6; +def SWM16_MMR6 : StdMMR6Rel, SWM16_MMR6_DESC, SWM16_MMR6_ENC, ISA_MICROMIPS32R6; +def SWSP_MMR6 : StdMMR6Rel, SWSP_MMR6_DESC, SWSP_MMR6_ENC, ISA_MICROMIPS32R6; +def PREFE_MMR6 : StdMMR6Rel, PREFE_MMR6_ENC, PREFE_MMR6_DESC, ISA_MICROMIPS32R6; +def CACHEE_MMR6 : StdMMR6Rel, CACHEE_MMR6_ENC, CACHEE_MMR6_DESC, + ISA_MICROMIPS32R6; +def WRPGPR_MMR6 : StdMMR6Rel, WRPGPR_MMR6_ENC, WRPGPR_MMR6_DESC, + ISA_MICROMIPS32R6; +def WSBH_MMR6 : StdMMR6Rel, WSBH_MMR6_ENC, WSBH_MMR6_DESC, ISA_MICROMIPS32R6; +def LB_MMR6 : R6MMR6Rel, LB_MMR6_ENC, LB_MMR6_DESC, ISA_MICROMIPS32R6; +def LBU_MMR6 : R6MMR6Rel, LBU_MMR6_ENC, LBU_MMR6_DESC, ISA_MICROMIPS32R6; +def LBE_MMR6 : R6MMR6Rel, LBE_MMR6_ENC, LBE_MMR6_DESC, ISA_MICROMIPS32R6; +def LBUE_MMR6 : R6MMR6Rel, LBUE_MMR6_ENC, LBUE_MMR6_DESC, ISA_MICROMIPS32R6; +def PAUSE_MMR6 : StdMMR6Rel, PAUSE_MMR6_DESC, PAUSE_MMR6_ENC, ISA_MICROMIPS32R6; +def RDHWR_MMR6 : R6MMR6Rel, RDHWR_MMR6_DESC, RDHWR_MMR6_ENC, ISA_MICROMIPS32R6; +def WAIT_MMR6 : StdMMR6Rel, WAIT_MMR6_DESC, WAIT_MMR6_ENC, ISA_MICROMIPS32R6; +def SSNOP_MMR6 : StdMMR6Rel, SSNOP_MMR6_DESC, SSNOP_MMR6_ENC, ISA_MICROMIPS32R6; +def SYNC_MMR6 : StdMMR6Rel, SYNC_MMR6_DESC, SYNC_MMR6_ENC, ISA_MICROMIPS32R6; +def SYNCI_MMR6 : StdMMR6Rel, SYNCI_MMR6_DESC, SYNCI_MMR6_ENC, ISA_MICROMIPS32R6; +def RDPGPR_MMR6 : R6MMR6Rel, RDPGPR_MMR6_DESC, RDPGPR_MMR6_ENC, + ISA_MICROMIPS32R6; +def SDBBP_MMR6 : R6MMR6Rel, SDBBP_MMR6_DESC, SDBBP_MMR6_ENC, ISA_MICROMIPS32R6; +def XOR_MMR6 : StdMMR6Rel, XOR_MMR6_DESC, XOR_MMR6_ENC, ISA_MICROMIPS32R6; +def XORI_MMR6 : StdMMR6Rel, XORI_MMR6_DESC, XORI_MMR6_ENC, ISA_MICROMIPS32R6; +let DecoderMethod = "DecodeMemMMImm16" in { + def SW_MMR6 : StdMMR6Rel, SW_MMR6_DESC, SW_MMR6_ENC, ISA_MICROMIPS32R6; +} +let DecoderMethod = "DecodeMemMMImm9" in { + def SWE_MMR6 : StdMMR6Rel, SWE_MMR6_DESC, SWE_MMR6_ENC, ISA_MICROMIPS32R6; +} +/// Floating Point Instructions +def FADD_S_MMR6 : StdMMR6Rel, FADD_S_MMR6_ENC, FADD_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def FADD_D_MMR6 : StdMMR6Rel, FADD_D_MMR6_ENC, FADD_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def FSUB_S_MMR6 : StdMMR6Rel, FSUB_S_MMR6_ENC, FSUB_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def FSUB_D_MMR6 : StdMMR6Rel, FSUB_D_MMR6_ENC, FSUB_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def FMUL_S_MMR6 : StdMMR6Rel, FMUL_S_MMR6_ENC, FMUL_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def FMUL_D_MMR6 : StdMMR6Rel, FMUL_D_MMR6_ENC, FMUL_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def FDIV_S_MMR6 : StdMMR6Rel, FDIV_S_MMR6_ENC, FDIV_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def FDIV_D_MMR6 : StdMMR6Rel, FDIV_D_MMR6_ENC, FDIV_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def MADDF_S_MMR6 : R6MMR6Rel, MADDF_S_MMR6_ENC, MADDF_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def MADDF_D_MMR6 : R6MMR6Rel, MADDF_D_MMR6_ENC, MADDF_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def MSUBF_S_MMR6 : R6MMR6Rel, MSUBF_S_MMR6_ENC, MSUBF_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def MSUBF_D_MMR6 : R6MMR6Rel, MSUBF_D_MMR6_ENC, MSUBF_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def FMOV_S_MMR6 : StdMMR6Rel, FMOV_S_MMR6_ENC, FMOV_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def FMOV_D_MMR6 : StdMMR6Rel, FMOV_D_MMR6_ENC, FMOV_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def FNEG_S_MMR6 : StdMMR6Rel, FNEG_S_MMR6_ENC, FNEG_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def FNEG_D_MMR6 : StdMMR6Rel, FNEG_D_MMR6_ENC, FNEG_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def MAX_S_MMR6 : R6MMR6Rel, MAX_S_MMR6_ENC, MAX_S_MMR6_DESC, ISA_MICROMIPS32R6; +def MAX_D_MMR6 : R6MMR6Rel, MAX_D_MMR6_ENC, MAX_D_MMR6_DESC, ISA_MICROMIPS32R6; +def MIN_S_MMR6 : R6MMR6Rel, MIN_S_MMR6_ENC, MIN_S_MMR6_DESC, ISA_MICROMIPS32R6; +def MIN_D_MMR6 : R6MMR6Rel, MIN_D_MMR6_ENC, MIN_D_MMR6_DESC, ISA_MICROMIPS32R6; +def MAXA_S_MMR6 : R6MMR6Rel, MAXA_S_MMR6_ENC, MAXA_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def MAXA_D_MMR6 : R6MMR6Rel, MAXA_D_MMR6_ENC, MAXA_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def MINA_S_MMR6 : R6MMR6Rel, MINA_S_MMR6_ENC, MINA_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def MINA_D_MMR6 : R6MMR6Rel, MINA_D_MMR6_ENC, MINA_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def CVT_L_S_MMR6 : StdMMR6Rel, CVT_L_S_MMR6_ENC, CVT_L_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def CVT_L_D_MMR6 : StdMMR6Rel, CVT_L_D_MMR6_ENC, CVT_L_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def CVT_W_S_MMR6 : StdMMR6Rel, CVT_W_S_MMR6_ENC, CVT_W_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def CVT_W_D_MMR6 : StdMMR6Rel, CVT_W_D_MMR6_ENC, CVT_W_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def CVT_D_S_MMR6 : StdMMR6Rel, CVT_D_S_MMR6_ENC, CVT_D_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def CVT_D_W_MMR6 : StdMMR6Rel, CVT_D_W_MMR6_ENC, CVT_D_W_MMR6_DESC, + ISA_MICROMIPS32R6; +def CVT_D_L_MMR6 : StdMMR6Rel, CVT_D_L_MMR6_ENC, CVT_D_L_MMR6_DESC, + ISA_MICROMIPS32R6; +def CVT_S_D_MMR6 : StdMMR6Rel, CVT_S_D_MMR6_ENC, CVT_S_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def CVT_S_W_MMR6 : StdMMR6Rel, CVT_S_W_MMR6_ENC, CVT_S_W_MMR6_DESC, + ISA_MICROMIPS32R6; +def CVT_S_L_MMR6 : StdMMR6Rel, CVT_S_L_MMR6_ENC, CVT_S_L_MMR6_DESC, + ISA_MICROMIPS32R6; +defm S_MMR6 : CMP_CC_MMR6<0b000101, "s", FGR32Opnd>; +defm D_MMR6 : CMP_CC_MMR6<0b010101, "d", FGR64Opnd>; +def ABS_S_MMR6 : StdMMR6Rel, ABS_S_MMR6_ENC, ABS_S_MMR6_DESC, ISA_MICROMIPS32R6; +def ABS_D_MMR6 : StdMMR6Rel, ABS_D_MMR6_ENC, ABS_D_MMR6_DESC, ISA_MICROMIPS32R6; +def FLOOR_L_S_MMR6 : StdMMR6Rel, FLOOR_L_S_MMR6_ENC, FLOOR_L_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def FLOOR_L_D_MMR6 : StdMMR6Rel, FLOOR_L_D_MMR6_ENC, FLOOR_L_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def FLOOR_W_S_MMR6 : StdMMR6Rel, FLOOR_W_S_MMR6_ENC, FLOOR_W_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def FLOOR_W_D_MMR6 : StdMMR6Rel, FLOOR_W_D_MMR6_ENC, FLOOR_W_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def CEIL_L_S_MMR6 : StdMMR6Rel, CEIL_L_S_MMR6_ENC, CEIL_L_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def CEIL_L_D_MMR6 : StdMMR6Rel, CEIL_L_D_MMR6_ENC, CEIL_L_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def CEIL_W_S_MMR6 : StdMMR6Rel, CEIL_W_S_MMR6_ENC, CEIL_W_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def CEIL_W_D_MMR6 : StdMMR6Rel, CEIL_W_D_MMR6_ENC, CEIL_W_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def TRUNC_L_S_MMR6 : StdMMR6Rel, TRUNC_L_S_MMR6_ENC, TRUNC_L_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def TRUNC_L_D_MMR6 : StdMMR6Rel, TRUNC_L_D_MMR6_ENC, TRUNC_L_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def TRUNC_W_S_MMR6 : StdMMR6Rel, TRUNC_W_S_MMR6_ENC, TRUNC_W_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def TRUNC_W_D_MMR6 : StdMMR6Rel, TRUNC_W_D_MMR6_ENC, TRUNC_W_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def SQRT_S_MMR6 : StdMMR6Rel, SQRT_S_MMR6_ENC, SQRT_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def SQRT_D_MMR6 : StdMMR6Rel, SQRT_D_MMR6_ENC, SQRT_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def RSQRT_S_MMR6 : StdMMR6Rel, RSQRT_S_MMR6_ENC, RSQRT_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def RSQRT_D_MMR6 : StdMMR6Rel, RSQRT_D_MMR6_ENC, RSQRT_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def SB_MMR6 : StdMMR6Rel, SB_MMR6_DESC, SB_MMR6_ENC, ISA_MICROMIPS32R6; +def SBE_MMR6 : StdMMR6Rel, SBE_MMR6_DESC, SBE_MMR6_ENC, ISA_MICROMIPS32R6; +def SCE_MMR6 : StdMMR6Rel, SCE_MMR6_DESC, SCE_MMR6_ENC, ISA_MICROMIPS32R6; +def SH_MMR6 : StdMMR6Rel, SH_MMR6_DESC, SH_MMR6_ENC, ISA_MICROMIPS32R6; +def SHE_MMR6 : StdMMR6Rel, SHE_MMR6_DESC, SHE_MMR6_ENC, ISA_MICROMIPS32R6; +def LLE_MMR6 : StdMMR6Rel, LLE_MMR6_DESC, LLE_MMR6_ENC, ISA_MICROMIPS32R6; +def LWE_MMR6 : StdMMR6Rel, LWE_MMR6_DESC, LWE_MMR6_ENC, ISA_MICROMIPS32R6; +def LW_MMR6 : StdMMR6Rel, LW_MMR6_DESC, LW_MMR6_ENC, ISA_MICROMIPS32R6; +def LUI_MMR6 : R6MMR6Rel, LUI_MMR6_DESC, LUI_MMR6_ENC, ISA_MICROMIPS32R6; +def ADDU16_MMR6 : StdMMR6Rel, ADDU16_MMR6_DESC, ADDU16_MMR6_ENC, + ISA_MICROMIPS32R6; +def AND16_MMR6 : StdMMR6Rel, AND16_MMR6_DESC, AND16_MMR6_ENC, + ISA_MICROMIPS32R6; +def ANDI16_MMR6 : StdMMR6Rel, ANDI16_MMR6_DESC, ANDI16_MMR6_ENC, + ISA_MICROMIPS32R6; +def NOT16_MMR6 : StdMMR6Rel, NOT16_MMR6_DESC, NOT16_MMR6_ENC, + ISA_MICROMIPS32R6; +def OR16_MMR6 : StdMMR6Rel, OR16_MMR6_DESC, OR16_MMR6_ENC, + ISA_MICROMIPS32R6; +def SLL16_MMR6 : StdMMR6Rel, SLL16_MMR6_DESC, SLL16_MMR6_ENC, + ISA_MICROMIPS32R6; +def SRL16_MMR6 : StdMMR6Rel, SRL16_MMR6_DESC, SRL16_MMR6_ENC, + ISA_MICROMIPS32R6; +def BREAK16_MMR6 : StdMMR6Rel, BREAK16_MMR6_DESC, BREAK16_MMR6_ENC, + ISA_MICROMIPS32R6; +def LI16_MMR6 : StdMMR6Rel, LI16_MMR6_DESC, LI16_MMR6_ENC, + ISA_MICROMIPS32R6; +def MOVE16_MMR6 : StdMMR6Rel, MOVE16_MMR6_DESC, MOVE16_MMR6_ENC, + ISA_MICROMIPS32R6; +def SDBBP16_MMR6 : StdMMR6Rel, SDBBP16_MMR6_DESC, SDBBP16_MMR6_ENC, + ISA_MICROMIPS32R6; +def SUBU16_MMR6 : StdMMR6Rel, SUBU16_MMR6_DESC, SUBU16_MMR6_ENC, + ISA_MICROMIPS32R6; +def XOR16_MMR6 : StdMMR6Rel, XOR16_MMR6_DESC, XOR16_MMR6_ENC, + ISA_MICROMIPS32R6; +def RECIP_S_MMR6 : StdMMR6Rel, RECIP_S_MMR6_ENC, RECIP_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def RECIP_D_MMR6 : StdMMR6Rel, RECIP_D_MMR6_ENC, RECIP_D_MMR6_DESC, ISA_MICROMIPS32R6; +def RINT_S_MMR6 : StdMMR6Rel, RINT_S_MMR6_ENC, RINT_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def RINT_D_MMR6 : StdMMR6Rel, RINT_D_MMR6_ENC, RINT_D_MMR6_DESC, ISA_MICROMIPS32R6; +def ROUND_L_S_MMR6 : StdMMR6Rel, ROUND_L_S_MMR6_ENC, ROUND_L_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def ROUND_L_D_MMR6 : StdMMR6Rel, ROUND_L_D_MMR6_ENC, ROUND_L_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def ROUND_W_S_MMR6 : StdMMR6Rel, ROUND_W_S_MMR6_ENC, ROUND_W_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def ROUND_W_D_MMR6 : StdMMR6Rel, ROUND_W_D_MMR6_ENC, ROUND_W_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def SEL_S_MMR6 : StdMMR6Rel, SEL_S_MMR6_ENC, SEL_S_MMR6_DESC, ISA_MICROMIPS32R6; +def SEL_D_MMR6 : StdMMR6Rel, SEL_D_MMR6_ENC, SEL_D_MMR6_DESC, ISA_MICROMIPS32R6; +def SELEQZ_S_MMR6 : StdMMR6Rel, SELEQZ_S_MMR6_ENC, SELEQZ_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def SELEQZ_D_MMR6 : StdMMR6Rel, SELEQZ_D_MMR6_ENC, SELEQZ_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def SELENZ_S_MMR6 : StdMMR6Rel, SELENZ_S_MMR6_ENC, SELENZ_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def SELENZ_D_MMR6 : StdMMR6Rel, SELENZ_D_MMR6_ENC, SELENZ_D_MMR6_DESC, + ISA_MICROMIPS32R6; +def CLASS_S_MMR6 : StdMMR6Rel, CLASS_S_MMR6_ENC, CLASS_S_MMR6_DESC, + ISA_MICROMIPS32R6; +def CLASS_D_MMR6 : StdMMR6Rel, CLASS_D_MMR6_ENC, CLASS_D_MMR6_DESC, + ISA_MICROMIPS32R6; +} + +//===----------------------------------------------------------------------===// +// +// MicroMips instruction aliases +// +//===----------------------------------------------------------------------===// + +def : MipsInstAlias<"ei", (EI_MMR6 ZERO), 1>, ISA_MICROMIPS32R6; +def : MipsInstAlias<"di", (DI_MMR6 ZERO), 1>, ISA_MICROMIPS32R6; +def : MipsInstAlias<"nop", (SLL_MMR6 ZERO, ZERO, 0), 1>, ISA_MICROMIPS32R6; +def B_MMR6_Pseudo : MipsAsmPseudoInst<(outs), (ins brtarget_mm:$offset), + !strconcat("b", "\t$offset")> { + string DecoderNamespace = "MicroMipsR6"; +} +def : MipsInstAlias<"sync", (SYNC_MMR6 0), 1>, ISA_MICROMIPS32R6; +def : MipsInstAlias<"sdbbp", (SDBBP_MMR6 0), 1>, ISA_MICROMIPS32R6; +def : MipsInstAlias<"rdhwr $rt, $rs", + (RDHWR_MMR6 GPR32Opnd:$rt, HWRegsOpnd:$rs, 0), 1>, + ISA_MICROMIPS32R6; + +//===----------------------------------------------------------------------===// +// +// MicroMips arbitrary patterns that map to one or more instructions +// +//===----------------------------------------------------------------------===// + +def : MipsPat<(store GPRMM16:$src, addrimm4lsl2:$addr), + (SW16_MMR6 GPRMM16:$src, addrimm4lsl2:$addr)>, ISA_MICROMIPS32R6; diff --git a/contrib/llvm/lib/Target/Mips/MicroMips64r6InstrFormats.td b/contrib/llvm/lib/Target/Mips/MicroMips64r6InstrFormats.td new file mode 100644 index 0000000..da305a2 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MicroMips64r6InstrFormats.td @@ -0,0 +1,86 @@ +//=- MicroMips64r6InstrFormats.td - Instruction Formats -*- tablegen -* -=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes microMIPS64r6 instruction formats. +// +//===----------------------------------------------------------------------===// + +class DAUI_FM_MMR6 { + bits<5> rt; + bits<5> rs; + bits<16> imm; + + bits<32> Inst; + + let Inst{31-26} = 0b111100; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-0} = imm; +} + +class POOL32I_ADD_IMM_FM_MMR6<bits<5> funct> { + bits<5> rs; + bits<16> imm; + + bits<32> Inst; + + let Inst{31-26} = 0b010000; + let Inst{25-21} = funct; + let Inst{20-16} = rs; + let Inst{15-0} = imm; +} + +class POOL32S_EXTBITS_FM_MMR6<bits<6> funct> { + bits<5> rt; + bits<5> rs; + bits<5> size; + bits<5> pos; + + bits<32> Inst; + + let Inst{31-26} = 0b010110; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-11} = size; + let Inst{10-6} = pos; + let Inst{5-0} = funct; +} + +class POOL32S_DALIGN_FM_MMR6 { + bits<5> rs; + bits<5> rt; + bits<5> rd; + bits<3> bp; + + bits<32> Inst; + + let Inst{31-26} = 0b010110; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-8} = bp; + let Inst{7-6} = 0b00; + let Inst{5-0} = 0b011100; +} + +class POOL32A_DIVMOD_FM_MMR6<string instr_asm, bits<9> funct> + : MMR6Arch<instr_asm> { + bits<5> rd; + bits<5> rs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0b010110; + let Inst{25-21} = rd; + let Inst{20-16} = rs; + let Inst{15-11} = rt; + let Inst{10-9} = 0b00; + let Inst{8-0} = funct; +} diff --git a/contrib/llvm/lib/Target/Mips/MicroMips64r6InstrInfo.td b/contrib/llvm/lib/Target/Mips/MicroMips64r6InstrInfo.td new file mode 100644 index 0000000..ec1aef8 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MicroMips64r6InstrInfo.td @@ -0,0 +1,119 @@ +//=- MicroMips64r6InstrInfo.td - Instruction Information -*- tablegen -*- -=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes MicroMips64r6 instructions. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// +// Instruction Encodings +// +//===----------------------------------------------------------------------===// + +class DAUI_MMR6_ENC : DAUI_FM_MMR6; +class DAHI_MMR6_ENC : POOL32I_ADD_IMM_FM_MMR6<0b10001>; +class DATI_MMR6_ENC : POOL32I_ADD_IMM_FM_MMR6<0b10000>; +class DEXT_MMR6_ENC : POOL32S_EXTBITS_FM_MMR6<0b101100>; +class DEXTM_MMR6_ENC : POOL32S_EXTBITS_FM_MMR6<0b100100>; +class DEXTU_MMR6_ENC : POOL32S_EXTBITS_FM_MMR6<0b010100>; +class DALIGN_MMR6_ENC : POOL32S_DALIGN_FM_MMR6; +class DDIV_MM64R6_ENC : POOL32A_DIVMOD_FM_MMR6<"ddiv", 0b100011000>; +class DMOD_MM64R6_ENC : POOL32A_DIVMOD_FM_MMR6<"dmod", 0b101011000>; +class DDIVU_MM64R6_ENC : POOL32A_DIVMOD_FM_MMR6<"ddivu", 0b110011000>; +class DMODU_MM64R6_ENC : POOL32A_DIVMOD_FM_MMR6<"dmodu", 0b111011000>; + +//===----------------------------------------------------------------------===// +// +// Instruction Descriptions +// +//===----------------------------------------------------------------------===// + +class DAUI_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> + : MMR6Arch<instr_asm>, MipsR6Inst { + dag OutOperandList = (outs GPROpnd:$rt); + dag InOperandList = (ins GPROpnd:$rs, simm16:$imm); + string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $imm"); + list<dag> Pattern = []; +} +class DAUI_MMR6_DESC : DAUI_MMR6_DESC_BASE<"daui", GPR64Opnd>; + +class DAHI_DATI_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> + : MMR6Arch<instr_asm>, MipsR6Inst { + dag OutOperandList = (outs GPROpnd:$rs); + dag InOperandList = (ins GPROpnd:$rt, simm16:$imm); + string AsmString = !strconcat(instr_asm, "\t$rt, $imm"); + string Constraints = "$rs = $rt"; +} +class DAHI_MMR6_DESC : DAHI_DATI_DESC_BASE<"dahi", GPR64Opnd>; +class DATI_MMR6_DESC : DAHI_DATI_DESC_BASE<"dati", GPR64Opnd>; + +class EXTBITS_DESC_BASE<string instr_asm, RegisterOperand RO, Operand PosOpnd, + Operand SizeOpnd, SDPatternOperator Op = null_frag> + : MMR6Arch<instr_asm>, MipsR6Inst { + dag OutOperandList = (outs RO:$rt); + dag InOperandList = (ins RO:$rs, PosOpnd:$pos, SizeOpnd:$size); + string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $pos, $size"); + list<dag> Pattern = [(set RO:$rt, (Op RO:$rs, imm:$pos, imm:$size))]; + InstrItinClass Itinerary = II_EXT; + Format Form = FrmR; + string BaseOpcode = instr_asm; +} +// TODO: Add 'pos + size' constraint check to dext* instructions +// DEXT: 0 < pos + size <= 63 +// DEXTM, DEXTU: 32 < pos + size <= 64 +class DEXT_MMR6_DESC : EXTBITS_DESC_BASE<"dext", GPR64Opnd, uimm5, + uimm5_plus1, MipsExt>; +class DEXTM_MMR6_DESC : EXTBITS_DESC_BASE<"dextm", GPR64Opnd, uimm5, + uimm5_plus33, MipsExt>; +class DEXTU_MMR6_DESC : EXTBITS_DESC_BASE<"dextu", GPR64Opnd, uimm5_plus32, + uimm5_plus1, MipsExt>; + +class DALIGN_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + Operand ImmOpnd> : MMR6Arch<instr_asm>, MipsR6Inst { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, ImmOpnd:$bp); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt, $bp"); + list<dag> Pattern = []; +} + +class DALIGN_MMR6_DESC : DALIGN_DESC_BASE<"dalign", GPR64Opnd, uimm3>; + +class DDIV_MM64R6_DESC : ArithLogicR<"ddiv", GPR32Opnd>; +class DMOD_MM64R6_DESC : ArithLogicR<"dmod", GPR32Opnd>; +class DDIVU_MM64R6_DESC : ArithLogicR<"ddivu", GPR32Opnd>; +class DMODU_MM64R6_DESC : ArithLogicR<"dmodu", GPR32Opnd>; + +//===----------------------------------------------------------------------===// +// +// Instruction Definitions +// +//===----------------------------------------------------------------------===// + +let DecoderNamespace = "MicroMipsR6" in { + def DAUI_MM64R6 : StdMMR6Rel, DAUI_MMR6_DESC, DAUI_MMR6_ENC, ISA_MICROMIPS64R6; + def DAHI_MM64R6 : StdMMR6Rel, DAHI_MMR6_DESC, DAHI_MMR6_ENC, ISA_MICROMIPS64R6; + def DATI_MM64R6 : StdMMR6Rel, DATI_MMR6_DESC, DATI_MMR6_ENC, ISA_MICROMIPS64R6; + def DEXT_MM64R6 : StdMMR6Rel, DEXT_MMR6_DESC, DEXT_MMR6_ENC, + ISA_MICROMIPS64R6; + def DEXTM_MM64R6 : StdMMR6Rel, DEXTM_MMR6_DESC, DEXTM_MMR6_ENC, + ISA_MICROMIPS64R6; + def DEXTU_MM64R6 : StdMMR6Rel, DEXTU_MMR6_DESC, DEXTU_MMR6_ENC, + ISA_MICROMIPS64R6; + def DALIGN_MM64R6 : StdMMR6Rel, DALIGN_MMR6_DESC, DALIGN_MMR6_ENC, + ISA_MICROMIPS64R6; + def DDIV_MM64R6 : R6MMR6Rel, DDIV_MM64R6_DESC, DDIV_MM64R6_ENC, + ISA_MICROMIPS64R6; + def DMOD_MM64R6 : R6MMR6Rel, DMOD_MM64R6_DESC, DMOD_MM64R6_ENC, + ISA_MICROMIPS64R6; + def DDIVU_MM64R6 : R6MMR6Rel, DDIVU_MM64R6_DESC, DDIVU_MM64R6_ENC, + ISA_MICROMIPS64R6; + def DMODU_MM64R6 : R6MMR6Rel, DMODU_MM64R6_DESC, DMODU_MM64R6_ENC, + ISA_MICROMIPS64R6; +} diff --git a/contrib/llvm/lib/Target/Mips/MicroMipsDSPInstrFormats.td b/contrib/llvm/lib/Target/Mips/MicroMipsDSPInstrFormats.td new file mode 100644 index 0000000..f11c09a --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MicroMipsDSPInstrFormats.td @@ -0,0 +1,244 @@ +//===-- MicroMipsDSPInstrFormats.td - Instruction Formats --*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +class MMDSPInst<string opstr = ""> + : MipsInst<(outs), (ins), "", [], NoItinerary, FrmOther>, PredicateControl { + let InsnPredicates = [HasDSP]; + let AdditionalPredicates = [InMicroMips]; + string BaseOpcode = opstr; + string Arch = "mmdsp"; + let DecoderNamespace = "MicroMips"; +} + +class MMDSPInstAlias<string Asm, dag Result, bit Emit = 0b1> + : InstAlias<Asm, Result, Emit>, PredicateControl { + let InsnPredicates = [HasDSP]; + let AdditionalPredicates = [InMicroMips]; +} + +class POOL32A_3R_FMT<string opstr, bits<11> op> : MMDSPInst<opstr> { + bits<5> rd; + bits<5> rs; + bits<5> rt; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-11} = rd; + let Inst{10-0} = op; +} + +class POOL32A_2R_FMT<string opstr, bits<10> op> : MMDSPInst<opstr> { + bits<5> rt; + bits<5> rs; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-6} = op; + let Inst{5-0} = 0b111100; +} + +class POOL32A_2RAC_FMT<string opstr, bits<8> op> : MMDSPInst<opstr> { + bits<5> rt; + bits<5> rs; + bits<2> ac; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-14} = ac; + let Inst{13-6} = op; + let Inst{5-0} = 0b111100; +} + +class POOL32A_3RB0_FMT<string opstr, bits<10> op> : MMDSPInst<opstr> { + bits<5> rd; + bits<5> rs; + bits<5> rt; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-11} = rd; + let Inst{10} = 0b0; + let Inst{9-0} = op; +} + +class POOL32A_2RSA4_FMT<string opstr, bits<12> op> : MMDSPInst<opstr> { + bits<5> rt; + bits<5> rs; + bits<4> sa; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-12} = sa; + let Inst{11-0} = op; +} + +class POOL32A_2RSA3_FMT<string opstr, bits<7> op> : MMDSPInst<opstr> { + bits<5> rt; + bits<5> rs; + bits<3> sa; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-13} = sa; + let Inst{12-6} = op; + let Inst{5-0} = 0b111100; +} + +class POOL32A_2RSA5B0_FMT<string opstr, bits<10> op> : MMDSPInst<opstr> { + bits<5> rt; + bits<5> rs; + bits<5> sa; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-11} = sa; + let Inst{10} = 0b0; + let Inst{9-0} = op; +} + +class POOL32A_2RSA4B0_FMT<string opstr, bits<11> op> : MMDSPInst<opstr> { + bits<5> rt; + bits<5> rs; + bits<4> sa; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-12} = sa; + let Inst{11} = 0b0; + let Inst{10-0} = op; +} + +class POOL32A_2RSA4OP6_FMT<string opstr, bits<6> op> : MMDSPInst<opstr> { + bits<5> rt; + bits<5> rs; + bits<4> sa; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-12} = sa; + let Inst{11-6} = op; + let Inst{5-0} = 0b111100; +} + +class POOL32A_1RIMM5AC_FMT<string opstr, bits<8> funct> : MMDSPInst<opstr> { + bits<5> rt; + bits<5> imm; + bits<2> ac; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rt; + let Inst{20-16} = imm; + let Inst{15-14} = ac; + let Inst{13-6} = funct; + let Inst{5-0} = 0b111100; +} + +class POOL32A_2RSA5_FMT<string opstr, bits<11> op> : MMDSPInst<opstr> { + bits<5> rt; + bits<5> rs; + bits<5> sa; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-11} = sa; + let Inst{10-0} = op; +} + +class POOL32A_1RMEMB0_FMT<string opstr, bits<10> funct> : MMDSPInst<opstr> { + bits<5> index; + bits<5> base; + bits<5> rd; + + let Inst{31-26} = 0; + let Inst{25-21} = index; + let Inst{20-16} = base; + let Inst{15-11} = rd; + let Inst{10} = 0b0; + let Inst{9-0} = funct; +} + +class POOL32A_1RAC_FMT<string instr_asm, bits<8> funct> : MMDSPInst<instr_asm> { + bits<5> rs; + bits<2> ac; + + let Inst{31-26} = 0; + let Inst{25-21} = 0; + let Inst{20-16} = rs; + let Inst{15-14} = ac; + let Inst{13-6} = funct; + let Inst{5-0} = 0b111100; +} + +class POOL32A_1RMASK7_FMT<string opstr, bits<8> op> : MMDSPInst<opstr> { + bits<5> rt; + bits<7> mask; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = rt; + let Inst{20-14} = mask; + let Inst{13-6} = op; + let Inst{5-0} = 0b111100; +} + +class POOL32A_1RIMM10_FMT<string opstr, bits<10> op> : MMDSPInst<opstr> { + bits<5> rd; + bits<10> imm; + + let Inst{31-26} = 0; + let Inst{25-16} = imm; + let Inst{15-11} = rd; + let Inst{10} = 0; + let Inst{9-0} = op; +} + +class POOL32A_1RIMM8_FMT<string opstr, bits<6> op> : MMDSPInst<opstr> { + bits<5> rt; + bits<8> imm; + + let Inst{31-26} = 0; + let Inst{25-21} = rt; + let Inst{20-13} = imm; + let Inst{12} = 0; + let Inst{11-6} = op; + let Inst{5-0} = 0b111100; +} + +class POOL32A_4B0SHIFT6AC4B0_FMT<string opstr, bits<10> op> : MMDSPInst<opstr> { + bits<6> shift; + bits<2> ac; + + let Inst{31-26} = 0b000000; + let Inst{25-22} = 0b0000; + let Inst{21-16} = shift; + let Inst{15-14} = ac; + let Inst{13-10} = 0b0000; + let Inst{9-0} = op; +} + +class POOL32A_5B01RAC_FMT<string opstr, bits<8> op> : MMDSPInst<opstr> { + bits<5> rs; + bits<2> ac; + + let Inst{31-26} = 0b000000; + let Inst{25-21} = 0b00000; + let Inst{20-16} = rs; + let Inst{15-14} = ac; + let Inst{13-6} = op; + let Inst{5-0} = 0b111100; +} diff --git a/contrib/llvm/lib/Target/Mips/MicroMipsDSPInstrInfo.td b/contrib/llvm/lib/Target/Mips/MicroMipsDSPInstrInfo.td new file mode 100644 index 0000000..b342e23 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MicroMipsDSPInstrInfo.td @@ -0,0 +1,528 @@ +//===- MicroMipsDSPInstrInfo.td - Micromips DSP instructions -*- tablegen *-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes MicroMips DSP instructions. +// +//===----------------------------------------------------------------------===// + +// Instruction encoding. +class ADDQ_PH_MM_ENC : POOL32A_3R_FMT<"addq.ph", 0b00000001101>; +class ADDQ_S_PH_MM_ENC : POOL32A_3R_FMT<"addq_s.ph", 0b10000001101>; +class ADDQ_S_W_MM_ENC : POOL32A_3RB0_FMT<"addq_s.w", 0b1100000101>; +class ADDQH_PH_MMR2_ENC : POOL32A_3R_FMT<"addqh.ph", 0b00001001101>; +class ADDQH_R_PH_MMR2_ENC : POOL32A_3R_FMT<"addqh_r.ph", 0b10001001101>; +class ADDQH_W_MMR2_ENC: POOL32A_3R_FMT<"addqh.w", 0b00010001101>; +class ADDQH_R_W_MMR2_ENC : POOL32A_3R_FMT<"addqh_r.w", 0b10010001101>; +class ADDU_PH_MMR2_ENC : POOL32A_3R_FMT<"addu.ph", 0b00100001101>; +class ADDU_S_PH_MMR2_ENC : POOL32A_3R_FMT<"addu_s.ph", 0b10100001101>; +class ADDU_QB_MM_ENC : POOL32A_3R_FMT<"addu.qb", 0b00011001101>; +class ADDU_S_QB_MM_ENC : POOL32A_3R_FMT<"addu_s.qb", 0b10011001101>; +class ADDUH_QB_MMR2_ENC : POOL32A_3R_FMT<"adduh.qb", 0b00101001101>; +class ADDUH_R_QB_MMR2_ENC : POOL32A_3R_FMT<"adduh_r.qb", 0b10101001101>; +class ADDSC_MM_ENC : POOL32A_3RB0_FMT<"addsc", 0b1110000101>; +class ADDWC_MM_ENC : POOL32A_3RB0_FMT<"addwc", 0b1111000101>; +class DPA_W_PH_MMR2_ENC : POOL32A_2RAC_FMT<"dpa.w.ph", 0b00000010>; +class DPAQ_S_W_PH_MM_ENC : POOL32A_2RAC_FMT<"dpaq_s.w.ph", 0b00001010>; +class DPAQ_SA_L_W_MM_ENC : POOL32A_2RAC_FMT<"dpaq_sa.l.w", 0b01001010>; +class DPAQX_S_W_PH_MMR2_ENC : POOL32A_2RAC_FMT<"dpaqx_s.w.ph", 0b10001010>; +class DPAQX_SA_W_PH_MMR2_ENC : POOL32A_2RAC_FMT<"dpaqx_sa.w.ph", 0b11001010>; +class DPAU_H_QBL_MM_ENC : POOL32A_2RAC_FMT<"dpau.h.qbl", 0b10000010>; +class DPAU_H_QBR_MM_ENC : POOL32A_2RAC_FMT<"dpau.h.qbr", 0b11000010>; +class DPAX_W_PH_MMR2_ENC : POOL32A_2RAC_FMT<"dpax.w.ph", 0b01000010>; +class ABSQ_S_PH_MM_ENC : POOL32A_2R_FMT<"absq_s.ph", 0b0001000100>; +class ABSQ_S_W_MM_ENC : POOL32A_2R_FMT<"absq_s.w", 0b0010000100>; +class ABSQ_S_QB_MMR2_ENC : POOL32A_2R_FMT<"absq_s.qb", 0b0000000100>; +class INSV_MM_ENC : POOL32A_2R_FMT<"insv", 0b0100000100>; +class MADD_DSP_MM_ENC : POOL32A_2RAC_FMT<"madd", 0b00101010>; +class MADDU_DSP_MM_ENC : POOL32A_2RAC_FMT<"maddu", 0b01101010>; +class MSUB_DSP_MM_ENC : POOL32A_2RAC_FMT<"msub", 0b10101010>; +class MSUBU_DSP_MM_ENC : POOL32A_2RAC_FMT<"msubu", 0b11101010>; +class MULT_DSP_MM_ENC : POOL32A_2RAC_FMT<"mult", 0b00110010>; +class MULTU_DSP_MM_ENC : POOL32A_2RAC_FMT<"multu", 0b01110010>; +class SHLL_PH_MM_ENC : POOL32A_2RSA4_FMT<"shll.ph", 0b001110110101>; +class SHLL_S_PH_MM_ENC : POOL32A_2RSA4_FMT<"shll_s.ph", 0b101110110101>; +class SHLL_QB_MM_ENC : POOL32A_2RSA3_FMT<"shll.qb", 0b0100001>; +class SHLLV_PH_MM_ENC : POOL32A_3R_FMT<"shllv.ph", 0b00000001110>; +class SHLLV_S_PH_MM_ENC : POOL32A_3R_FMT<"shllv_s.ph", 0b10000001110>; +class SHLLV_QB_MM_ENC : POOL32A_3RB0_FMT<"shllv.qb", 0b1110010101>; +class SHLLV_S_W_MM_ENC : POOL32A_3RB0_FMT<"shllv_s.w", 0b1111010101>; +class SHLL_S_W_MM_ENC : POOL32A_2RSA5B0_FMT<"shll_s.w", 0b1111110101>; +class SHRA_QB_MMR2_ENC : POOL32A_2RSA3_FMT<"shra.qb", 0b0000111>; +class SHRA_R_QB_MMR2_ENC : POOL32A_2RSA3_FMT<"shra_r.qb", 0b1000111>; +class SHRA_PH_MM_ENC : POOL32A_2RSA4B0_FMT<"shra.ph", 0b01100110101>; +class SHRA_R_PH_MM_ENC : POOL32A_2RSA4B0_FMT<"shra_r.ph", 0b11100110101>; +class SHRAV_PH_MM_ENC : POOL32A_3R_FMT<"shrav.ph", 0b00110001101>; +class SHRAV_R_PH_MM_ENC : POOL32A_3R_FMT<"shrav_r.ph", 0b10110001101>; +class SHRAV_QB_MMR2_ENC : POOL32A_3R_FMT<"shrav.qb", 0b00111001101>; +class SHRAV_R_QB_MMR2_ENC : POOL32A_3R_FMT<"shrav_r.qb", 0b10111001101>; +class SHRAV_R_W_MM_ENC : POOL32A_3RB0_FMT<"shrav_r.w", 0b1011010101>; +class SHRA_R_W_MM_ENC : POOL32A_2RSA5B0_FMT<"shra_r.w", 0b1011110101>; +class SHRL_PH_MMR2_ENC : POOL32A_2RSA4OP6_FMT<"shrl.ph", 0b001111>; +class SHRL_QB_MM_ENC : POOL32A_2RSA3_FMT<"shrl.qb", 0b1100001>; +class SHRLV_PH_MMR2_ENC : POOL32A_3RB0_FMT<"shrlv.ph", 0b1100010101>; +class SHRLV_QB_MM_ENC : POOL32A_3RB0_FMT<"shrlv.qb", 0b1101010101>; +class PRECEQ_W_PHL_MM_ENC : POOL32A_2R_FMT<"preceq.w.phl", 0b0101000100>; +class PRECEQ_W_PHR_MM_ENC : POOL32A_2R_FMT<"preceq.w.phr", 0b0110000100>; +class PRECEQU_PH_QBL_MM_ENC : POOL32A_2R_FMT<"precequ.ph.qbl", 0b0111000100>; +class PRECEQU_PH_QBLA_MM_ENC : POOL32A_2R_FMT<"precequ.ph.qbla", 0b0111001100>; +class PRECEQU_PH_QBR_MM_ENC : POOL32A_2R_FMT<"precequ.ph.qbr", 0b1001000100>; +class PRECEQU_PH_QBRA_MM_ENC : POOL32A_2R_FMT<"precequ.ph.qbra", 0b1001001100>; +class PRECEU_PH_QBL_MM_ENC : POOL32A_2R_FMT<"preceu.ph.qbl", 0b1011000100>; +class PRECEU_PH_QBLA_MM_ENC : POOL32A_2R_FMT<"preceu.ph.qbla", 0b1011001100>; +class PRECEU_PH_QBR_MM_ENC : POOL32A_2R_FMT<"preceu.ph.qbr", 0b1101000100>; +class PRECEU_PH_QBRA_MM_ENC : POOL32A_2R_FMT<"preceu.ph.qbra", 0b1101001100>; +class SUBQ_PH_MM_ENC : POOL32A_3R_FMT<"subq.ph", 0b01000001101>; +class SUBQ_S_PH_MM_ENC : POOL32A_3R_FMT<"subq_s.ph", 0b11000001101>; +class SUBQ_S_W_MM_ENC : POOL32A_3RB0_FMT<"subq_s.w", 0b1101000101>; +class SUBQH_PH_MMR2_ENC : POOL32A_3R_FMT<"subqh.ph", 0b01001001101>; +class SUBQH_R_PH_MMR2_ENC : POOL32A_3R_FMT<"subqh_r.ph", 0b11001001101>; +class SUBQH_W_MMR2_ENC : POOL32A_3R_FMT<"subqh.w", 0b01010001101>; +class SUBQH_R_W_MMR2_ENC : POOL32A_3R_FMT<"subqh_r.w", 0b11010001101>; +class SUBU_PH_MMR2_ENC : POOL32A_3R_FMT<"subu.ph", 0b01100001101>; +class SUBU_S_PH_MMR2_ENC : POOL32A_3R_FMT<"subu_s.ph", 0b11100001101>; +class SUBU_QB_MM_ENC : POOL32A_3R_FMT<"subu.qb", 0b01011001101>; +class SUBU_S_QB_MM_ENC : POOL32A_3R_FMT<"subu_s.qb", 0b11011001101>; +class SUBUH_QB_MMR2_ENC : POOL32A_3R_FMT<"subuh.qb", 0b01101001101>; +class SUBUH_R_QB_MMR2_ENC : POOL32A_3R_FMT<"subuh_r.qb", 0b11101001101>; +class EXTP_MM_ENC : POOL32A_1RIMM5AC_FMT<"extp", 0b10011001>; +class EXTPDP_MM_ENC : POOL32A_1RIMM5AC_FMT<"extpdp", 0b11011001>; +class EXTPDPV_MM_ENC : POOL32A_2RAC_FMT<"extpdpv", 0b11100010>; +class EXTPV_MM_ENC : POOL32A_2RAC_FMT<"extpv", 0b10100010>; +class EXTR_W_MM_ENC : POOL32A_1RIMM5AC_FMT<"extr.w", 0b00111001>; +class EXTR_R_W_MM_ENC : POOL32A_1RIMM5AC_FMT<"extr_r.w", 0b01111001>; +class EXTR_RS_W_MM_ENC : POOL32A_1RIMM5AC_FMT<"extr_rs.w", 0b10111001>; +class EXTR_S_H_MM_ENC : POOL32A_1RIMM5AC_FMT<"extr_s.h", 0b11111001>; +class EXTRV_W_MM_ENC : POOL32A_2RAC_FMT<"extrv.w", 0b00111010>; +class EXTRV_R_W_MM_ENC : POOL32A_2RAC_FMT<"extrv_r.w", 0b01111010>; +class EXTRV_RS_W_MM_ENC : POOL32A_2RAC_FMT<"extrv_rs.w", 0b10111010>; +class EXTRV_S_H_MM_ENC : POOL32A_2RAC_FMT<"extrv_s.h", 0b11111010>; +class DPS_W_PH_MMR2_ENC : POOL32A_2RAC_FMT<"dps.w.ph", 0b00010010>; +class DPSQ_S_W_PH_MM_ENC : POOL32A_2RAC_FMT<"dpsq_s.w.ph", 0b00011010>; +class DPSQ_SA_L_W_MM_ENC : POOL32A_2RAC_FMT<"dpsq_sa.l.w", 0b01011010>; +class DPSQX_S_W_PH_MMR2_ENC : POOL32A_2RAC_FMT<"dpsqx_s.w.ph", 0b10011010>; +class DPSQX_SA_W_PH_MMR2_ENC : POOL32A_2RAC_FMT<"dpsqx_sa.w.ph", 0b11011010>; +class DPSU_H_QBL_MM_ENC : POOL32A_2RAC_FMT<"dpsu.h.qbl", 0b10010010>; +class DPSU_H_QBR_MM_ENC : POOL32A_2RAC_FMT<"dpsu.h.qbr", 0b11010010>; +class DPSX_W_PH_MMR2_ENC : POOL32A_2RAC_FMT<"dpsx.w.ph", 0b01010010>; +class MUL_PH_MMR2_ENC : POOL32A_3R_FMT<"mul.ph", 0b00000101101>; +class MUL_S_PH_MMR2_ENC : POOL32A_3R_FMT<"mul_s.ph", 0b10000101101>; +class MULEQ_S_W_PHL_MM_ENC : POOL32A_3RB0_FMT<"muleq_s.w.phl", 0b0000100101>; +class MULEQ_S_W_PHR_MM_ENC : POOL32A_3RB0_FMT<"muleq_s.w.phr", 0b0001100101>; +class MULEU_S_PH_QBL_MM_ENC : POOL32A_3RB0_FMT<"muleu_s.ph.qbl", 0b0010010101>; +class MULEU_S_PH_QBR_MM_ENC : POOL32A_3RB0_FMT<"muleu_s.ph.qbr", 0b0011010101>; +class MULQ_RS_PH_MM_ENC : POOL32A_3RB0_FMT<"mulq_rs.ph", 0b0100010101>; +class MULQ_RS_W_MMR2_ENC : POOL32A_3RB0_FMT<"mulq_rs.w", 0b0110010101>; +class MULQ_S_PH_MMR2_ENC : POOL32A_3RB0_FMT<"mulq_s.ph", 0b0101010101>; +class MULQ_S_W_MMR2_ENC : POOL32A_3RB0_FMT<"mulq_s.w", 0b0111010101>; +class PRECR_QB_PH_MMR2_ENC : POOL32A_3RB0_FMT<"precr.qb.ph", 0b0001101101>; +class PRECR_SRA_PH_W_MMR2_ENC + : POOL32A_2RSA5_FMT<"precr_sra.ph.w", 0b01111001101>; +class PRECR_SRA_R_PH_W_MMR2_ENC + : POOL32A_2RSA5_FMT<"precr_sra_r.ph.w", 0b11111001101>; +class PRECRQ_PH_W_MM_ENC : POOL32A_3RB0_FMT<"precrq.ph.w", 0b0011101101>; +class PRECRQ_QB_PH_MM_ENC : POOL32A_3RB0_FMT<"precrq.qb.ph", 0b0010101101>; +class PRECRQU_S_QB_PH_MM_ENC + : POOL32A_3RB0_FMT<"precrqu_s.qb.ph", 0b0101101101>; +class PRECRQ_RS_PH_W_MM_ENC : POOL32A_3RB0_FMT<"precrq_rs.ph.w", 0b0100101101>; +class LBUX_MM_ENC : POOL32A_1RMEMB0_FMT<"lbux", 0b1000100101>; +class LHX_MM_ENC : POOL32A_1RMEMB0_FMT<"lhx", 0b0101100101>; +class LWX_MM_ENC : POOL32A_1RMEMB0_FMT<"lwx", 0b0110100101>; +class MAQ_S_W_PHL_MM_ENC : POOL32A_2RAC_FMT<"maq_s.w.phl", 0b01101001>; +class MAQ_SA_W_PHL_MM_ENC : POOL32A_2RAC_FMT<"maq_sa.w.phl", 0b11101001>; +class MAQ_S_W_PHR_MM_ENC : POOL32A_2RAC_FMT<"maq_s.w.phr", 0b00101001>; +class MAQ_SA_W_PHR_MM_ENC : POOL32A_2RAC_FMT<"maq_sa.w.phr", 0b10101001>; +class MFHI_MM_ENC : POOL32A_1RAC_FMT<"mfhi", 0b00000001>; +class MFLO_MM_ENC : POOL32A_1RAC_FMT<"mflo", 0b01000001>; +class MTHI_MM_ENC : POOL32A_1RAC_FMT<"mthi", 0b10000001>; +class MTLO_MM_ENC : POOL32A_1RAC_FMT<"mthi", 0b11000001>; +class PREPEND_MMR2_ENC : POOL32A_2RSA5B0_FMT<"prepend", 0b1001010101>; +class RADDU_W_QB_MM_ENC : POOL32A_2R_FMT<"raddu.w.qb", 0b1111000100>; +class RDDSP_MM_ENC : POOL32A_1RMASK7_FMT<"rddsp", 0b00011001>; +class REPL_PH_MM_ENC : POOL32A_1RIMM10_FMT<"repl.ph", 0b0000111101>; +class REPL_QB_MM_ENC : POOL32A_1RIMM8_FMT<"repl.qb", 0b010111>; +class REPLV_PH_MM_ENC : POOL32A_2R_FMT<"replv.ph", 0b0000001100>; +class REPLV_QB_MM_ENC : POOL32A_2R_FMT<"replv.qb", 0b0001001100>; +class MTHLIP_MM_ENC : POOL32A_1RAC_FMT<"mthlip", 0b00001001>; +class PACKRL_PH_MM_ENC : POOL32A_3RB0_FMT<"packrl.ph", 0b0110101101>; +class PICK_PH_MM_ENC : POOL32A_3RB0_FMT<"pick.ph", 0b1000101101>; +class PICK_QB_MM_ENC : POOL32A_3RB0_FMT<"pick.qb", 0b0111101101>; +class SHILO_MM_ENC : POOL32A_4B0SHIFT6AC4B0_FMT<"shilo", 0b0000011101>; +class SHILOV_MM_ENC : POOL32A_5B01RAC_FMT<"shilov", 0b01001001>; +class WRDSP_MM_ENC : POOL32A_1RMASK7_FMT<"wrdsp", 0b01011001>; + +// Instruction desc. +class ABSQ_S_PH_MM_R2_DESC_BASE<string opstr, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand ROD, + RegisterOperand ROS = ROD> { + dag OutOperandList = (outs ROD:$rt); + dag InOperandList = (ins ROS:$rs); + string AsmString = !strconcat(opstr, "\t$rt, $rs"); + list<dag> Pattern = [(set ROD:$rt, (OpNode ROS:$rs))]; + InstrItinClass Itinerary = itin; +} +class ABSQ_S_PH_MM_DESC : ABSQ_S_PH_MM_R2_DESC_BASE< + "absq_s.ph", int_mips_absq_s_ph, NoItinerary, DSPROpnd>, Defs<[DSPOutFlag20]>; +class ABSQ_S_W_MM_DESC : ABSQ_S_PH_MM_R2_DESC_BASE< + "absq_s.w", int_mips_absq_s_w, NoItinerary, GPR32Opnd>, Defs<[DSPOutFlag20]>; +class ABSQ_S_QB_MMR2_DESC : ABSQ_S_PH_MM_R2_DESC_BASE< + "absq_s.qb", int_mips_absq_s_qb, NoItinerary, DSPROpnd>, Defs<[DSPOutFlag20]>; +class PRECEQ_W_PHL_MM_DESC : ABSQ_S_PH_MM_R2_DESC_BASE< + "preceq.w.phl", int_mips_preceq_w_phl, NoItinerary, GPR32Opnd, DSPROpnd>; +class PRECEQ_W_PHR_MM_DESC : ABSQ_S_PH_MM_R2_DESC_BASE< + "preceq.w.phr", int_mips_preceq_w_phr, NoItinerary, GPR32Opnd, DSPROpnd>; +class PRECEQU_PH_QBL_MM_DESC : ABSQ_S_PH_MM_R2_DESC_BASE< + "precequ.ph.qbl", int_mips_precequ_ph_qbl, NoItinerary, DSPROpnd>; +class PRECEQU_PH_QBLA_MM_DESC : ABSQ_S_PH_MM_R2_DESC_BASE< + "precequ.ph.qbla", int_mips_precequ_ph_qbla, NoItinerary, DSPROpnd>; +class PRECEQU_PH_QBR_MM_DESC : ABSQ_S_PH_MM_R2_DESC_BASE< + "precequ.ph.qbr", int_mips_precequ_ph_qbr, NoItinerary, DSPROpnd>; +class PRECEQU_PH_QBRA_MM_DESC : ABSQ_S_PH_MM_R2_DESC_BASE< + "precequ.ph.qbra", int_mips_precequ_ph_qbra, NoItinerary, DSPROpnd>; +class PRECEU_PH_QBL_MM_DESC : ABSQ_S_PH_MM_R2_DESC_BASE< + "preceu.ph.qbl", int_mips_preceu_ph_qbl, NoItinerary, DSPROpnd>; +class PRECEU_PH_QBLA_MM_DESC : ABSQ_S_PH_MM_R2_DESC_BASE< + "preceu.ph.qbla", int_mips_preceu_ph_qbla, NoItinerary, DSPROpnd>; +class PRECEU_PH_QBR_MM_DESC : ABSQ_S_PH_MM_R2_DESC_BASE< + "preceu.ph.qbr", int_mips_preceu_ph_qbr, NoItinerary, DSPROpnd>; +class PRECEU_PH_QBRA_MM_DESC : ABSQ_S_PH_MM_R2_DESC_BASE< + "preceu.ph.qbra", int_mips_preceu_ph_qbra, NoItinerary, DSPROpnd>; + +class SHLL_R2_MM_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + SDPatternOperator ImmPat, InstrItinClass itin, + RegisterOperand RO, Operand ImmOpnd> { + dag OutOperandList = (outs RO:$rt); + dag InOperandList = (ins RO:$rs, ImmOpnd:$sa); + string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $sa"); + list<dag> Pattern = [(set RO:$rt, (OpNode RO:$rs, ImmPat:$sa))]; + InstrItinClass Itinerary = itin; + bit hasSideEffects = 1; +} +class SHLL_PH_MM_DESC : SHLL_R2_MM_DESC_BASE< + "shll.ph", null_frag, immZExt4, NoItinerary, DSPROpnd, uimm4>, + Defs<[DSPOutFlag22]>; +class SHLL_S_PH_MM_DESC : SHLL_R2_MM_DESC_BASE< + "shll_s.ph", int_mips_shll_s_ph, immZExt4, NoItinerary, DSPROpnd, uimm4>, + Defs<[DSPOutFlag22]>; +class SHLL_QB_MM_DESC : SHLL_R2_MM_DESC_BASE< + "shll.qb", null_frag, immZExt3, NoItinerary, DSPROpnd, uimm3>, + Defs<[DSPOutFlag22]>; +class SHLL_S_W_MM_DESC : SHLL_R2_MM_DESC_BASE< + "shll_s.w", int_mips_shll_s_w, immZExt5, NoItinerary, GPR32Opnd, uimm5>, + Defs<[DSPOutFlag22]>; +class SHRA_QB_MMR2_DESC : SHLL_R2_MM_DESC_BASE< + "shra.qb", null_frag, immZExt3, NoItinerary, DSPROpnd, uimm3>; +class SHRA_R_QB_MMR2_DESC : SHLL_R2_MM_DESC_BASE< + "shra_r.qb", int_mips_shra_r_qb, immZExt3, NoItinerary, DSPROpnd, uimm3>; +class SHRA_PH_MM_DESC : SHLL_R2_MM_DESC_BASE< + "shra.ph", null_frag, immZExt4, NoItinerary, DSPROpnd, uimm4>; +class SHRA_R_PH_MM_DESC : SHLL_R2_MM_DESC_BASE< + "shra_r.ph", int_mips_shra_r_ph, immZExt4, NoItinerary, DSPROpnd, uimm4>; +class SHRA_R_W_MM_DESC : SHLL_R2_MM_DESC_BASE< + "shra_r.w", int_mips_shra_r_w, immZExt5, NoItinerary, GPR32Opnd, uimm5>; +class SHRL_QB_MM_DESC : SHLL_R2_MM_DESC_BASE< + "shrl.qb", null_frag, immZExt3, NoItinerary, DSPROpnd, uimm3>; +class SHRL_PH_MMR2_DESC : SHLL_R2_MM_DESC_BASE< + "shrl.ph", null_frag, immZExt4, NoItinerary, DSPROpnd, uimm4>; + +class SHLLV_R3_MM_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand RO> { + dag OutOperandList = (outs RO:$rd); + dag InOperandList = (ins RO:$rt, GPR32Opnd:$rs); + string AsmString = !strconcat(instr_asm, "\t$rd, $rt, $rs"); + list<dag> Pattern = [(set RO:$rd, (OpNode RO:$rt, GPR32Opnd:$rs))]; + InstrItinClass Itinerary = itin; +} +class SHLLV_PH_MM_DESC : SHLLV_R3_MM_DESC_BASE< + "shllv.ph", int_mips_shll_ph, NoItinerary, DSPROpnd>, Defs<[DSPOutFlag22]>; +class SHLLV_S_PH_MM_DESC : SHLLV_R3_MM_DESC_BASE< + "shllv_s.ph", int_mips_shll_s_ph, NoItinerary, DSPROpnd>, + Defs<[DSPOutFlag22]>; +class SHLLV_QB_MM_DESC : SHLLV_R3_MM_DESC_BASE< + "shllv.qb", int_mips_shll_qb, NoItinerary, DSPROpnd>, Defs<[DSPOutFlag22]>; +class SHLLV_S_W_MM_DESC : SHLLV_R3_MM_DESC_BASE< + "shllv_s.w", int_mips_shll_s_w, NoItinerary, GPR32Opnd>, Defs<[DSPOutFlag22]>; +class SHRAV_PH_MM_DESC : SHLLV_R3_MM_DESC_BASE< + "shrav.ph", int_mips_shra_ph, NoItinerary, DSPROpnd>; +class SHRAV_R_PH_MM_DESC : SHLLV_R3_MM_DESC_BASE< + "shrav_r.ph", int_mips_shra_r_ph, NoItinerary, DSPROpnd>; +class SHRAV_QB_MMR2_DESC : SHLLV_R3_MM_DESC_BASE< + "shrav.qb", int_mips_shra_qb, NoItinerary, DSPROpnd>; +class SHRAV_R_QB_MMR2_DESC : SHLLV_R3_MM_DESC_BASE< + "shrav_r.qb", int_mips_shra_r_qb, NoItinerary, DSPROpnd>; +class SHRAV_R_W_MM_DESC : SHLLV_R3_MM_DESC_BASE< + "shrav_r.w", int_mips_shra_r_w, NoItinerary, GPR32Opnd>; +class SHRLV_PH_MMR2_DESC : SHLLV_R3_MM_DESC_BASE< + "shrlv.ph", int_mips_shrl_ph, NoItinerary, DSPROpnd>; +class SHRLV_QB_MM_DESC : SHLLV_R3_MM_DESC_BASE< + "shrlv.qb", int_mips_shrl_qb, NoItinerary, DSPROpnd>; + +class EXT_MM_2R_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs GPR32Opnd:$rt); + dag InOperandList = (ins ACC64DSPOpnd:$ac, GPR32Opnd:$rs); + string AsmString = !strconcat(instr_asm, "\t$rt, $ac, $rs"); + InstrItinClass Itinerary = itin; +} +class EXT_MM_1R_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs GPR32Opnd:$rt); + dag InOperandList = (ins ACC64DSPOpnd:$ac, uimm5:$imm); + string AsmString = !strconcat(instr_asm, "\t$rt, $ac, $imm"); + InstrItinClass Itinerary = itin; +} + +class EXTP_MM_DESC + : EXT_MM_1R_DESC_BASE<"extp", MipsEXTP, NoItinerary>, + Uses<[DSPPos]>, Defs<[DSPEFI]>; +class EXTPDP_MM_DESC + : EXT_MM_1R_DESC_BASE<"extpdp", MipsEXTPDP, NoItinerary>, + Uses<[DSPPos]>, Defs<[DSPPos, DSPEFI]>; +class EXTPDPV_MM_DESC + : EXT_MM_2R_DESC_BASE<"extpdpv", MipsEXTPDP, NoItinerary>, + Uses<[DSPPos]>, Defs<[DSPPos, DSPEFI]>; +class EXTPV_MM_DESC + : EXT_MM_2R_DESC_BASE<"extpv", MipsEXTP, NoItinerary>, + Uses<[DSPPos]>, Defs<[DSPEFI]>; +class EXTR_W_MM_DESC + : EXT_MM_1R_DESC_BASE<"extr.w", MipsEXTR_W, NoItinerary>, + Defs<[DSPOutFlag23]>; +class EXTR_R_W_MM_DESC + : EXT_MM_1R_DESC_BASE<"extr_r.w", MipsEXTR_R_W, NoItinerary>, + Defs<[DSPOutFlag23]>; +class EXTR_RS_W_MM_DESC + : EXT_MM_1R_DESC_BASE<"extr_rs.w", MipsEXTR_RS_W, NoItinerary>, + Defs<[DSPOutFlag23]>; +class EXTR_S_H_MM_DESC + : EXT_MM_1R_DESC_BASE<"extr_s.h", MipsEXTR_S_H, NoItinerary>, + Defs<[DSPOutFlag23]>; +class EXTRV_W_MM_DESC + : EXT_MM_2R_DESC_BASE<"extrv.w", MipsEXTR_W, NoItinerary>, + Defs<[DSPOutFlag23]>; +class EXTRV_R_W_MM_DESC + : EXT_MM_2R_DESC_BASE<"extrv_r.w", MipsEXTR_R_W, NoItinerary>, + Defs<[DSPOutFlag23]>; +class EXTRV_RS_W_MM_DESC + : EXT_MM_2R_DESC_BASE<"extrv_rs.w", MipsEXTR_RS_W, NoItinerary>, + Defs<[DSPOutFlag23]>; +class EXTRV_S_H_MM_DESC + : EXT_MM_2R_DESC_BASE<"extrv_s.h", MipsEXTR_S_H, NoItinerary>, + Defs<[DSPOutFlag23]>; + +class MFHI_MM_DESC_BASE<string instr_asm, RegisterOperand RO, SDNode OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs GPR32Opnd:$rs); + dag InOperandList = (ins RO:$ac); + string AsmString = !strconcat(instr_asm, "\t$rs, $ac"); + list<dag> Pattern = [(set GPR32Opnd:$rs, (OpNode RO:$ac))]; + InstrItinClass Itinerary = itin; +} + +class MFHI_MM_DESC : MFHI_MM_DESC_BASE<"mfhi", ACC64DSPOpnd, MipsMFHI, + NoItinerary>; +class MFLO_MM_DESC : MFHI_MM_DESC_BASE<"mflo", ACC64DSPOpnd, MipsMFLO, + NoItinerary>; + +class RADDU_W_QB_MM_DESC { + dag OutOperandList = (outs GPR32Opnd:$rt); + dag InOperandList = (ins DSPROpnd:$rs); + string AsmString = !strconcat("raddu.w.qb", "\t$rt, $rs"); + list<dag> Pattern = [(set GPR32Opnd:$rt, (int_mips_raddu_w_qb DSPROpnd:$rs))]; + InstrItinClass Itinerary = NoItinerary; + string BaseOpcode = "raddu.w.qb"; +} + +class RDDSP_MM_DESC { + dag OutOperandList = (outs GPR32Opnd:$rt); + dag InOperandList = (ins uimm16:$mask); + string AsmString = !strconcat("rddsp", "\t$rt, $mask"); + list<dag> Pattern = [(set GPR32Opnd:$rt, (int_mips_rddsp immZExt10:$mask))]; + InstrItinClass Itinerary = NoItinerary; +} + +class REPL_QB_MM_DESC { + dag OutOperandList = (outs DSPROpnd:$rt); + dag InOperandList = (ins uimm16:$imm); + string AsmString = !strconcat("repl.qb", "\t$rt, $imm"); + list<dag> Pattern = [(set DSPROpnd:$rt, (int_mips_repl_qb immZExt8:$imm))]; + InstrItinClass Itinerary = NoItinerary; +} + +class REPLV_PH_MM_DESC : ABSQ_S_PH_MM_R2_DESC_BASE<"replv.ph", int_mips_repl_ph, + NoItinerary, DSPROpnd, + GPR32Opnd>; +class REPLV_QB_MM_DESC : ABSQ_S_PH_MM_R2_DESC_BASE<"replv.qb", int_mips_repl_qb, + NoItinerary, DSPROpnd, + GPR32Opnd>; + +class WRDSP_MM_DESC { + dag OutOperandList = (outs); + dag InOperandList = (ins GPR32Opnd:$rt, uimm7:$mask); + string AsmString = !strconcat("wrdsp", "\t$rt, $mask"); + list<dag> Pattern = [(int_mips_wrdsp GPR32Opnd:$rt, immZExt7:$mask)]; + InstrItinClass Itinerary = NoItinerary; +} + +// Instruction defs. +// microMIPS DSP Rev 1 +def ADDQ_PH_MM : DspMMRel, ADDQ_PH_MM_ENC, ADDQ_PH_DESC; +def ADDQ_S_PH_MM : DspMMRel, ADDQ_S_PH_MM_ENC, ADDQ_S_PH_DESC; +def ADDQ_S_W_MM : DspMMRel, ADDQ_S_W_MM_ENC, ADDQ_S_W_DESC; +def ADDU_QB_MM : DspMMRel, ADDU_QB_MM_ENC, ADDU_QB_DESC; +def ADDU_S_QB_MM : DspMMRel, ADDU_S_QB_MM_ENC, ADDU_S_QB_DESC; +def ADDSC_MM : DspMMRel, ADDSC_MM_ENC, ADDSC_DESC; +def ADDWC_MM : DspMMRel, ADDWC_MM_ENC, ADDWC_DESC; +def DPAQ_S_W_PH_MM : DspMMRel, DPAQ_S_W_PH_MM_ENC, DPAQ_S_W_PH_DESC; +def DPAQ_SA_L_W_MM : DspMMRel, DPAQ_SA_L_W_MM_ENC, DPAQ_SA_L_W_DESC; +def DPAU_H_QBL_MM : DspMMRel, DPAU_H_QBL_MM_ENC, DPAU_H_QBL_DESC; +def DPAU_H_QBR_MM : DspMMRel, DPAU_H_QBR_MM_ENC, DPAU_H_QBR_DESC; +def ABSQ_S_PH_MM : DspMMRel, ABSQ_S_PH_MM_ENC, ABSQ_S_PH_MM_DESC; +def ABSQ_S_W_MM : DspMMRel, ABSQ_S_W_MM_ENC, ABSQ_S_W_MM_DESC; +def INSV_MM : DspMMRel, INSV_MM_ENC, INSV_DESC; +def MADD_DSP_MM : DspMMRel, MADD_DSP_MM_ENC, MADD_DSP_DESC; +def MADDU_DSP_MM : DspMMRel, MADDU_DSP_MM_ENC, MADDU_DSP_DESC; +def MSUB_DSP_MM : DspMMRel, MSUB_DSP_MM_ENC, MSUB_DSP_DESC; +def MSUBU_DSP_MM : DspMMRel, MSUBU_DSP_MM_ENC, MSUBU_DSP_DESC; +def MULT_DSP_MM : DspMMRel, MULT_DSP_MM_ENC, MULT_DSP_DESC; +def MULTU_DSP_MM : DspMMRel, MULTU_DSP_MM_ENC, MULTU_DSP_DESC; +def SHLL_PH_MM : DspMMRel, SHLL_PH_MM_ENC, SHLL_PH_MM_DESC; +def SHLL_S_PH_MM : DspMMRel, SHLL_S_PH_MM_ENC, SHLL_S_PH_MM_DESC; +def SHLL_QB_MM : DspMMRel, SHLL_QB_MM_ENC, SHLL_QB_MM_DESC; +def SHLLV_PH_MM : DspMMRel, SHLLV_PH_MM_ENC, SHLLV_PH_MM_DESC; +def SHLLV_S_PH_MM : DspMMRel, SHLLV_S_PH_MM_ENC, SHLLV_S_PH_MM_DESC; +def SHLLV_QB_MM : DspMMRel, SHLLV_QB_MM_ENC, SHLLV_QB_MM_DESC; +def SHLLV_S_W_MM : DspMMRel, SHLLV_S_W_MM_ENC, SHLLV_S_W_MM_DESC; +def SHLL_S_W_MM : DspMMRel, SHLL_S_W_MM_ENC, SHLL_S_W_MM_DESC; +def SHRA_PH_MM : DspMMRel, SHRA_PH_MM_ENC, SHRA_PH_MM_DESC; +def SHRA_R_PH_MM : DspMMRel, SHRA_R_PH_MM_ENC, SHRA_R_PH_MM_DESC; +def SHRAV_PH_MM : DspMMRel, SHRAV_PH_MM_ENC, SHRAV_PH_MM_DESC; +def SHRAV_R_PH_MM : DspMMRel, SHRAV_R_PH_MM_ENC, SHRAV_R_PH_MM_DESC; +def SHRAV_R_W_MM : DspMMRel, SHRAV_R_W_MM_ENC, SHRAV_R_W_MM_DESC; +def SHRA_R_W_MM : DspMMRel, SHRA_R_W_MM_ENC, SHRA_R_W_MM_DESC; +def SHRL_QB_MM : DspMMRel, SHRL_QB_MM_ENC, SHRL_QB_MM_DESC; +def SHRLV_QB_MM : DspMMRel, SHRLV_QB_MM_ENC, SHRLV_QB_MM_DESC; +def PRECEQ_W_PHL_MM : DspMMRel, PRECEQ_W_PHL_MM_ENC, PRECEQ_W_PHL_MM_DESC; +def PRECEQ_W_PHR_MM : DspMMRel, PRECEQ_W_PHR_MM_ENC, PRECEQ_W_PHR_MM_DESC; +def PRECEQU_PH_QBL_MM : DspMMRel, PRECEQU_PH_QBL_MM_ENC, PRECEQU_PH_QBL_MM_DESC; +def PRECEQU_PH_QBLA_MM : DspMMRel, PRECEQU_PH_QBLA_MM_ENC, + PRECEQU_PH_QBLA_MM_DESC; +def PRECEQU_PH_QBR_MM : DspMMRel, PRECEQU_PH_QBR_MM_ENC, PRECEQU_PH_QBR_MM_DESC; +def PRECEQU_PH_QBRA_MM : DspMMRel, PRECEQU_PH_QBRA_MM_ENC, + PRECEQU_PH_QBRA_MM_DESC; +def PRECEU_PH_QBL_MM : DspMMRel, PRECEU_PH_QBL_MM_ENC, PRECEU_PH_QBL_MM_DESC; +def PRECEU_PH_QBLA_MM : DspMMRel, PRECEU_PH_QBLA_MM_ENC, PRECEU_PH_QBLA_MM_DESC; +def PRECEU_PH_QBR_MM : DspMMRel, PRECEU_PH_QBR_MM_ENC, PRECEU_PH_QBR_MM_DESC; +def PRECEU_PH_QBRA_MM : DspMMRel, PRECEU_PH_QBRA_MM_ENC, PRECEU_PH_QBRA_MM_DESC; +def SUBQ_PH_MM : DspMMRel, SUBQ_PH_MM_ENC, SUBQ_PH_DESC; +def SUBQ_S_PH_MM : DspMMRel, SUBQ_S_PH_MM_ENC, SUBQ_S_PH_DESC; +def SUBQ_S_W_MM : DspMMRel, SUBQ_S_W_MM_ENC, SUBQ_S_W_DESC; +def SUBU_QB_MM : DspMMRel, SUBU_QB_MM_ENC, SUBU_QB_DESC; +def SUBU_S_QB_MM : DspMMRel, SUBU_S_QB_MM_ENC, SUBU_S_QB_DESC; +def EXTP_MM : DspMMRel, EXTP_MM_ENC, EXTP_MM_DESC; +def EXTPDP_MM : DspMMRel, EXTPDP_MM_ENC, EXTPDP_MM_DESC; +def EXTPDPV_MM : DspMMRel, EXTPDPV_MM_ENC, EXTPDPV_MM_DESC; +def EXTPV_MM : DspMMRel, EXTPV_MM_ENC, EXTPV_MM_DESC; +def EXTR_W_MM : DspMMRel, EXTR_W_MM_ENC, EXTR_W_MM_DESC; +def EXTR_R_W_MM : DspMMRel, EXTR_R_W_MM_ENC, EXTR_R_W_MM_DESC; +def EXTR_RS_W_MM : DspMMRel, EXTR_RS_W_MM_ENC, EXTR_RS_W_MM_DESC; +def EXTR_S_H_MM : DspMMRel, EXTR_S_H_MM_ENC, EXTR_S_H_MM_DESC; +def EXTRV_W_MM : DspMMRel, EXTRV_W_MM_ENC, EXTRV_W_MM_DESC; +def EXTRV_R_W_MM : DspMMRel, EXTRV_R_W_MM_ENC, EXTRV_R_W_MM_DESC; +def EXTRV_RS_W_MM : DspMMRel, EXTRV_RS_W_MM_ENC, EXTRV_RS_W_MM_DESC; +def EXTRV_S_H_MM : DspMMRel, EXTRV_S_H_MM_ENC, EXTRV_S_H_MM_DESC; +def DPSQ_S_W_PH_MM : DspMMRel, DPSQ_S_W_PH_MM_ENC, DPSQ_S_W_PH_DESC; +def DPSQ_SA_L_W_MM : DspMMRel, DPSQ_SA_L_W_MM_ENC, DPSQ_SA_L_W_DESC; +def DPSU_H_QBL_MM : DspMMRel, DPSU_H_QBL_MM_ENC, DPSU_H_QBL_DESC; +def DPSU_H_QBR_MM : DspMMRel, DPSU_H_QBR_MM_ENC, DPSU_H_QBR_DESC; +def MULEQ_S_W_PHL_MM : DspMMRel, MULEQ_S_W_PHL_MM_ENC, MULEQ_S_W_PHL_DESC; +def MULEQ_S_W_PHR_MM : DspMMRel, MULEQ_S_W_PHR_MM_ENC, MULEQ_S_W_PHR_DESC; +def MULEU_S_PH_QBL_MM : DspMMRel, MULEU_S_PH_QBL_MM_ENC, MULEU_S_PH_QBL_DESC; +def MULEU_S_PH_QBR_MM : DspMMRel, MULEU_S_PH_QBR_MM_ENC, MULEU_S_PH_QBR_DESC; +def MULQ_RS_PH_MM : DspMMRel, MULQ_RS_PH_MM_ENC, MULQ_RS_PH_DESC; +def PRECRQ_PH_W_MM : DspMMRel, PRECRQ_PH_W_MM_ENC, PRECRQ_PH_W_DESC; +def PRECRQ_QB_PH_MM : DspMMRel, PRECRQ_QB_PH_MM_ENC, PRECRQ_QB_PH_DESC; +def PRECRQU_S_QB_PH_MM : DspMMRel, PRECRQU_S_QB_PH_MM_ENC, PRECRQU_S_QB_PH_DESC; +def PRECRQ_RS_PH_W_MM : DspMMRel, PRECRQ_RS_PH_W_MM_ENC, PRECRQ_RS_PH_W_DESC; +def LBUX_MM : DspMMRel, LBUX_MM_ENC, LBUX_DESC; +def LHX_MM : DspMMRel, LHX_MM_ENC, LHX_DESC; +def LWX_MM : DspMMRel, LWX_MM_ENC, LWX_DESC; +def MAQ_S_W_PHL_MM : DspMMRel, MAQ_S_W_PHL_MM_ENC, MAQ_S_W_PHL_DESC; +def MAQ_SA_W_PHL_MM : DspMMRel, MAQ_SA_W_PHL_MM_ENC, MAQ_SA_W_PHL_DESC; +def MAQ_S_W_PHR_MM : DspMMRel, MAQ_S_W_PHR_MM_ENC, MAQ_S_W_PHR_DESC; +def MAQ_SA_W_PHR_MM : DspMMRel, MAQ_SA_W_PHR_MM_ENC, MAQ_SA_W_PHR_DESC; +def MFHI_DSP_MM : DspMMRel, MFHI_MM_ENC, MFHI_MM_DESC; +def MFLO_DSP_MM : DspMMRel, MFLO_MM_ENC, MFLO_MM_DESC; +def MTHI_DSP_MM : DspMMRel, MTHI_MM_ENC, MTHI_DESC; +def MTLO_DSP_MM : DspMMRel, MTLO_MM_ENC, MTLO_DESC; +def RADDU_W_QB_MM : DspMMRel, RADDU_W_QB_MM_ENC, RADDU_W_QB_MM_DESC; +def RDDSP_MM : DspMMRel, RDDSP_MM_ENC, RDDSP_MM_DESC; +def REPL_PH_MM : DspMMRel, REPL_PH_MM_ENC, REPL_PH_DESC; +def REPL_QB_MM : DspMMRel, REPL_QB_MM_ENC, REPL_QB_MM_DESC; +def REPLV_PH_MM : DspMMRel, REPLV_PH_MM_ENC, REPLV_PH_MM_DESC; +def REPLV_QB_MM : DspMMRel, REPLV_QB_MM_ENC, REPLV_QB_MM_DESC; +def MTHLIP_MM : DspMMRel, MTHLIP_MM_ENC, MTHLIP_DESC; +def PACKRL_PH_MM : DspMMRel, PACKRL_PH_MM_ENC, PACKRL_PH_DESC; +def PICK_PH_MM : DspMMRel, PICK_PH_MM_ENC, PICK_PH_DESC; +def PICK_QB_MM : DspMMRel, PICK_QB_MM_ENC, PICK_QB_DESC; +def SHILO_MM : DspMMRel, SHILO_MM_ENC, SHILO_DESC; +def SHILOV_MM : DspMMRel, SHILOV_MM_ENC, SHILOV_DESC; +def WRDSP_MM : DspMMRel, WRDSP_MM_ENC, WRDSP_MM_DESC; +// microMIPS DSP Rev 2 +def ABSQ_S_QB_MMR2 : DspMMRel, ABSQ_S_QB_MMR2_ENC, ABSQ_S_QB_MMR2_DESC, + ISA_DSPR2; +def ADDQH_PH_MMR2 : DspMMRel, ADDQH_PH_MMR2_ENC, ADDQH_PH_DESC, ISA_DSPR2; +def ADDQH_R_PH_MMR2 : DspMMRel, ADDQH_R_PH_MMR2_ENC, ADDQH_R_PH_DESC, ISA_DSPR2; +def ADDQH_W_MMR2 : DspMMRel, ADDQH_W_MMR2_ENC, ADDQH_W_DESC, ISA_DSPR2; +def ADDQH_R_W_MMR2 : DspMMRel, ADDQH_R_W_MMR2_ENC, ADDQH_R_W_DESC, ISA_DSPR2; +def ADDU_PH_MMR2 : DspMMRel, ADDU_PH_MMR2_ENC, ADDU_PH_DESC, ISA_DSPR2; +def ADDU_S_PH_MMR2 : DspMMRel, ADDU_S_PH_MMR2_ENC, ADDU_S_PH_DESC, ISA_DSPR2; +def ADDUH_QB_MMR2 : DspMMRel, ADDUH_QB_MMR2_ENC, ADDUH_QB_DESC, ISA_DSPR2; +def ADDUH_R_QB_MMR2 : DspMMRel, ADDUH_R_QB_MMR2_ENC, ADDUH_R_QB_DESC, ISA_DSPR2; +def DPA_W_PH_MMR2 : DspMMRel, DPA_W_PH_MMR2_ENC, DPA_W_PH_DESC, ISA_DSPR2; +def DPAQX_S_W_PH_MMR2 : DspMMRel, DPAQX_S_W_PH_MMR2_ENC, DPAQX_S_W_PH_DESC, + ISA_DSPR2; +def DPAQX_SA_W_PH_MMR2 : DspMMRel, DPAQX_SA_W_PH_MMR2_ENC, DPAQX_SA_W_PH_DESC, + ISA_DSPR2; +def DPAX_W_PH_MMR2 : DspMMRel, DPAX_W_PH_MMR2_ENC, DPAX_W_PH_DESC, ISA_DSPR2; +def SHRA_QB_MMR2 : DspMMRel, SHRA_QB_MMR2_ENC, SHRA_QB_MMR2_DESC, ISA_DSPR2; +def SHRA_R_QB_MMR2 : DspMMRel, SHRA_R_QB_MMR2_ENC, SHRA_R_QB_MMR2_DESC, + ISA_DSPR2; +def SHRAV_QB_MMR2 : DspMMRel, SHRAV_QB_MMR2_ENC, SHRAV_QB_MMR2_DESC, ISA_DSPR2; +def SHRAV_R_QB_MMR2 : DspMMRel, SHRAV_R_QB_MMR2_ENC, SHRAV_R_QB_MMR2_DESC, + ISA_DSPR2; +def SHRL_PH_MMR2 : DspMMRel, SHRL_PH_MMR2_ENC, SHRL_PH_MMR2_DESC, ISA_DSPR2; +def SHRLV_PH_MMR2 : DspMMRel, SHRLV_PH_MMR2_ENC, SHRLV_PH_MMR2_DESC, ISA_DSPR2; +def SUBQH_PH_MMR2 : DspMMRel, SUBQH_PH_MMR2_ENC, SUBQH_PH_DESC, ISA_DSPR2; +def SUBQH_R_PH_MMR2 : DspMMRel, SUBQH_R_PH_MMR2_ENC, SUBQH_R_PH_DESC, ISA_DSPR2; +def SUBQH_W_MMR2 : DspMMRel, SUBQH_W_MMR2_ENC, SUBQH_W_DESC, ISA_DSPR2; +def SUBQH_R_W_MMR2 : DspMMRel, SUBQH_R_W_MMR2_ENC, SUBQH_R_W_DESC, ISA_DSPR2; +def SUBU_PH_MMR2 : DspMMRel, SUBU_PH_MMR2_ENC, SUBU_PH_DESC, ISA_DSPR2; +def SUBU_S_PH_MMR2 : DspMMRel, SUBU_S_PH_MMR2_ENC, SUBU_S_PH_DESC, ISA_DSPR2; +def SUBUH_QB_MMR2 : DspMMRel, SUBUH_QB_MMR2_ENC, SUBUH_QB_DESC, ISA_DSPR2; +def SUBUH_R_QB_MMR2 : DspMMRel, SUBUH_R_QB_MMR2_ENC, SUBUH_R_QB_DESC, ISA_DSPR2; +def DPS_W_PH_MMR2 : DspMMRel, DPS_W_PH_MMR2_ENC, DPS_W_PH_DESC, ISA_DSPR2; +def DPSQX_S_W_PH_MMR2 : DspMMRel, DPSQX_S_W_PH_MMR2_ENC, DPSQX_S_W_PH_DESC, + ISA_DSPR2; +def DPSQX_SA_W_PH_MMR2 : DspMMRel, DPSQX_SA_W_PH_MMR2_ENC, DPSQX_SA_W_PH_DESC, + ISA_DSPR2; +def DPSX_W_PH_MMR2 : DspMMRel, DPSX_W_PH_MMR2_ENC, DPSX_W_PH_DESC, ISA_DSPR2; +def MUL_PH_MMR2 : DspMMRel, MUL_PH_MMR2_ENC, MUL_PH_DESC, ISA_DSPR2; +def MUL_S_PH_MMR2 : DspMMRel, MUL_S_PH_MMR2_ENC, MUL_S_PH_DESC, ISA_DSPR2; +def MULQ_RS_W_MMR2 : DspMMRel, MULQ_RS_W_MMR2_ENC, MULQ_RS_W_DESC, ISA_DSPR2; +def MULQ_S_PH_MMR2 : DspMMRel, MULQ_S_PH_MMR2_ENC, MULQ_S_PH_DESC, ISA_DSPR2; +def MULQ_S_W_MMR2 : DspMMRel, MULQ_S_W_MMR2_ENC, MULQ_S_W_DESC, ISA_DSPR2; +def PRECR_QB_PH_MMR2 : DspMMRel, PRECR_QB_PH_MMR2_ENC, PRECR_QB_PH_DESC, + ISA_DSPR2; +def PRECR_SRA_PH_W_MMR2 : DspMMRel, PRECR_SRA_PH_W_MMR2_ENC, + PRECR_SRA_PH_W_DESC, ISA_DSPR2; +def PRECR_SRA_R_PH_W_MMR2 : DspMMRel, PRECR_SRA_R_PH_W_MMR2_ENC, + PRECR_SRA_R_PH_W_DESC, ISA_DSPR2; +def PREPEND_MMR2 : DspMMRel, PREPEND_MMR2_ENC, PREPEND_DESC, ISA_DSPR2; + +// Instruction alias. +def : MMDSPInstAlias<"wrdsp $rt", (WRDSP_MM GPR32Opnd:$rt, 0x1F), 1>; diff --git a/contrib/llvm/lib/Target/Mips/MicroMipsInstrFPU.td b/contrib/llvm/lib/Target/Mips/MicroMipsInstrFPU.td new file mode 100644 index 0000000..756e6c9 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MicroMipsInstrFPU.td @@ -0,0 +1,150 @@ +let isCodeGenOnly = 1, Predicates = [InMicroMips] in { +def FADD_S_MM : MMRel, ADDS_FT<"add.s", FGR32Opnd, II_ADD_S, 1, fadd>, + ADDS_FM_MM<0, 0x30>; +def FDIV_S_MM : MMRel, ADDS_FT<"div.s", FGR32Opnd, II_DIV_S, 0, fdiv>, + ADDS_FM_MM<0, 0xf0>; +def FMUL_S_MM : MMRel, ADDS_FT<"mul.s", FGR32Opnd, II_MUL_S, 1, fmul>, + ADDS_FM_MM<0, 0xb0>; +def FSUB_S_MM : MMRel, ADDS_FT<"sub.s", FGR32Opnd, II_SUB_S, 0, fsub>, + ADDS_FM_MM<0, 0x70>; + +def FADD_MM : MMRel, ADDS_FT<"add.d", AFGR64Opnd, II_ADD_D, 1, fadd>, + ADDS_FM_MM<1, 0x30>; +def FDIV_MM : MMRel, ADDS_FT<"div.d", AFGR64Opnd, II_DIV_D, 0, fdiv>, + ADDS_FM_MM<1, 0xf0>; +def FMUL_MM : MMRel, ADDS_FT<"mul.d", AFGR64Opnd, II_MUL_D, 1, fmul>, + ADDS_FM_MM<1, 0xb0>; +def FSUB_MM : MMRel, ADDS_FT<"sub.d", AFGR64Opnd, II_SUB_D, 0, fsub>, + ADDS_FM_MM<1, 0x70>; + +def LWC1_MM : MMRel, LW_FT<"lwc1", FGR32Opnd, II_LWC1, load>, LW_FM_MM<0x27>; +def SWC1_MM : MMRel, SW_FT<"swc1", FGR32Opnd, II_SWC1, store>, + LW_FM_MM<0x26>; +def LDC1_MM : MMRel, LW_FT<"ldc1", AFGR64Opnd, II_LDC1, load>, LW_FM_MM<0x2f>; +def SDC1_MM : MMRel, SW_FT<"sdc1", AFGR64Opnd, II_SDC1, store>, + LW_FM_MM<0x2e>; +def LWXC1_MM : MMRel, LWXC1_FT<"lwxc1", FGR32Opnd, II_LWXC1, load>, + LWXC1_FM_MM<0x48>, INSN_MIPS4_32R2_NOT_32R6_64R6; +def SWXC1_MM : MMRel, SWXC1_FT<"swxc1", FGR32Opnd, II_SWXC1, store>, + SWXC1_FM_MM<0x88>, INSN_MIPS4_32R2_NOT_32R6_64R6; +def LUXC1_MM : MMRel, LWXC1_FT<"luxc1", AFGR64Opnd, II_LUXC1>, + LWXC1_FM_MM<0x148>, INSN_MIPS5_32R2_NOT_32R6_64R6; +def SUXC1_MM : MMRel, SWXC1_FT<"suxc1", AFGR64Opnd, II_SUXC1>, + SWXC1_FM_MM<0x188>, INSN_MIPS5_32R2_NOT_32R6_64R6; + +def FCMP_S32_MM : MMRel, CEQS_FT<"s", FGR32, II_C_CC_S, MipsFPCmp>, + CEQS_FM_MM<0>; +def FCMP_D32_MM : MMRel, CEQS_FT<"d", AFGR64, II_C_CC_D, MipsFPCmp>, + CEQS_FM_MM<1>; + +def BC1F_MM : MMRel, BC1F_FT<"bc1f", brtarget_mm, II_BC1F, MIPS_BRANCH_F>, + BC1F_FM_MM<0x1c>, ISA_MIPS1_NOT_32R6_64R6; +def BC1T_MM : MMRel, BC1F_FT<"bc1t", brtarget_mm, II_BC1T, MIPS_BRANCH_T>, + BC1F_FM_MM<0x1d>, ISA_MIPS1_NOT_32R6_64R6; +def CVT_W_S_MM : MMRel, ABSS_FT<"cvt.w.s", FGR32Opnd, FGR32Opnd, II_CVT>, + ROUND_W_FM_MM<0, 0x24>; +def ROUND_W_S_MM : MMRel, StdMMR6Rel, ABSS_FT<"round.w.s", FGR32Opnd, FGR32Opnd, II_ROUND>, + ROUND_W_FM_MM<0, 0xec>; + +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, StdMMR6Rel, ABSS_FT<"round.w.d", FGR32Opnd, AFGR64Opnd, II_ROUND>, + ROUND_W_FM_MM<1, 0xec>; +def TRUNC_W_MM : MMRel, ABSS_FT<"trunc.w.d", FGR32Opnd, AFGR64Opnd, II_TRUNC>, + ROUND_W_FM_MM<1, 0xac>; + +def FSQRT_MM : MMRel, ABSS_FT<"sqrt.d", AFGR64Opnd, AFGR64Opnd, II_SQRT_D, + fsqrt>, ROUND_W_FM_MM<1, 0x28>; + +def CVT_L_S_MM : MMRel, ABSS_FT<"cvt.l.s", FGR64Opnd, FGR32Opnd, II_CVT>, + ROUND_W_FM_MM<0, 0x4>, INSN_MIPS3_32R2; +def CVT_L_D64_MM : MMRel, ABSS_FT<"cvt.l.d", FGR64Opnd, FGR64Opnd, II_CVT>, + ROUND_W_FM_MM<1, 0x4>, INSN_MIPS3_32R2; + +def FABS_S_MM : MMRel, ABSS_FT<"abs.s", FGR32Opnd, FGR32Opnd, II_ABS, fabs>, + ABS_FM_MM<0, 0xd>; +def FMOV_S_MM : MMRel, ABSS_FT<"mov.s", FGR32Opnd, FGR32Opnd, II_MOV_S>, + ABS_FM_MM<0, 0x1>; +def FNEG_S_MM : MMRel, ABSS_FT<"neg.s", FGR32Opnd, FGR32Opnd, II_NEG, fneg>, + ABS_FM_MM<0, 0x2d>; +def CVT_D_S_MM : MMRel, ABSS_FT<"cvt.d.s", AFGR64Opnd, FGR32Opnd, II_CVT>, + ABS_FM_MM<0, 0x4d>; +def CVT_D32_W_MM : MMRel, ABSS_FT<"cvt.d.w", AFGR64Opnd, FGR32Opnd, II_CVT>, + ABS_FM_MM<1, 0x4d>; +def CVT_S_D32_MM : MMRel, ABSS_FT<"cvt.s.d", FGR32Opnd, AFGR64Opnd, II_CVT>, + ABS_FM_MM<0, 0x6d>; +def CVT_S_W_MM : MMRel, ABSS_FT<"cvt.s.w", FGR32Opnd, FGR32Opnd, II_CVT>, + ABS_FM_MM<1, 0x6d>; + +def FABS_MM : MMRel, ABSS_FT<"abs.d", AFGR64Opnd, AFGR64Opnd, II_ABS, fabs>, + ABS_FM_MM<1, 0xd>; +def FNEG_MM : MMRel, ABSS_FT<"neg.d", AFGR64Opnd, AFGR64Opnd, II_NEG, fneg>, + ABS_FM_MM<1, 0x2d>; + +def FMOV_D32_MM : MMRel, ABSS_FT<"mov.d", AFGR64Opnd, AFGR64Opnd, II_MOV_D>, + ABS_FM_MM<1, 0x1>, FGR_32; + +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, AFGR64Opnd, II_MFHC1>, + MFC1_FM_MM<0xc0>, ISA_MIPS32R2, FGR_32; +def MTHC1_MM : MMRel, MTC1_64_FT<"mthc1", AFGR64Opnd, GPR32Opnd, II_MTHC1>, + MFC1_FM_MM<0xe0>, ISA_MIPS32R2, FGR_32; + +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>; +} + +let AdditionalPredicates = [InMicroMips] in { + def FLOOR_W_S_MM : MMRel, ABSS_FT<"floor.w.s", FGR32Opnd, FGR32Opnd, + II_FLOOR>, ROUND_W_FM_MM<0, 0x2c>; + def TRUNC_W_S_MM : MMRel, StdMMR6Rel, ABSS_FT<"trunc.w.s", FGR32Opnd, + FGR32Opnd, II_TRUNC>, ROUND_W_FM_MM<0, 0xac>; + def CEIL_W_S_MM : MMRel, ABSS_FT<"ceil.w.s", FGR32Opnd, FGR32Opnd, II_CEIL>, + ROUND_W_FM_MM<0, 0x6c>; + def FSQRT_S_MM : MMRel, ABSS_FT<"sqrt.s", FGR32Opnd, FGR32Opnd, II_SQRT_S, + fsqrt>, ROUND_W_FM_MM<0, 0x28>; +} diff --git a/contrib/llvm/lib/Target/Mips/MicroMipsInstrFormats.td b/contrib/llvm/lib/Target/Mips/MicroMipsInstrFormats.td new file mode 100644 index 0000000..b736367 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MicroMipsInstrFormats.td @@ -0,0 +1,1024 @@ +//===----------------------------------------------------------------------===// +// 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 ARITH_FM_MM16<bit funct> { + bits<3> rd; + bits<3> rt; + bits<3> rs; + + bits<16> Inst; + + let Inst{15-10} = 0x01; + let Inst{9-7} = rd; + let Inst{6-4} = rt; + let Inst{3-1} = rs; + let Inst{0} = funct; +} + +class ANDI_FM_MM16<bits<6> funct> { + bits<3> rd; + bits<3> rs; + bits<4> imm; + + bits<16> Inst; + + let Inst{15-10} = funct; + let Inst{9-7} = rd; + let Inst{6-4} = rs; + let Inst{3-0} = imm; +} + +class LOGIC_FM_MM16<bits<4> funct> { + bits<3> rt; + bits<3> rs; + + bits<16> Inst; + + let Inst{15-10} = 0x11; + let Inst{9-6} = funct; + let Inst{5-3} = rt; + let Inst{2-0} = rs; +} + +class SHIFT_FM_MM16<bits<1> funct> { + bits<3> rd; + bits<3> rt; + bits<3> shamt; + + bits<16> Inst; + + let Inst{15-10} = 0x09; + let Inst{9-7} = rd; + let Inst{6-4} = rt; + let Inst{3-1} = shamt; + let Inst{0} = funct; +} + +class ADDIUR2_FM_MM16 { + bits<3> rd; + bits<3> rs; + bits<3> imm; + + bits<16> Inst; + + let Inst{15-10} = 0x1b; + let Inst{9-7} = rd; + let Inst{6-4} = rs; + let Inst{3-1} = imm; + let Inst{0} = 0; +} + +class LOAD_STORE_FM_MM16<bits<6> op> { + bits<3> rt; + bits<7> addr; + + bits<16> Inst; + + let Inst{15-10} = op; + let Inst{9-7} = rt; + let Inst{6-4} = addr{6-4}; + let Inst{3-0} = addr{3-0}; +} + +class LOAD_STORE_SP_FM_MM16<bits<6> op> { + bits<5> rt; + bits<5> offset; + + bits<16> Inst; + + let Inst{15-10} = op; + let Inst{9-5} = rt; + let Inst{4-0} = offset; +} + +class LOAD_GP_FM_MM16<bits<6> op> { + bits<3> rt; + bits<7> offset; + + bits<16> Inst; + + let Inst{15-10} = op; + let Inst{9-7} = rt; + let Inst{6-0} = offset; +} + +class ADDIUS5_FM_MM16 { + bits<5> rd; + bits<4> imm; + + bits<16> Inst; + + let Inst{15-10} = 0x13; + let Inst{9-5} = rd; + let Inst{4-1} = imm; + let Inst{0} = 0; +} + +class ADDIUSP_FM_MM16 { + bits<9> imm; + + bits<16> Inst; + + let Inst{15-10} = 0x13; + let Inst{9-1} = imm; + let Inst{0} = 1; +} + +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 LI_FM_MM16 { + bits<3> rd; + bits<7> imm; + + bits<16> Inst; + + let Inst{15-10} = 0x3b; + let Inst{9-7} = rd; + let Inst{6-0} = imm; +} + +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; +} + +class JRADDIUSP_FM_MM16<bits<5> op> { + bits<5> rs; + bits<5> imm; + + bits<16> Inst; + + let Inst{15-10} = 0x11; + let Inst{9-5} = op; + let Inst{4-0} = imm; +} + +class ADDIUR1SP_FM_MM16 { + bits<3> rd; + bits<6> imm; + + bits<16> Inst; + + let Inst{15-10} = 0x1b; + let Inst{9-7} = rd; + let Inst{6-1} = imm; + let Inst{0} = 1; +} + +class BRKSDBBP16_FM_MM<bits<6> op> { + bits<4> code_; + bits<16> Inst; + + let Inst{15-10} = 0x11; + let Inst{9-4} = op; + let Inst{3-0} = code_; +} + +class BEQNEZ_FM_MM16<bits<6> op> { + bits<3> rs; + bits<7> offset; + + bits<16> Inst; + + let Inst{15-10} = op; + let Inst{9-7} = rs; + let Inst{6-0} = offset; +} + +class B16_FM { + bits<10> offset; + + bits<16> Inst; + + let Inst{15-10} = 0x33; + let Inst{9-0} = offset; +} + +class MOVEP_FM_MM16 { + bits<3> dst_regs; + bits<3> rt; + bits<3> rs; + + bits<16> Inst; + + let Inst{15-10} = 0x21; + let Inst{9-7} = dst_regs; + let Inst{6-4} = rt; + let Inst{3-1} = rs; + let Inst{0} = 0; +} + +//===----------------------------------------------------------------------===// +// MicroMIPS 32-bit Instruction Formats +//===----------------------------------------------------------------------===// + +class MMArch { + string Arch = "micromips"; + list<dag> Pattern = []; +} + +class ADD_FM_MM<bits<6> op, bits<10> funct> : MMArch { + bits<5> rt; + bits<5> rs; + bits<5> rd; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-11} = rd; + let Inst{10} = 0; + let Inst{9-0} = funct; +} + +class ADDI_FM_MM<bits<6> op> : MMArch { + bits<5> rs; + bits<5> rt; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-0} = imm16; +} + +class SLTI_FM_MM<bits<6> op> : MMArch { + bits<5> rt; + bits<5> rs; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-0} = imm16; +} + +class LUI_FM_MM : MMArch { + bits<5> rt; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = 0x10; + let Inst{25-21} = 0xd; + let Inst{20-16} = rt; + let Inst{15-0} = imm16; +} + +class MULT_FM_MM<bits<10> funct> : MMArch { + bits<5> rs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-6} = funct; + let Inst{5-0} = 0x3c; +} + +class SRA_FM_MM<bits<10> funct, bit rotate> : MMArch { + bits<5> rd; + bits<5> rt; + bits<5> shamt; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rd; + let Inst{20-16} = rt; + let Inst{15-11} = shamt; + let Inst{10} = rotate; + let Inst{9-0} = funct; +} + +class SRLV_FM_MM<bits<10> funct, bit rotate> : MMArch { + bits<5> rd; + bits<5> rt; + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-11} = rd; + let Inst{10} = rotate; + let Inst{9-0} = funct; +} + +class LW_FM_MM<bits<6> op> : MMArch { + bits<5> rt; + bits<21> addr; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rt; + let Inst{20-16} = addr{20-16}; + let Inst{15-0} = addr{15-0}; +} + +class POOL32C_LHUE_FM_MM<bits<6> op, bits<4> fmt, bits<3> funct> : MMArch { + bits<5> rt; + bits<21> addr; + bits<5> base = addr{20-16}; + bits<9> offset = addr{8-0}; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rt; + let Inst{20-16} = base; + let Inst{15-12} = fmt; + let Inst{11-9} = funct; + let Inst{8-0} = offset; +} + +class LWL_FM_MM<bits<4> funct> { + bits<5> rt; + bits<21> addr; + + bits<32> Inst; + + let Inst{31-26} = 0x18; + let Inst{25-21} = rt; + let Inst{20-16} = addr{20-16}; + let Inst{15-12} = funct; + let Inst{11-0} = addr{11-0}; +} + +class POOL32C_STEVA_LDEVA_FM_MM<bits<4> type, bits<3> funct> { + bits<5> rt; + bits<21> addr; + bits<5> base = addr{20-16}; + bits<9> offset = addr{8-0}; + + bits<32> Inst; + + let Inst{31-26} = 0x18; + let Inst{25-21} = rt; + let Inst{20-16} = base; + let Inst{15-12} = type; + let Inst{11-9} = funct; + let Inst{8-0} = offset; +} + +class CMov_F_I_FM_MM<bits<7> func> : MMArch { + bits<5> rd; + bits<5> rs; + bits<3> fcc; + + bits<32> Inst; + + let Inst{31-26} = 0x15; + let Inst{25-21} = rd; + let Inst{20-16} = rs; + let Inst{15-13} = fcc; + let Inst{12-6} = func; + let Inst{5-0} = 0x3b; +} + +class MTLO_FM_MM<bits<10> funct> : MMArch { + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = 0x00; + let Inst{20-16} = rs; + let Inst{15-6} = funct; + let Inst{5-0} = 0x3c; +} + +class MFLO_FM_MM<bits<10> funct> : MMArch { + bits<5> rd; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = 0x00; + let Inst{20-16} = rd; + let Inst{15-6} = funct; + let Inst{5-0} = 0x3c; +} + +class CLO_FM_MM<bits<10> funct> : MMArch { + bits<5> rd; + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = rd; + let Inst{20-16} = rs; + let Inst{15-6} = funct; + let Inst{5-0} = 0x3c; +} + +class SEB_FM_MM<bits<10> funct> : MMArch { + bits<5> rd; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = rd; + let Inst{20-16} = rt; + let Inst{15-6} = funct; + let Inst{5-0} = 0x3c; +} + +class EXT_FM_MM<bits<6> funct> : MMArch { + bits<5> rt; + bits<5> rs; + bits<5> pos; + bits<5> size; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-11} = size; + let Inst{10-6} = pos; + let Inst{5-0} = funct; +} + +class J_FM_MM<bits<6> op> : MMArch { + bits<26> target; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-0} = target; +} + +class JR_FM_MM<bits<8> funct> : MMArch { + bits<5> rs; + + bits<32> Inst; + + let Inst{31-21} = 0x00; + let Inst{20-16} = rs; + let Inst{15-14} = 0x0; + let Inst{13-6} = funct; + let Inst{5-0} = 0x3c; +} + +class JALR_FM_MM<bits<10> funct> { + bits<5> rs; + bits<5> rd; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = rd; + let Inst{20-16} = rs; + let Inst{15-6} = funct; + let Inst{5-0} = 0x3c; +} + +class BEQ_FM_MM<bits<6> op> : MMArch { + bits<5> rs; + bits<5> rt; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-0} = offset; +} + +class BGEZ_FM_MM<bits<5> funct> : MMArch { + bits<5> rs; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = 0x10; + let Inst{25-21} = funct; + let Inst{20-16} = rs; + let Inst{15-0} = offset; +} + +class BGEZAL_FM_MM<bits<5> funct> : MMArch { + bits<5> rs; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = 0x10; + let Inst{25-21} = funct; + let Inst{20-16} = rs; + let Inst{15-0} = offset; +} + +class 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; + bits<4> code_; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-12} = code_; + let Inst{11-6} = funct; + let Inst{5-0} = 0x3c; +} + +class TEQI_FM_MM<bits<5> funct> : MMArch { + bits<5> rs; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = 0x10; + let Inst{25-21} = funct; + let Inst{20-16} = rs; + let Inst{15-0} = imm16; +} + +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 LLE_FM_MM<bits<4> funct> { + bits<5> rt; + bits<21> addr; + bits<5> base = addr{20-16}; + bits<9> offset = addr{8-0}; + + bits<32> Inst; + + let Inst{31-26} = 0x18; + let Inst{25-21} = rt; + let Inst{20-16} = base; + let Inst{15-12} = funct; + let Inst{11-9} = 0x6; + let Inst{8-0} = offset; +} + +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; +} + +class COMPACT_BRANCH_FM_MM<bits<5> funct> { + bits<5> rs; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = 0x10; + let Inst{25-21} = funct; + let Inst{20-16} = rs; + let Inst{15-0} = offset; +} + +class COP0_TLB_FM_MM<bits<10> op> : MMArch { + bits<32> Inst; + + let Inst{31-26} = 0x0; + let Inst{25-16} = 0x0; + let Inst{15-6} = op; + let Inst{5-0} = 0x3c; +} + +class SDBBP_FM_MM : MMArch { + bits<10> code_; + + bits<32> Inst; + + let Inst{31-26} = 0x0; + let Inst{25-16} = code_; + let Inst{15-6} = 0x36d; + let Inst{5-0} = 0x3c; +} + +class RDHWR_FM_MM : MMArch { + bits<5> rt; + bits<5> rd; + + bits<32> Inst; + + let Inst{31-26} = 0x0; + let Inst{25-21} = rt; + let Inst{20-16} = rd; + let Inst{15-6} = 0x1ac; + let Inst{5-0} = 0x3c; +} + +class LWXS_FM_MM<bits<10> funct> { + bits<5> rd; + bits<5> base; + bits<5> index; + + bits<32> Inst; + + let Inst{31-26} = 0x0; + let Inst{25-21} = index; + let Inst{20-16} = base; + let Inst{15-11} = rd; + let Inst{10} = 0; + let Inst{9-0} = funct; +} + +class LWM_FM_MM<bits<4> funct> : MMArch { + bits<5> rt; + bits<21> addr; + + bits<32> Inst; + + let Inst{31-26} = 0x8; + 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 LWM_FM_MM16<bits<4> funct> : MMArch, PredicateControl { + bits<2> rt; + bits<4> addr; + + bits<16> Inst; + + let Inst{15-10} = 0x11; + let Inst{9-6} = funct; + let Inst{5-4} = rt; + let Inst{3-0} = addr; +} + +class CACHE_PREF_FM_MM<bits<6> op, bits<4> funct> : MMArch { + bits<21> addr; + bits<5> hint; + bits<5> base = addr{20-16}; + bits<12> offset = addr{11-0}; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = hint; + let Inst{20-16} = base; + let Inst{15-12} = funct; + let Inst{11-0} = offset; +} + +class CACHE_PREFE_FM_MM<bits<6> op, bits<3> funct> : MMArch { + bits<21> addr; + bits<5> hint; + bits<5> base = addr{20-16}; + bits<9> offset = addr{8-0}; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = hint; + let Inst{20-16} = base; + let Inst{15-12} = 0xA; + let Inst{11-9} = funct; + let Inst{8-0} = offset; +} + +class POOL32F_PREFX_FM_MM<bits<6> op, bits<9> funct> : MMArch { + bits<5> index; + bits<5> base; + bits<5> hint; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = index; + let Inst{20-16} = base; + let Inst{15-11} = hint; + let Inst{10-9} = 0x0; + let Inst{8-0} = funct; +} + +class BARRIER_FM_MM<bits<5> op> : MMArch { + bits<32> Inst; + + let Inst{31-26} = 0x0; + let Inst{25-21} = 0x0; + let Inst{20-16} = 0x0; + let Inst{15-11} = op; + let Inst{10-6} = 0x0; + let Inst{5-0} = 0x0; +} + +class ADDIUPC_FM_MM { + bits<3> rs; + bits<23> imm; + + bits<32> Inst; + + let Inst{31-26} = 0x1e; + let Inst{25-23} = rs; + let Inst{22-0} = imm; +} diff --git a/contrib/llvm/lib/Target/Mips/MicroMipsInstrInfo.td b/contrib/llvm/lib/Target/Mips/MicroMipsInstrInfo.td new file mode 100644 index 0000000..99f0f44 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MicroMipsInstrInfo.td @@ -0,0 +1,1034 @@ +def addrimm12 : ComplexPattern<iPTR, 2, "selectIntAddrMM", [frameindex]>; +def addrimm4lsl2 : ComplexPattern<iPTR, 2, "selectIntAddrLSL2MM", [frameindex]>; + +def simm4 : Operand<i32> { + let DecoderMethod = "DecodeSimm4"; +} +def simm7 : Operand<i32>; +def li_simm7 : Operand<i32> { + let DecoderMethod = "DecodeLiSimm7"; +} + +def simm12 : Operand<i32> { + let DecoderMethod = "DecodeSimm12"; +} + +def uimm6_lsl2 : Operand<i32> { + let EncoderMethod = "getUImm6Lsl2Encoding"; + let DecoderMethod = "DecodeUImm6Lsl2"; +} + +def simm9_addiusp : Operand<i32> { + let EncoderMethod = "getSImm9AddiuspValue"; + let DecoderMethod = "DecodeSimm9SP"; +} + +def uimm3_shift : Operand<i32> { + let EncoderMethod = "getUImm3Mod8Encoding"; + let DecoderMethod = "DecodePOOL16BEncodedField"; +} + +def simm3_lsa2 : Operand<i32> { + let EncoderMethod = "getSImm3Lsa2Value"; + let DecoderMethod = "DecodeAddiur2Simm7"; +} + +def uimm4_andi : Operand<i32> { + let EncoderMethod = "getUImm4AndValue"; + let DecoderMethod = "DecodeANDI16Imm"; +} + +def immSExtAddiur2 : ImmLeaf<i32, [{return Imm == 1 || Imm == -1 || + ((Imm % 4 == 0) && + Imm < 28 && Imm > 0);}]>; + +def immSExtAddius5 : ImmLeaf<i32, [{return Imm >= -8 && Imm <= 7;}]>; + +def immZExtAndi16 : ImmLeaf<i32, + [{return (Imm == 128 || (Imm >= 1 && Imm <= 4) || Imm == 7 || Imm == 8 || + Imm == 15 || Imm == 16 || Imm == 31 || Imm == 32 || Imm == 63 || + Imm == 64 || Imm == 255 || Imm == 32768 || Imm == 65535 );}]>; + +def immZExt2Shift : ImmLeaf<i32, [{return Imm >= 1 && Imm <= 8;}]>; + +def immLi16 : ImmLeaf<i32, [{return Imm >= -1 && Imm <= 126;}]>; + +def MicroMipsMemGPRMM16AsmOperand : AsmOperandClass { + let Name = "MicroMipsMem"; + let RenderMethod = "addMicroMipsMemOperands"; + let ParserMethod = "parseMemOperand"; + let PredicateMethod = "isMemWithGRPMM16Base"; +} + +class mem_mm_4_generic : Operand<i32> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops GPRMM16, simm4); + let OperandType = "OPERAND_MEMORY"; + let ParserMatchClass = MicroMipsMemGPRMM16AsmOperand; +} + +def mem_mm_4 : mem_mm_4_generic { + let EncoderMethod = "getMemEncodingMMImm4"; +} + +def mem_mm_4_lsl1 : mem_mm_4_generic { + let EncoderMethod = "getMemEncodingMMImm4Lsl1"; +} + +def mem_mm_4_lsl2 : mem_mm_4_generic { + let EncoderMethod = "getMemEncodingMMImm4Lsl2"; +} + +def MicroMipsMemSPAsmOperand : AsmOperandClass { + let Name = "MicroMipsMemSP"; + let RenderMethod = "addMemOperands"; + let ParserMethod = "parseMemOperand"; + let PredicateMethod = "isMemWithUimmWordAlignedOffsetSP<7>"; +} + +def mem_mm_sp_imm5_lsl2 : Operand<i32> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops GPR32:$base, simm5:$offset); + let OperandType = "OPERAND_MEMORY"; + let ParserMatchClass = MicroMipsMemSPAsmOperand; + let EncoderMethod = "getMemEncodingMMSPImm5Lsl2"; +} + +def mem_mm_gp_imm7_lsl2 : Operand<i32> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops GPRMM16:$base, simm7:$offset); + let OperandType = "OPERAND_MEMORY"; + let EncoderMethod = "getMemEncodingMMGPImm7Lsl2"; +} + +def mem_mm_9 : Operand<i32> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops GPR32, simm9); + let EncoderMethod = "getMemEncodingMMImm9"; + let ParserMatchClass = MipsMemAsmOperand; + let OperandType = "OPERAND_MEMORY"; +} + +def mem_mm_12 : Operand<i32> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops GPR32, simm12); + let EncoderMethod = "getMemEncodingMMImm12"; + let ParserMatchClass = MipsMemAsmOperand; + let OperandType = "OPERAND_MEMORY"; +} + +def mem_mm_16 : Operand<i32> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops GPR32, simm16); + let EncoderMethod = "getMemEncodingMMImm16"; + let ParserMatchClass = MipsMemAsmOperand; + let OperandType = "OPERAND_MEMORY"; +} + +def MipsMemUimm4AsmOperand : AsmOperandClass { + let Name = "MemOffsetUimm4"; + let SuperClasses = [MipsMemAsmOperand]; + let RenderMethod = "addMemOperands"; + let ParserMethod = "parseMemOperand"; + let PredicateMethod = "isMemWithUimmOffsetSP<6>"; +} + +def mem_mm_4sp : Operand<i32> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops GPR32, uimm8); + let EncoderMethod = "getMemEncodingMMImm4sp"; + let ParserMatchClass = MipsMemUimm4AsmOperand; + let OperandType = "OPERAND_MEMORY"; +} + +def jmptarget_mm : Operand<OtherVT> { + let EncoderMethod = "getJumpTargetOpValueMM"; +} + +def calltarget_mm : Operand<iPTR> { + let EncoderMethod = "getJumpTargetOpValueMM"; +} + +def brtarget7_mm : Operand<OtherVT> { + let EncoderMethod = "getBranchTarget7OpValueMM"; + let OperandType = "OPERAND_PCREL"; + let DecoderMethod = "DecodeBranchTarget7MM"; + let ParserMatchClass = MipsJumpTargetAsmOperand; +} + +def brtarget10_mm : Operand<OtherVT> { + let EncoderMethod = "getBranchTargetOpValueMMPC10"; + let OperandType = "OPERAND_PCREL"; + let DecoderMethod = "DecodeBranchTarget10MM"; + let ParserMatchClass = MipsJumpTargetAsmOperand; +} + +def brtarget_mm : Operand<OtherVT> { + let EncoderMethod = "getBranchTargetOpValueMM"; + let OperandType = "OPERAND_PCREL"; + let DecoderMethod = "DecodeBranchTargetMM"; + let ParserMatchClass = MipsJumpTargetAsmOperand; +} + +def simm23_lsl2 : Operand<i32> { + let EncoderMethod = "getSimm23Lsl2Encoding"; + let DecoderMethod = "DecodeSimm23Lsl2"; +} + +class CompactBranchMM<string opstr, DAGOperand opnd, PatFrag cond_op, + RegisterOperand RO> : + InstSE<(outs), (ins RO:$rs, opnd:$offset), + !strconcat(opstr, "\t$rs, $offset"), [], II_BCCZC, FrmI> { + let isBranch = 1; + let isTerminator = 1; + let hasDelaySlot = 0; + let Defs = [AT]; +} + +let canFoldAsLoad = 1 in +class LoadLeftRightMM<string opstr, SDNode OpNode, RegisterOperand RO, + Operand MemOpnd> : + InstSE<(outs RO:$rt), (ins MemOpnd:$addr, RO:$src), + !strconcat(opstr, "\t$rt, $addr"), + [(set RO:$rt, (OpNode addrimm12:$addr, RO:$src))], + NoItinerary, FrmI> { + let DecoderMethod = "DecodeMemMMImm12"; + string Constraints = "$src = $rt"; +} + +class StoreLeftRightMM<string opstr, SDNode OpNode, RegisterOperand RO, + Operand MemOpnd>: + InstSE<(outs), (ins RO:$rt, MemOpnd:$addr), + !strconcat(opstr, "\t$rt, $addr"), + [(OpNode RO:$rt, addrimm12:$addr)], NoItinerary, FrmI> { + let DecoderMethod = "DecodeMemMMImm12"; +} + +/// A register pair used by movep instruction. +def MovePRegPairAsmOperand : AsmOperandClass { + let Name = "MovePRegPair"; + let ParserMethod = "parseMovePRegPair"; + let PredicateMethod = "isMovePRegPair"; +} + +def movep_regpair : Operand<i32> { + let EncoderMethod = "getMovePRegPairOpValue"; + let ParserMatchClass = MovePRegPairAsmOperand; + let PrintMethod = "printRegisterList"; + let DecoderMethod = "DecodeMovePRegPair"; + let MIOperandInfo = (ops GPR32Opnd, GPR32Opnd); +} + +class MovePMM16<string opstr, RegisterOperand RO> : +MicroMipsInst16<(outs movep_regpair:$dst_regs), (ins RO:$rs, RO:$rt), + !strconcat(opstr, "\t$dst_regs, $rs, $rt"), [], + NoItinerary, FrmR> { + let isReMaterializable = 1; +} + +/// A register pair used by load/store pair instructions. +def RegPairAsmOperand : AsmOperandClass { + let Name = "RegPair"; + let ParserMethod = "parseRegisterPair"; +} + +def regpair : Operand<i32> { + let EncoderMethod = "getRegisterPairOpValue"; + let ParserMatchClass = RegPairAsmOperand; + let PrintMethod = "printRegisterPair"; + let DecoderMethod = "DecodeRegPairOperand"; + let MIOperandInfo = (ops GPR32Opnd, GPR32Opnd); +} + +class StorePairMM<string opstr, InstrItinClass Itin = NoItinerary, + ComplexPattern Addr = addr> : + InstSE<(outs), (ins regpair:$rt, mem_mm_12:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI, opstr> { + let DecoderMethod = "DecodeMemMMImm12"; + let mayStore = 1; +} + +class LoadPairMM<string opstr, InstrItinClass Itin = NoItinerary, + ComplexPattern Addr = addr> : + InstSE<(outs regpair:$rt), (ins mem_mm_12:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI, opstr> { + let DecoderMethod = "DecodeMemMMImm12"; + let mayLoad = 1; +} + +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 LLEBaseMM<string opstr, RegisterOperand RO> : + InstSE<(outs RO:$rt), (ins mem_mm_12:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], NoItinerary, FrmI> { + let DecoderMethod = "DecodeMemMMImm9"; + 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 SCEBaseMM<string opstr, RegisterOperand RO> : + InstSE<(outs RO:$dst), (ins RO:$rt, mem_mm_12:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], NoItinerary, FrmI> { + let DecoderMethod = "DecodeMemMMImm9"; + 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 ArithRMM16<string opstr, RegisterOperand RO, bit isComm = 0, + InstrItinClass Itin = NoItinerary, + SDPatternOperator OpNode = null_frag> : + MicroMipsInst16<(outs RO:$rd), (ins RO:$rs, RO:$rt), + !strconcat(opstr, "\t$rd, $rs, $rt"), + [(set RO:$rd, (OpNode RO:$rs, RO:$rt))], Itin, FrmR> { + let isCommutable = isComm; +} + +class AndImmMM16<string opstr, RegisterOperand RO, + InstrItinClass Itin = NoItinerary> : + MicroMipsInst16<(outs RO:$rd), (ins RO:$rs, uimm4_andi:$imm), + !strconcat(opstr, "\t$rd, $rs, $imm"), [], Itin, FrmI>; + +class LogicRMM16<string opstr, RegisterOperand RO, + InstrItinClass Itin = NoItinerary, + SDPatternOperator OpNode = null_frag> : + MicroMipsInst16<(outs RO:$dst), (ins RO:$rs, RO:$rt), + !strconcat(opstr, "\t$rt, $rs"), + [(set RO:$dst, (OpNode RO:$rs, RO:$rt))], Itin, FrmR> { + let isCommutable = 1; + let Constraints = "$rt = $dst"; +} + +class NotMM16<string opstr, RegisterOperand RO> : + MicroMipsInst16<(outs RO:$rt), (ins RO:$rs), + !strconcat(opstr, "\t$rt, $rs"), + [(set RO:$rt, (not RO:$rs))], NoItinerary, FrmR>; + +class ShiftIMM16<string opstr, Operand ImmOpnd, RegisterOperand RO, + InstrItinClass Itin = NoItinerary> : + MicroMipsInst16<(outs RO:$rd), (ins RO:$rt, ImmOpnd:$shamt), + !strconcat(opstr, "\t$rd, $rt, $shamt"), [], Itin, FrmR>; + +class LoadMM16<string opstr, DAGOperand RO, SDPatternOperator OpNode, + InstrItinClass Itin, Operand MemOpnd> : + MicroMipsInst16<(outs RO:$rt), (ins MemOpnd:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI> { + let DecoderMethod = "DecodeMemMMImm4"; + let canFoldAsLoad = 1; + let mayLoad = 1; +} + +class StoreMM16<string opstr, DAGOperand RTOpnd, DAGOperand RO, + SDPatternOperator OpNode, InstrItinClass Itin, + Operand MemOpnd> : + MicroMipsInst16<(outs), (ins RTOpnd:$rt, MemOpnd:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI> { + let DecoderMethod = "DecodeMemMMImm4"; + let mayStore = 1; +} + +class LoadSPMM16<string opstr, DAGOperand RO, InstrItinClass Itin, + Operand MemOpnd> : + MicroMipsInst16<(outs RO:$rt), (ins MemOpnd:$offset), + !strconcat(opstr, "\t$rt, $offset"), [], Itin, FrmI> { + let DecoderMethod = "DecodeMemMMSPImm5Lsl2"; + let canFoldAsLoad = 1; + let mayLoad = 1; +} + +class StoreSPMM16<string opstr, DAGOperand RO, InstrItinClass Itin, + Operand MemOpnd> : + MicroMipsInst16<(outs), (ins RO:$rt, MemOpnd:$offset), + !strconcat(opstr, "\t$rt, $offset"), [], Itin, FrmI> { + let DecoderMethod = "DecodeMemMMSPImm5Lsl2"; + let mayStore = 1; +} + +class LoadGPMM16<string opstr, DAGOperand RO, InstrItinClass Itin, + Operand MemOpnd> : + MicroMipsInst16<(outs RO:$rt), (ins MemOpnd:$offset), + !strconcat(opstr, "\t$rt, $offset"), [], Itin, FrmI> { + let DecoderMethod = "DecodeMemMMGPImm7Lsl2"; + let canFoldAsLoad = 1; + let mayLoad = 1; +} + +class AddImmUR2<string opstr, RegisterOperand RO> : + MicroMipsInst16<(outs RO:$rd), (ins RO:$rs, simm3_lsa2:$imm), + !strconcat(opstr, "\t$rd, $rs, $imm"), + [], NoItinerary, FrmR> { + let isCommutable = 1; +} + +class AddImmUS5<string opstr, RegisterOperand RO> : + MicroMipsInst16<(outs RO:$dst), (ins RO:$rd, simm4:$imm), + !strconcat(opstr, "\t$rd, $imm"), [], NoItinerary, FrmR> { + let Constraints = "$rd = $dst"; +} + +class AddImmUR1SP<string opstr, RegisterOperand RO> : + MicroMipsInst16<(outs RO:$rd), (ins uimm6_lsl2:$imm), + !strconcat(opstr, "\t$rd, $imm"), [], NoItinerary, FrmR>; + +class AddImmUSP<string opstr> : + MicroMipsInst16<(outs), (ins simm9_addiusp:$imm), + !strconcat(opstr, "\t$imm"), [], NoItinerary, FrmI>; + +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; +} + +class LoadImmMM16<string opstr, Operand Od, RegisterOperand RO> : + MicroMipsInst16<(outs RO:$rd), (ins Od:$imm), + !strconcat(opstr, "\t$rd, $imm"), [], NoItinerary, FrmI> { + 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)], II_JALR, FrmR>, PredicateControl { + let isCall = 1; + let hasDelaySlot = 1; + let Defs = [RA]; +} + +// 16-bit Jump Reg +class JumpRegMM16<string opstr, RegisterOperand RO> : + MicroMipsInst16<(outs), (ins RO:$rs), !strconcat(opstr, "\t$rs"), + [], II_JR, FrmR> { + let hasDelaySlot = 1; + let isBranch = 1; + let isIndirectBranch = 1; +} + +// Base class for JRADDIUSP instruction. +class JumpRAddiuStackMM16 : + MicroMipsInst16<(outs), (ins uimm5_lsl2:$imm), "jraddiusp\t$imm", + [], II_JRADDIUSP, FrmR> { + let isTerminator = 1; + let isBarrier = 1; + let isBranch = 1; + let isIndirectBranch = 1; +} + +// 16-bit Jump and Link (Call) - Short Delay Slot +class JumpLinkRegSMM16<string opstr, RegisterOperand RO> : + MicroMipsInst16<(outs), (ins RO:$rs), !strconcat(opstr, "\t$rs"), + [], II_JALRS, FrmR> { + let isCall = 1; + let hasDelaySlot = 1; + let Defs = [RA]; +} + +// 16-bit Jump Register Compact - No delay slot +class JumpRegCMM16<string opstr, RegisterOperand RO> : + MicroMipsInst16<(outs), (ins RO:$rs), !strconcat(opstr, "\t$rs"), + [], II_JRC, FrmR> { + let isTerminator = 1; + let isBarrier = 1; + let isBranch = 1; + let isIndirectBranch = 1; +} + +// Break16 and Sdbbp16 +class BrkSdbbp16MM<string opstr> : + MicroMipsInst16<(outs), (ins uimm4:$code_), + !strconcat(opstr, "\t$code_"), + [], NoItinerary, FrmOther>; + +class CBranchZeroMM<string opstr, DAGOperand opnd, RegisterOperand RO> : + MicroMipsInst16<(outs), (ins RO:$rs, opnd:$offset), + !strconcat(opstr, "\t$rs, $offset"), [], II_BCCZ, FrmI> { + let isBranch = 1; + let isTerminator = 1; + let hasDelaySlot = 1; + let Defs = [AT]; +} + +// MicroMIPS Jump and Link (Call) - Short Delay Slot +let isCall = 1, hasDelaySlot = 1, Defs = [RA] in { + class JumpLinkMM<string opstr, DAGOperand opnd> : + InstSE<(outs), (ins opnd:$target), !strconcat(opstr, "\t$target"), + [], II_JALS, FrmJ, opstr> { + let DecoderMethod = "DecodeJumpTargetMM"; + } + + class JumpLinkRegMM<string opstr, RegisterOperand RO>: + InstSE<(outs RO:$rd), (ins RO:$rs), !strconcat(opstr, "\t$rd, $rs"), + [], II_JALRS, FrmR>; + + class BranchCompareToZeroLinkMM<string opstr, DAGOperand opnd, + RegisterOperand RO> : + InstSE<(outs), (ins RO:$rs, opnd:$offset), + !strconcat(opstr, "\t$rs, $offset"), [], II_BCCZALS, FrmI, opstr>; +} + +class LoadWordIndexedScaledMM<string opstr, RegisterOperand RO, + InstrItinClass Itin = NoItinerary, + SDPatternOperator OpNode = null_frag> : + InstSE<(outs RO:$rd), (ins PtrRC:$base, PtrRC:$index), + !strconcat(opstr, "\t$rd, ${index}(${base})"), [], Itin, FrmFI>; + +class PrefetchIndexed<string opstr> : + InstSE<(outs), (ins PtrRC:$base, PtrRC:$index, uimm5:$hint), + !strconcat(opstr, "\t$hint, ${index}(${base})"), [], NoItinerary, FrmOther>; + +class AddImmUPC<string opstr, RegisterOperand RO> : + InstSE<(outs RO:$rs), (ins simm23_lsl2:$imm), + !strconcat(opstr, "\t$rs, $imm"), [], NoItinerary, FrmR>; + +/// A list of registers used by load/store multiple instructions. +def RegListAsmOperand : AsmOperandClass { + let Name = "RegList"; + let ParserMethod = "parseRegisterList"; +} + +def reglist : Operand<i32> { + let EncoderMethod = "getRegisterListOpValue"; + let ParserMatchClass = RegListAsmOperand; + let PrintMethod = "printRegisterList"; + let DecoderMethod = "DecodeRegListOperand"; +} + +def RegList16AsmOperand : AsmOperandClass { + let Name = "RegList16"; + let ParserMethod = "parseRegisterList"; + let PredicateMethod = "isRegList16"; + let RenderMethod = "addRegListOperands"; +} + +def reglist16 : Operand<i32> { + let EncoderMethod = "getRegisterListOpValue16"; + let DecoderMethod = "DecodeRegListOperand16"; + let PrintMethod = "printRegisterList"; + let ParserMatchClass = RegList16AsmOperand; +} + +class StoreMultMM<string opstr, + InstrItinClass Itin = NoItinerary, ComplexPattern Addr = addr> : + InstSE<(outs), (ins reglist:$rt, mem_mm_12:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI, opstr> { + let DecoderMethod = "DecodeMemMMImm12"; + let mayStore = 1; +} + +class LoadMultMM<string opstr, + InstrItinClass Itin = NoItinerary, ComplexPattern Addr = addr> : + InstSE<(outs reglist:$rt), (ins mem_mm_12:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI, opstr> { + let DecoderMethod = "DecodeMemMMImm12"; + let mayLoad = 1; +} + +class StoreMultMM16<string opstr, + InstrItinClass Itin = NoItinerary, + ComplexPattern Addr = addr> : + MicroMipsInst16<(outs), (ins reglist16:$rt, mem_mm_4sp:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI> { + let DecoderMethod = "DecodeMemMMReglistImm4Lsl2"; + let mayStore = 1; +} + +class LoadMultMM16<string opstr, + InstrItinClass Itin = NoItinerary, + ComplexPattern Addr = addr> : + MicroMipsInst16<(outs reglist16:$rt), (ins mem_mm_4sp:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI> { + let DecoderMethod = "DecodeMemMMReglistImm4Lsl2"; + let mayLoad = 1; +} + +class UncondBranchMM16<string opstr> : + MicroMipsInst16<(outs), (ins brtarget10_mm:$offset), + !strconcat(opstr, "\t$offset"), + [], II_B, FrmI> { + let isBranch = 1; + let isTerminator = 1; + let isBarrier = 1; + let hasDelaySlot = 1; + let Predicates = [RelocPIC, InMicroMips]; + let Defs = [AT]; +} + +def ADDU16_MM : ArithRMM16<"addu16", GPRMM16Opnd, 1, II_ADDU, add>, + ARITH_FM_MM16<0>, ISA_MICROMIPS_NOT_32R6_64R6; +def AND16_MM : LogicRMM16<"and16", GPRMM16Opnd, II_AND, and>, + LOGIC_FM_MM16<0x2>, ISA_MICROMIPS_NOT_32R6_64R6; +def ANDI16_MM : AndImmMM16<"andi16", GPRMM16Opnd, II_AND>, ANDI_FM_MM16<0x0b>, + ISA_MICROMIPS_NOT_32R6_64R6; +def NOT16_MM : NotMM16<"not16", GPRMM16Opnd>, LOGIC_FM_MM16<0x0>, + ISA_MICROMIPS_NOT_32R6_64R6; +def OR16_MM : LogicRMM16<"or16", GPRMM16Opnd, II_OR, or>, LOGIC_FM_MM16<0x3>, + ISA_MICROMIPS_NOT_32R6_64R6; +def SLL16_MM : ShiftIMM16<"sll16", uimm3_shift, GPRMM16Opnd, II_SLL>, + SHIFT_FM_MM16<0>, ISA_MICROMIPS_NOT_32R6_64R6; +def SRL16_MM : ShiftIMM16<"srl16", uimm3_shift, GPRMM16Opnd, II_SRL>, + SHIFT_FM_MM16<1>, ISA_MICROMIPS_NOT_32R6_64R6; + +def SUBU16_MM : ArithRMM16<"subu16", GPRMM16Opnd, 0, II_SUBU, sub>, + ARITH_FM_MM16<1>, ISA_MICROMIPS_NOT_32R6_64R6; +def XOR16_MM : LogicRMM16<"xor16", GPRMM16Opnd, II_XOR, xor>, + LOGIC_FM_MM16<0x1>, ISA_MICROMIPS_NOT_32R6_64R6; +def LBU16_MM : LoadMM16<"lbu16", GPRMM16Opnd, zextloadi8, II_LBU, + mem_mm_4>, LOAD_STORE_FM_MM16<0x02>; +def LHU16_MM : LoadMM16<"lhu16", GPRMM16Opnd, zextloadi16, II_LHU, + mem_mm_4_lsl1>, LOAD_STORE_FM_MM16<0x0a>; +def LW16_MM : LoadMM16<"lw16", GPRMM16Opnd, load, II_LW, mem_mm_4_lsl2>, + LOAD_STORE_FM_MM16<0x1a>; +def SB16_MM : StoreMM16<"sb16", GPRMM16OpndZero, GPRMM16Opnd, truncstorei8, + II_SB, mem_mm_4>, LOAD_STORE_FM_MM16<0x22>; +def SH16_MM : StoreMM16<"sh16", GPRMM16OpndZero, GPRMM16Opnd, truncstorei16, + II_SH, mem_mm_4_lsl1>, + LOAD_STORE_FM_MM16<0x2a>; +def SW16_MM : StoreMM16<"sw16", GPRMM16OpndZero, GPRMM16Opnd, store, II_SW, + mem_mm_4_lsl2>, LOAD_STORE_FM_MM16<0x3a>; +def LWGP_MM : LoadGPMM16<"lw", GPRMM16Opnd, II_LW, mem_mm_gp_imm7_lsl2>, + LOAD_GP_FM_MM16<0x19>; +def LWSP_MM : LoadSPMM16<"lw", GPR32Opnd, II_LW, mem_mm_sp_imm5_lsl2>, + LOAD_STORE_SP_FM_MM16<0x12>; +def SWSP_MM : StoreSPMM16<"sw", GPR32Opnd, II_SW, mem_mm_sp_imm5_lsl2>, + LOAD_STORE_SP_FM_MM16<0x32>; +def ADDIUR1SP_MM : AddImmUR1SP<"addiur1sp", GPRMM16Opnd>, ADDIUR1SP_FM_MM16; +def ADDIUR2_MM : AddImmUR2<"addiur2", GPRMM16Opnd>, ADDIUR2_FM_MM16; +def ADDIUS5_MM : AddImmUS5<"addius5", GPR32Opnd>, ADDIUS5_FM_MM16; +def ADDIUSP_MM : AddImmUSP<"addiusp">, ADDIUSP_FM_MM16; +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 MOVEP_MM : MovePMM16<"movep", GPRMM16OpndMoveP>, MOVEP_FM_MM16; +def LI16_MM : LoadImmMM16<"li16", li_simm7, GPRMM16Opnd>, LI_FM_MM16, + IsAsCheapAsAMove; +def JALR16_MM : JumpLinkRegMM16<"jalr", GPR32Opnd>, JALR_FM_MM16<0x0e>, + ISA_MICROMIPS32_NOT_MIPS32R6; +def JALRS16_MM : JumpLinkRegSMM16<"jalrs16", GPR32Opnd>, JALR_FM_MM16<0x0f>; +def JRC16_MM : JumpRegCMM16<"jrc", GPR32Opnd>, JALR_FM_MM16<0x0d>; +def JRADDIUSP : JumpRAddiuStackMM16, JRADDIUSP_FM_MM16<0x18>; +def JR16_MM : JumpRegMM16<"jr16", GPR32Opnd>, JALR_FM_MM16<0x0c>; +def BEQZ16_MM : CBranchZeroMM<"beqz16", brtarget7_mm, GPRMM16Opnd>, + BEQNEZ_FM_MM16<0x23>; +def BNEZ16_MM : CBranchZeroMM<"bnez16", brtarget7_mm, GPRMM16Opnd>, + BEQNEZ_FM_MM16<0x2b>; +def B16_MM : UncondBranchMM16<"b16">, B16_FM; +def BREAK16_MM : BrkSdbbp16MM<"break16">, BRKSDBBP16_FM_MM<0x28>, + ISA_MICROMIPS_NOT_32R6_64R6; +def SDBBP16_MM : BrkSdbbp16MM<"sdbbp16">, BRKSDBBP16_FM_MM<0x2C>, + ISA_MICROMIPS_NOT_32R6_64R6; + +let DecoderNamespace = "MicroMips" in { + /// Load and Store Instructions - multiple + def SWM16_MM : StoreMultMM16<"swm16">, LWM_FM_MM16<0x5>, + ISA_MICROMIPS32_NOT_MIPS32R6; + def LWM16_MM : LoadMultMM16<"lwm16">, LWM_FM_MM16<0x4>, + ISA_MICROMIPS32_NOT_MIPS32R6; +} + +class WaitMM<string opstr> : + InstSE<(outs), (ins uimm10:$code_), !strconcat(opstr, "\t$code_"), [], + NoItinerary, FrmOther, opstr>; + +let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in { + /// Compact Branch Instructions + def BEQZC_MM : CompactBranchMM<"beqzc", brtarget_mm, seteq, GPR32Opnd>, + COMPACT_BRANCH_FM_MM<0x7>; + def BNEZC_MM : CompactBranchMM<"bnezc", brtarget_mm, setne, GPR32Opnd>, + COMPACT_BRANCH_FM_MM<0x5>; + + /// Arithmetic Instructions (ALU Immediate) + def ADDiu_MM : MMRel, ArithLogicI<"addiu", simm16, GPR32Opnd>, + ADDI_FM_MM<0xc>; + def ADDi_MM : MMRel, ArithLogicI<"addi", simm16, GPR32Opnd>, + ADDI_FM_MM<0x4>; + def SLTi_MM : MMRel, SetCC_I<"slti", setlt, simm16, immSExt16, GPR32Opnd>, + SLTI_FM_MM<0x24>; + def SLTiu_MM : MMRel, SetCC_I<"sltiu", setult, simm16, immSExt16, GPR32Opnd>, + SLTI_FM_MM<0x2c>; + def ANDi_MM : MMRel, ArithLogicI<"andi", uimm16, GPR32Opnd>, + ADDI_FM_MM<0x34>; + def ORi_MM : MMRel, ArithLogicI<"ori", uimm16, GPR32Opnd>, + ADDI_FM_MM<0x14>; + def XORi_MM : MMRel, ArithLogicI<"xori", uimm16, GPR32Opnd>, + ADDI_FM_MM<0x1c>; + def LUi_MM : MMRel, LoadUpper<"lui", GPR32Opnd, uimm16>, LUI_FM_MM; + + 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, 1, II_ADDU, add>, + ADD_FM_MM<0, 0x150>; + def SUBu_MM : MMRel, ArithLogicR<"subu", GPR32Opnd, 0, II_SUBU, sub>, + ADD_FM_MM<0, 0x1d0>; + def MUL_MM : MMRel, ArithLogicR<"mul", GPR32Opnd>, ADD_FM_MM<0, 0x210>; + def ADD_MM : MMRel, ArithLogicR<"add", GPR32Opnd>, ADD_FM_MM<0, 0x110>; + def SUB_MM : MMRel, ArithLogicR<"sub", GPR32Opnd>, ADD_FM_MM<0, 0x190>; + def SLT_MM : MMRel, SetCC_R<"slt", setlt, GPR32Opnd>, ADD_FM_MM<0, 0x350>; + def SLTu_MM : MMRel, SetCC_R<"sltu", setult, GPR32Opnd>, + ADD_FM_MM<0, 0x390>; + def AND_MM : MMRel, ArithLogicR<"and", GPR32Opnd, 1, II_AND, and>, + ADD_FM_MM<0, 0x250>; + def OR_MM : MMRel, ArithLogicR<"or", GPR32Opnd, 1, II_OR, or>, + ADD_FM_MM<0, 0x290>; + 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", II_MULT, GPR32Opnd, [HI0, LO0]>, + MULT_FM_MM<0x22c>; + def MULTu_MM : MMRel, Mult<"multu", II_MULTU, GPR32Opnd, [HI0, LO0]>, + MULT_FM_MM<0x26c>; + def SDIV_MM : MMRel, Div<"div", II_DIV, GPR32Opnd, [HI0, LO0]>, + MULT_FM_MM<0x2ac>; + def UDIV_MM : MMRel, Div<"divu", II_DIVU, GPR32Opnd, [HI0, LO0]>, + MULT_FM_MM<0x2ec>; + + /// Arithmetic Instructions with PC and Immediate + def ADDIUPC_MM : AddImmUPC<"addiupc", GPRMM16Opnd>, ADDIUPC_FM_MM; + + /// Shift Instructions + 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, II_SRL>, + SRA_FM_MM<0x40, 0>; + 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, II_SLLV>, + SRLV_FM_MM<0x10, 0>; + 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, II_SRAV>, + SRLV_FM_MM<0x90, 0>; + 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, II_ROTRV>, + SRLV_FM_MM<0xd0, 0>; + + /// Load and Store Instructions - aligned + let DecoderMethod = "DecodeMemMMImm16" in { + def LB_MM : Load<"lb", GPR32Opnd>, MMRel, LW_FM_MM<0x7>; + def LBu_MM : Load<"lbu", GPR32Opnd>, MMRel, LW_FM_MM<0x5>; + def LH_MM : Load<"lh", GPR32Opnd>, MMRel, LW_FM_MM<0xf>; + def LHu_MM : Load<"lhu", GPR32Opnd>, MMRel, LW_FM_MM<0xd>; + def LW_MM : Load<"lw", GPR32Opnd>, MMRel, LW_FM_MM<0x3f>; + def SB_MM : Store<"sb", GPR32Opnd>, MMRel, LW_FM_MM<0x6>; + def SH_MM : Store<"sh", GPR32Opnd>, MMRel, LW_FM_MM<0xe>; + def SW_MM : Store<"sw", GPR32Opnd>, MMRel, LW_FM_MM<0x3e>; + } + + let DecoderMethod = "DecodeMemMMImm9" in { + def LBE_MM : Load<"lbe", GPR32Opnd>, POOL32C_LHUE_FM_MM<0x18, 0x6, 0x4>; + def LBuE_MM : Load<"lbue", GPR32Opnd>, POOL32C_LHUE_FM_MM<0x18, 0x6, 0x0>; + def LHE_MM : Load<"lhe", GPR32Opnd>, POOL32C_LHUE_FM_MM<0x18, 0x6, 0x5>; + def LHuE_MM : Load<"lhue", GPR32Opnd>, POOL32C_LHUE_FM_MM<0x18, 0x6, 0x1>; + def LWE_MM : Load<"lwe", GPR32Opnd>, POOL32C_LHUE_FM_MM<0x18, 0x6, 0x7>; + def SBE_MM : Store<"sbe", GPR32Opnd>, POOL32C_LHUE_FM_MM<0x18, 0xa, 0x4>; + def SHE_MM : Store<"she", GPR32Opnd>, POOL32C_LHUE_FM_MM<0x18, 0xa, 0x5>; + def SWE_MM : StoreMemory<"swe", GPR32Opnd, mem_simm9gpr>, + POOL32C_LHUE_FM_MM<0x18, 0xa, 0x7>; + } + + def LWXS_MM : LoadWordIndexedScaledMM<"lwxs", GPR32Opnd>, LWXS_FM_MM<0x118>; + + 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>; + def LWR_MM : LoadLeftRightMM<"lwr", MipsLWR, GPR32Opnd, mem_mm_12>, + LWL_FM_MM<0x1>; + def SWL_MM : StoreLeftRightMM<"swl", MipsSWL, GPR32Opnd, mem_mm_12>, + LWL_FM_MM<0x8>; + def SWR_MM : StoreLeftRightMM<"swr", MipsSWR, GPR32Opnd, mem_mm_12>, + LWL_FM_MM<0x9>; + let DecoderMethod = "DecodeMemMMImm9" in { + def LWLE_MM : LoadLeftRightMM<"lwle", MipsLWL, GPR32Opnd, mem_mm_12>, + POOL32C_STEVA_LDEVA_FM_MM<0x6, 0x2>; + def LWRE_MM : LoadLeftRightMM<"lwre", MipsLWR, GPR32Opnd, mem_mm_12>, + POOL32C_STEVA_LDEVA_FM_MM<0x6, 0x3>; + def SWLE_MM : StoreLeftRightMM<"swle", MipsSWL, GPR32Opnd, mem_mm_12>, + POOL32C_STEVA_LDEVA_FM_MM<0xa, 0x0>; + def SWRE_MM : StoreLeftRightMM<"swre", MipsSWR, GPR32Opnd, mem_mm_12>, + POOL32C_STEVA_LDEVA_FM_MM<0xa, 0x1>, ISA_MIPS1_NOT_32R6_64R6; + } + + /// Load and Store Instructions - multiple + def SWM32_MM : StoreMultMM<"swm32">, LWM_FM_MM<0xd>; + def LWM32_MM : LoadMultMM<"lwm32">, LWM_FM_MM<0x5>; + + /// Load and Store Pair Instructions + def SWP_MM : StorePairMM<"swp">, LWM_FM_MM<0x9>; + def LWP_MM : LoadPairMM<"lwp">, LWM_FM_MM<0x1>; + + /// Load and Store multiple pseudo Instructions + class LoadWordMultMM<string instr_asm > : + MipsAsmPseudoInst<(outs reglist:$rt), (ins mem_mm_12:$addr), + !strconcat(instr_asm, "\t$rt, $addr")> ; + + class StoreWordMultMM<string instr_asm > : + MipsAsmPseudoInst<(outs), (ins reglist:$rt, mem_mm_12:$addr), + !strconcat(instr_asm, "\t$rt, $addr")> ; + + + def SWM_MM : StoreWordMultMM<"swm">; + def LWM_MM : LoadWordMultMM<"lwm">; + + /// Move Conditional + def MOVZ_I_MM : MMRel, CMov_I_I_FT<"movz", GPR32Opnd, GPR32Opnd, + NoItinerary>, ADD_FM_MM<0, 0x58>; + def MOVN_I_MM : MMRel, CMov_I_I_FT<"movn", GPR32Opnd, GPR32Opnd, + NoItinerary>, ADD_FM_MM<0, 0x18>; + def MOVT_I_MM : MMRel, CMov_F_I_FT<"movt", GPR32Opnd, II_MOVT>, + CMov_F_I_FM_MM<0x25>; + def MOVF_I_MM : MMRel, CMov_F_I_FT<"movf", GPR32Opnd, II_MOVF>, + CMov_F_I_FM_MM<0x5>; + + /// Move to/from HI/LO + def MTHI_MM : MMRel, MoveToLOHI<"mthi", GPR32Opnd, [HI0]>, + MTLO_FM_MM<0x0b5>; + def MTLO_MM : MMRel, MoveToLOHI<"mtlo", GPR32Opnd, [LO0]>, + MTLO_FM_MM<0x0f5>; + def MFHI_MM : MMRel, MoveFromLOHI<"mfhi", GPR32Opnd, AC0>, + MFLO_FM_MM<0x035>; + def MFLO_MM : MMRel, MoveFromLOHI<"mflo", GPR32Opnd, AC0>, + MFLO_FM_MM<0x075>; + + /// Multiply Add/Sub Instructions + def MADD_MM : MMRel, MArithR<"madd", 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>, + ISA_MIPS32; + def CLO_MM : MMRel, CountLeading1<"clo", GPR32Opnd>, CLO_FM_MM<0x12c>, + ISA_MIPS32; + + /// Sign Ext In Register Instructions. + def SEB_MM : MMRel, SignExtInReg<"seb", i8, GPR32Opnd, II_SEB>, + SEB_FM_MM<0x0ac>, ISA_MIPS32R2; + def SEH_MM : MMRel, SignExtInReg<"seh", i16, GPR32Opnd, II_SEH>, + SEB_FM_MM<0x0ec>, ISA_MIPS32R2; + + /// Word Swap Bytes Within Halfwords + def WSBH_MM : MMRel, SubwordSwap<"wsbh", GPR32Opnd, II_WSBH>, + SEB_FM_MM<0x1ec>, ISA_MIPS32R2; + // TODO: Add '0 < pos+size <= 32' constraint check to ext instruction + def EXT_MM : MMRel, ExtBase<"ext", GPR32Opnd, uimm5, uimm5_plus1, + MipsExt>, EXT_FM_MM<0x2c>; + def INS_MM : MMRel, InsBase<"ins", GPR32Opnd, uimm5, MipsIns>, + EXT_FM_MM<0x0c>; + + /// Jump Instructions + let DecoderMethod = "DecodeJumpTargetMM" in { + def J_MM : MMRel, JumpFJ<jmptarget_mm, "j", br, bb, "j">, + J_FM_MM<0x35>; + def JAL_MM : MMRel, JumpLink<"jal", calltarget_mm>, J_FM_MM<0x3d>; + def JALX_MM : MMRel, JumpLink<"jalx", calltarget>, J_FM_MM<0x3c>; + } + def JR_MM : MMRel, IndirectBranch<"jr", GPR32Opnd>, JR_FM_MM<0x3c>; + def JALR_MM : JumpLinkReg<"jalr", GPR32Opnd>, JALR_FM_MM<0x03c>; + + /// Jump Instructions - Short Delay Slot + def JALS_MM : JumpLinkMM<"jals", calltarget_mm>, J_FM_MM<0x1d>; + def JALRS_MM : JumpLinkRegMM<"jalrs", GPR32Opnd>, JALR_FM_MM<0x13c>; + + /// Branch Instructions + def BEQ_MM : MMRel, CBranch<"beq", brtarget_mm, seteq, GPR32Opnd>, + BEQ_FM_MM<0x25>; + def BNE_MM : MMRel, CBranch<"bne", brtarget_mm, setne, GPR32Opnd>, + BEQ_FM_MM<0x2d>; + def BGEZ_MM : MMRel, CBranchZero<"bgez", brtarget_mm, setge, GPR32Opnd>, + BGEZ_FM_MM<0x2>; + def BGTZ_MM : MMRel, CBranchZero<"bgtz", brtarget_mm, setgt, GPR32Opnd>, + BGEZ_FM_MM<0x6>; + def BLEZ_MM : MMRel, CBranchZero<"blez", brtarget_mm, setle, GPR32Opnd>, + BGEZ_FM_MM<0x4>; + def BLTZ_MM : MMRel, CBranchZero<"bltz", brtarget_mm, setlt, GPR32Opnd>, + BGEZ_FM_MM<0x0>; + def BGEZAL_MM : MMRel, BGEZAL_FT<"bgezal", brtarget_mm, GPR32Opnd>, + BGEZAL_FM_MM<0x03>; + def BLTZAL_MM : MMRel, BGEZAL_FT<"bltzal", brtarget_mm, GPR32Opnd>, + BGEZAL_FM_MM<0x01>; + + /// Branch Instructions - Short Delay Slot + def BGEZALS_MM : BranchCompareToZeroLinkMM<"bgezals", brtarget_mm, + GPR32Opnd>, BGEZAL_FM_MM<0x13>; + def BLTZALS_MM : BranchCompareToZeroLinkMM<"bltzals", brtarget_mm, + GPR32Opnd>, BGEZAL_FM_MM<0x11>; + + /// Control Instructions + def SYNC_MM : MMRel, SYNC_FT<"sync">, SYNC_FM_MM; + def BREAK_MM : MMRel, BRK_FT<"break">, BRK_FM_MM; + def SYSCALL_MM : MMRel, SYS_FT<"syscall">, SYS_FM_MM; + def WAIT_MM : WaitMM<"wait">, WAIT_FM_MM; + def ERET_MM : MMRel, ER_FT<"eret">, ER_FM_MM<0x3cd>; + def DERET_MM : MMRel, ER_FT<"deret">, ER_FM_MM<0x38d>; + def EI_MM : MMRel, DEI_FT<"ei", GPR32Opnd>, EI_FM_MM<0x15d>, + ISA_MIPS32R2; + def DI_MM : MMRel, DEI_FT<"di", GPR32Opnd>, EI_FM_MM<0x11d>, + ISA_MIPS32R2; + + /// Trap Instructions + def TEQ_MM : MMRel, TEQ_FT<"teq", GPR32Opnd>, TEQ_FM_MM<0x0>; + def TGE_MM : MMRel, TEQ_FT<"tge", GPR32Opnd>, TEQ_FM_MM<0x08>; + def TGEU_MM : MMRel, TEQ_FT<"tgeu", GPR32Opnd>, TEQ_FM_MM<0x10>; + def TLT_MM : MMRel, TEQ_FT<"tlt", GPR32Opnd>, TEQ_FM_MM<0x20>; + def TLTU_MM : MMRel, TEQ_FT<"tltu", GPR32Opnd>, TEQ_FM_MM<0x28>; + def TNE_MM : MMRel, TEQ_FT<"tne", GPR32Opnd>, TEQ_FM_MM<0x30>; + + def TEQI_MM : MMRel, TEQI_FT<"teqi", GPR32Opnd>, TEQI_FM_MM<0x0e>; + def TGEI_MM : MMRel, TEQI_FT<"tgei", GPR32Opnd>, TEQI_FM_MM<0x09>; + def TGEIU_MM : MMRel, TEQI_FT<"tgeiu", GPR32Opnd>, TEQI_FM_MM<0x0b>; + def TLTI_MM : MMRel, TEQI_FT<"tlti", GPR32Opnd>, TEQI_FM_MM<0x08>; + def TLTIU_MM : MMRel, TEQI_FT<"tltiu", GPR32Opnd>, TEQI_FM_MM<0x0a>; + def TNEI_MM : MMRel, TEQI_FT<"tnei", GPR32Opnd>, TEQI_FM_MM<0x0c>; + + /// Load-linked, Store-conditional + def LL_MM : LLBaseMM<"ll", GPR32Opnd>, LL_FM_MM<0x3>; + def SC_MM : SCBaseMM<"sc", GPR32Opnd>, LL_FM_MM<0xb>; + + def LLE_MM : LLEBaseMM<"lle", GPR32Opnd>, LLE_FM_MM<0x6>; + def SCE_MM : SCEBaseMM<"sce", GPR32Opnd>, LLE_FM_MM<0xA>; + + let DecoderMethod = "DecodeCacheOpMM" in { + def CACHE_MM : MMRel, CacheOp<"cache", mem_mm_12>, + CACHE_PREF_FM_MM<0x08, 0x6>; + def PREF_MM : MMRel, CacheOp<"pref", mem_mm_12>, + CACHE_PREF_FM_MM<0x18, 0x2>; + } + + let DecoderMethod = "DecodePrefeOpMM" in { + def PREFE_MM : MMRel, CacheOp<"prefe", mem_mm_9>, + CACHE_PREFE_FM_MM<0x18, 0x2>; + def CACHEE_MM : MMRel, CacheOp<"cachee", mem_mm_9>, + CACHE_PREFE_FM_MM<0x18, 0x3>; + } + def SSNOP_MM : MMRel, Barrier<"ssnop">, BARRIER_FM_MM<0x1>; + def EHB_MM : MMRel, Barrier<"ehb">, BARRIER_FM_MM<0x3>; + def PAUSE_MM : MMRel, Barrier<"pause">, BARRIER_FM_MM<0x5>; + + def TLBP_MM : MMRel, TLB<"tlbp">, COP0_TLB_FM_MM<0x0d>; + def TLBR_MM : MMRel, TLB<"tlbr">, COP0_TLB_FM_MM<0x4d>; + def TLBWI_MM : MMRel, TLB<"tlbwi">, COP0_TLB_FM_MM<0x8d>; + def TLBWR_MM : MMRel, TLB<"tlbwr">, COP0_TLB_FM_MM<0xcd>; + + def SDBBP_MM : MMRel, SYS_FT<"sdbbp">, SDBBP_FM_MM; + + def PREFX_MM : PrefetchIndexed<"prefx">, POOL32F_PREFX_FM_MM<0x15, 0x1A0>; +} + +let DecoderNamespace = "MicroMips" in { + def RDHWR_MM : MMRel, R6MMR6Rel, ReadHardware<GPR32Opnd, HWRegsOpnd>, + RDHWR_FM_MM, ISA_MICROMIPS32_NOT_MIPS32R6; +} + +let Predicates = [InMicroMips] in { + +//===----------------------------------------------------------------------===// +// MicroMips arbitrary patterns that map to one or more instructions +//===----------------------------------------------------------------------===// + +def : MipsPat<(i32 immLi16:$imm), + (LI16_MM immLi16:$imm)>; +def : MipsPat<(i32 immSExt16:$imm), + (ADDiu_MM ZERO, immSExt16:$imm)>; +def : MipsPat<(i32 immZExt16:$imm), + (ORi_MM ZERO, immZExt16:$imm)>; +def : MipsPat<(not GPR32:$in), + (NOR_MM GPR32Opnd:$in, ZERO)>; + +def : MipsPat<(add GPRMM16:$src, immSExtAddiur2:$imm), + (ADDIUR2_MM GPRMM16:$src, immSExtAddiur2:$imm)>; +def : MipsPat<(add GPR32:$src, immSExtAddius5:$imm), + (ADDIUS5_MM GPR32:$src, immSExtAddius5:$imm)>; +def : MipsPat<(add GPR32:$src, immSExt16:$imm), + (ADDiu_MM GPR32:$src, immSExt16:$imm)>; + +def : MipsPat<(and GPRMM16:$src, immZExtAndi16:$imm), + (ANDI16_MM GPRMM16:$src, immZExtAndi16:$imm)>; +def : MipsPat<(and GPR32:$src, immZExt16:$imm), + (ANDi_MM GPR32:$src, immZExt16:$imm)>; + +def : MipsPat<(shl GPRMM16:$src, immZExt2Shift:$imm), + (SLL16_MM GPRMM16:$src, immZExt2Shift:$imm)>; +def : MipsPat<(shl GPR32:$src, immZExt5:$imm), + (SLL_MM GPR32:$src, immZExt5:$imm)>; + +def : MipsPat<(srl GPRMM16:$src, immZExt2Shift:$imm), + (SRL16_MM GPRMM16:$src, immZExt2Shift:$imm)>; +def : MipsPat<(srl GPR32:$src, immZExt5:$imm), + (SRL_MM GPR32:$src, immZExt5:$imm)>; + +def : MipsPat<(store GPRMM16:$src, addrimm4lsl2:$addr), + (SW16_MM GPRMM16:$src, addrimm4lsl2:$addr)>; +def : MipsPat<(store GPR32:$src, addr:$addr), + (SW_MM GPR32:$src, addr:$addr)>; + +def : MipsPat<(load addrimm4lsl2:$addr), + (LW16_MM addrimm4lsl2:$addr)>; +def : MipsPat<(load addr:$addr), + (LW_MM addr:$addr)>; + +//===----------------------------------------------------------------------===// +// MicroMips instruction aliases +//===----------------------------------------------------------------------===// + +class UncondBranchMMPseudo<string opstr> : + MipsAsmPseudoInst<(outs), (ins brtarget_mm:$offset), + !strconcat(opstr, "\t$offset")>; + +def B_MM_Pseudo : UncondBranchMMPseudo<"b">, ISA_MICROMIPS; + + def : MipsInstAlias<"wait", (WAIT_MM 0x0), 1>; + def : MipsInstAlias<"nop", (SLL_MM ZERO, ZERO, 0), 1>; + def : MipsInstAlias<"nop", (MOVE16_MM ZERO, ZERO), 1>; +} + +let Predicates = [InMicroMips] in { +def : MipsInstAlias<"ei", (EI_MM ZERO), 1>, ISA_MIPS32R2; +def : MipsInstAlias<"di", (DI_MM ZERO), 1>, ISA_MIPS32R2; +def : MipsInstAlias<"teq $rs, $rt", + (TEQ_MM GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>; +def : MipsInstAlias<"tge $rs, $rt", + (TGE_MM GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>; +def : MipsInstAlias<"tgeu $rs, $rt", + (TGEU_MM GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>; +def : MipsInstAlias<"tlt $rs, $rt", + (TLT_MM GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>; +def : MipsInstAlias<"tltu $rs, $rt", + (TLTU_MM GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>; +def : MipsInstAlias<"tne $rs, $rt", + (TNE_MM GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>; +} diff --git a/contrib/llvm/lib/Target/Mips/Mips.h b/contrib/llvm/lib/Target/Mips/Mips.h new file mode 100644 index 0000000..671d7a8 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips.h @@ -0,0 +1,36 @@ +//===-- Mips.h - Top-level interface for Mips representation ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the entry points for global functions defined in +// the LLVM Mips back-end. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPS_H +#define LLVM_LIB_TARGET_MIPS_MIPS_H + +#include "MCTargetDesc/MipsMCTargetDesc.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + class MipsTargetMachine; + class ModulePass; + class FunctionPass; + + ModulePass *createMipsOs16Pass(MipsTargetMachine &TM); + ModulePass *createMips16HardFloatPass(MipsTargetMachine &TM); + + FunctionPass *createMipsModuleISelDagPass(MipsTargetMachine &TM); + FunctionPass *createMipsOptimizePICCallPass(MipsTargetMachine &TM); + FunctionPass *createMipsDelaySlotFillerPass(MipsTargetMachine &TM); + FunctionPass *createMipsLongBranchPass(MipsTargetMachine &TM); + FunctionPass *createMipsConstantIslandPass(MipsTargetMachine &tm); +} // end namespace llvm; + +#endif diff --git a/contrib/llvm/lib/Target/Mips/Mips.td b/contrib/llvm/lib/Target/Mips/Mips.td new file mode 100644 index 0000000..35352b6 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips.td @@ -0,0 +1,222 @@ +//===-- Mips.td - Describe the Mips Target Machine ---------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This is the top level entry point for the Mips target. +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Target-independent interfaces +//===----------------------------------------------------------------------===// + +include "llvm/Target/Target.td" + +// The overall idea of the PredicateControl class is to chop the Predicates list +// into subsets that are usually overridden independently. This allows +// subclasses to partially override the predicates of their superclasses without +// having to re-add all the existing predicates. +class PredicateControl { + // Predicates for the encoding scheme in use such as HasStdEnc + list<Predicate> EncodingPredicates = []; + // Predicates for the GPR size such as IsGP64bit + list<Predicate> GPRPredicates = []; + // Predicates for the FGR size and layout such as IsFP64bit + list<Predicate> FGRPredicates = []; + // Predicates for the instruction group membership such as ISA's and ASE's + list<Predicate> InsnPredicates = []; + // Predicate for marking the instruction as usable in hard-float mode only. + list<Predicate> HardFloatPredicate = []; + // Predicates for anything else + list<Predicate> AdditionalPredicates = []; + list<Predicate> Predicates = !listconcat(EncodingPredicates, + GPRPredicates, + FGRPredicates, + InsnPredicates, + HardFloatPredicate, + AdditionalPredicates); +} + +// Like Requires<> but for the AdditionalPredicates list +class AdditionalRequires<list<Predicate> preds> { + list<Predicate> AdditionalPredicates = preds; +} + +//===----------------------------------------------------------------------===// +// Register File, Calling Conv, Instruction Descriptions +//===----------------------------------------------------------------------===// + +include "MipsRegisterInfo.td" +include "MipsSchedule.td" +include "MipsInstrInfo.td" +include "MipsCallingConv.td" + +def MipsInstrInfo : InstrInfo; + +//===----------------------------------------------------------------------===// +// Mips Subtarget features // +//===----------------------------------------------------------------------===// + +def FeatureNoABICalls : SubtargetFeature<"noabicalls", "NoABICalls", "true", + "Disable SVR4-style position-independent code">; +def FeatureGP64Bit : SubtargetFeature<"gp64", "IsGP64bit", "true", + "General Purpose Registers are 64-bit wide">; +def FeatureFP64Bit : SubtargetFeature<"fp64", "IsFP64bit", "true", + "Support 64-bit FP registers">; +def FeatureFPXX : SubtargetFeature<"fpxx", "IsFPXX", "true", + "Support for FPXX">; +def FeatureNaN2008 : SubtargetFeature<"nan2008", "IsNaN2008bit", "true", + "IEEE 754-2008 NaN encoding">; +def FeatureSingleFloat : SubtargetFeature<"single-float", "IsSingleFloat", + "true", "Only supports single precision float">; +def FeatureSoftFloat : SubtargetFeature<"soft-float", "IsSoftFloat", "true", + "Does not support floating point instructions">; +def FeatureNoOddSPReg : SubtargetFeature<"nooddspreg", "UseOddSPReg", "false", + "Disable odd numbered single-precision " + "registers">; +def FeatureVFPU : SubtargetFeature<"vfpu", "HasVFPU", + "true", "Enable vector FPU instructions">; +def FeatureMips1 : SubtargetFeature<"mips1", "MipsArchVersion", "Mips1", + "Mips I ISA Support [highly experimental]">; +def FeatureMips2 : SubtargetFeature<"mips2", "MipsArchVersion", "Mips2", + "Mips II ISA Support [highly experimental]", + [FeatureMips1]>; +def FeatureMips3_32 : SubtargetFeature<"mips3_32", "HasMips3_32", "true", + "Subset of MIPS-III that is also in MIPS32 " + "[highly experimental]">; +def FeatureMips3_32r2 : SubtargetFeature<"mips3_32r2", "HasMips3_32r2", "true", + "Subset of MIPS-III that is also in MIPS32r2 " + "[highly experimental]">; +def FeatureMips3 : SubtargetFeature<"mips3", "MipsArchVersion", "Mips3", + "MIPS III ISA Support [highly experimental]", + [FeatureMips2, FeatureMips3_32, + FeatureMips3_32r2, FeatureGP64Bit, + FeatureFP64Bit]>; +def FeatureMips4_32 : SubtargetFeature<"mips4_32", "HasMips4_32", "true", + "Subset of MIPS-IV that is also in MIPS32 " + "[highly experimental]">; +def FeatureMips4_32r2 : SubtargetFeature<"mips4_32r2", "HasMips4_32r2", "true", + "Subset of MIPS-IV that is also in MIPS32r2 " + "[highly experimental]">; +def FeatureMips4 : SubtargetFeature<"mips4", "MipsArchVersion", + "Mips4", "MIPS IV ISA Support", + [FeatureMips3, FeatureMips4_32, + FeatureMips4_32r2]>; +def FeatureMips5_32r2 : SubtargetFeature<"mips5_32r2", "HasMips5_32r2", "true", + "Subset of MIPS-V that is also in MIPS32r2 " + "[highly experimental]">; +def FeatureMips5 : SubtargetFeature<"mips5", "MipsArchVersion", "Mips5", + "MIPS V ISA Support [highly experimental]", + [FeatureMips4, FeatureMips5_32r2]>; +def FeatureMips32 : SubtargetFeature<"mips32", "MipsArchVersion", "Mips32", + "Mips32 ISA Support", + [FeatureMips2, FeatureMips3_32, + FeatureMips4_32]>; +def FeatureMips32r2 : SubtargetFeature<"mips32r2", "MipsArchVersion", + "Mips32r2", "Mips32r2 ISA Support", + [FeatureMips3_32r2, FeatureMips4_32r2, + FeatureMips5_32r2, FeatureMips32]>; +def FeatureMips32r3 : SubtargetFeature<"mips32r3", "MipsArchVersion", + "Mips32r3", "Mips32r3 ISA Support", + [FeatureMips32r2]>; +def FeatureMips32r5 : SubtargetFeature<"mips32r5", "MipsArchVersion", + "Mips32r5", "Mips32r5 ISA Support", + [FeatureMips32r3]>; +def FeatureMips32r6 : SubtargetFeature<"mips32r6", "MipsArchVersion", + "Mips32r6", + "Mips32r6 ISA Support [experimental]", + [FeatureMips32r5, FeatureFP64Bit, + FeatureNaN2008]>; +def FeatureMips64 : SubtargetFeature<"mips64", "MipsArchVersion", + "Mips64", "Mips64 ISA Support", + [FeatureMips5, FeatureMips32]>; +def FeatureMips64r2 : SubtargetFeature<"mips64r2", "MipsArchVersion", + "Mips64r2", "Mips64r2 ISA Support", + [FeatureMips64, FeatureMips32r2]>; +def FeatureMips64r3 : SubtargetFeature<"mips64r3", "MipsArchVersion", + "Mips64r3", "Mips64r3 ISA Support", + [FeatureMips64r2, FeatureMips32r3]>; +def FeatureMips64r5 : SubtargetFeature<"mips64r5", "MipsArchVersion", + "Mips64r5", "Mips64r5 ISA Support", + [FeatureMips64r3, FeatureMips32r5]>; +def FeatureMips64r6 : SubtargetFeature<"mips64r6", "MipsArchVersion", + "Mips64r6", + "Mips64r6 ISA Support [experimental]", + [FeatureMips32r6, FeatureMips64r5, + FeatureNaN2008]>; + +def FeatureMips16 : SubtargetFeature<"mips16", "InMips16Mode", "true", + "Mips16 mode">; + +def FeatureDSP : SubtargetFeature<"dsp", "HasDSP", "true", "Mips DSP ASE">; +def FeatureDSPR2 : SubtargetFeature<"dspr2", "HasDSPR2", "true", + "Mips DSP-R2 ASE", [FeatureDSP]>; +def FeatureDSPR3 + : SubtargetFeature<"dspr3", "HasDSPR3", "true", "Mips DSP-R3 ASE", + [ FeatureDSP, FeatureDSPR2 ]>; + +def FeatureMSA : SubtargetFeature<"msa", "HasMSA", "true", "Mips MSA ASE">; + +def FeatureEVA : SubtargetFeature<"eva", "HasEVA", "true", "Mips EVA ASE">; + +def FeatureMicroMips : SubtargetFeature<"micromips", "InMicroMipsMode", "true", + "microMips mode">; + +def FeatureCnMips : SubtargetFeature<"cnmips", "HasCnMips", + "true", "Octeon cnMIPS Support", + [FeatureMips64r2]>; + +def FeatureUseTCCInDIV : SubtargetFeature< + "use-tcc-in-div", + "UseTCCInDIV", "false", + "Force the assembler to use trapping">; + +//===----------------------------------------------------------------------===// +// Mips processors supported. +//===----------------------------------------------------------------------===// + +def ImplP5600 : SubtargetFeature<"p5600", "ProcImpl", + "MipsSubtarget::CPU::P5600", + "The P5600 Processor", [FeatureMips32r5]>; + +class Proc<string Name, list<SubtargetFeature> Features> + : Processor<Name, MipsGenericItineraries, Features>; + +def : Proc<"mips1", [FeatureMips1]>; +def : Proc<"mips2", [FeatureMips2]>; +def : Proc<"mips32", [FeatureMips32]>; +def : Proc<"mips32r2", [FeatureMips32r2]>; +def : Proc<"mips32r3", [FeatureMips32r3]>; +def : Proc<"mips32r5", [FeatureMips32r5]>; +def : Proc<"mips32r6", [FeatureMips32r6]>; + +def : Proc<"mips3", [FeatureMips3]>; +def : Proc<"mips4", [FeatureMips4]>; +def : Proc<"mips5", [FeatureMips5]>; +def : Proc<"mips64", [FeatureMips64]>; +def : Proc<"mips64r2", [FeatureMips64r2]>; +def : Proc<"mips64r3", [FeatureMips64r3]>; +def : Proc<"mips64r5", [FeatureMips64r5]>; +def : Proc<"mips64r6", [FeatureMips64r6]>; +def : Proc<"octeon", [FeatureMips64r2, FeatureCnMips]>; +def : ProcessorModel<"p5600", MipsP5600Model, [ImplP5600]>; + +def MipsAsmParser : AsmParser { + let ShouldEmitMatchRegisterName = 0; +} + +def MipsAsmParserVariant : AsmParserVariant { + int Variant = 0; + + // Recognize hard coded registers. + string RegisterPrefix = "$"; +} + +def Mips : Target { + let InstructionSet = MipsInstrInfo; + let AssemblyParsers = [MipsAsmParser]; + let AssemblyParserVariants = [MipsAsmParserVariant]; +} diff --git a/contrib/llvm/lib/Target/Mips/Mips16FrameLowering.cpp b/contrib/llvm/lib/Target/Mips/Mips16FrameLowering.cpp new file mode 100644 index 0000000..26426c0 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16FrameLowering.cpp @@ -0,0 +1,177 @@ +//===-- Mips16FrameLowering.cpp - Mips16 Frame Information ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips16 implementation of TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#include "Mips16FrameLowering.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "Mips16InstrInfo.h" +#include "MipsInstrInfo.h" +#include "MipsRegisterInfo.h" +#include "MipsSubtarget.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetOptions.h" + +using namespace llvm; + +Mips16FrameLowering::Mips16FrameLowering(const MipsSubtarget &STI) + : MipsFrameLowering(STI, STI.stackAlignment()) {} + +void Mips16FrameLowering::emitPrologue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported"); + MachineFrameInfo *MFI = MF.getFrameInfo(); + const Mips16InstrInfo &TII = + *static_cast<const Mips16InstrInfo *>(STI.getInstrInfo()); + MachineBasicBlock::iterator MBBI = MBB.begin(); + + // Debug location must be unknown since the first debug location is used + // to determine the end of the prologue. + DebugLoc dl; + + uint64_t StackSize = MFI->getStackSize(); + + // No need to allocate space on the stack. + if (StackSize == 0 && !MFI->adjustsStack()) return; + + MachineModuleInfo &MMI = MF.getMMI(); + const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); + MachineLocation DstML, SrcML; + + // Adjust stack. + TII.makeFrame(Mips::SP, StackSize, MBB, MBBI); + + // emit ".cfi_def_cfa_offset StackSize" + 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).setMIFlag(MachineInstr::FrameSetup); + +} + +void Mips16FrameLowering::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + const Mips16InstrInfo &TII = + *static_cast<const Mips16InstrInfo *>(STI.getInstrInfo()); + DebugLoc dl = MBBI->getDebugLoc(); + uint64_t StackSize = MFI->getStackSize(); + + if (!StackSize) + return; + + if (hasFP(MF)) + BuildMI(MBB, MBBI, dl, TII.get(Mips::Move32R16), Mips::SP) + .addReg(Mips::S0); + + // Adjust stack. + // assumes stacksize multiple of 8 + TII.restoreFrame(Mips::SP, StackSize, MBB, MBBI); +} + +bool Mips16FrameLowering:: +spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const { + MachineFunction *MF = MBB.getParent(); + MachineBasicBlock *EntryBlock = &MF->front(); + + // + // Registers RA, S0,S1 are the callee saved registers and they + // will be saved with the "save" instruction + // during emitPrologue + // + for (unsigned i = 0, e = CSI.size(); i != e; ++i) { + // Add the callee-saved register as live-in. Do not add if the register is + // RA and return address is taken, because it has already been added in + // method MipsTargetLowering::LowerRETURNADDR. + // It's killed at the spill, unless the register is RA and return address + // is taken. + unsigned Reg = CSI[i].getReg(); + bool IsRAAndRetAddrIsTaken = (Reg == Mips::RA) + && MF->getFrameInfo()->isReturnAddressTaken(); + if (!IsRAAndRetAddrIsTaken) + EntryBlock->addLiveIn(Reg); + } + + return true; +} + +bool Mips16FrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const { + // + // Registers RA,S0,S1 are the callee saved registers and they will be restored + // with the restore instruction during emitEpilogue. + // We need to override this virtual function, otherwise llvm will try and + // restore the registers on it's on from the stack. + // + + return true; +} + +bool +Mips16FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + // Reserve call frame if the size of the maximum call frame fits into 15-bit + // immediate field and there are no variable sized objects on the stack. + return isInt<15>(MFI->getMaxCallFrameSize()) && !MFI->hasVarSizedObjects(); +} + +void Mips16FrameLowering::determineCalleeSaves(MachineFunction &MF, + BitVector &SavedRegs, + RegScavenger *RS) const { + TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); + const Mips16InstrInfo &TII = + *static_cast<const Mips16InstrInfo *>(STI.getInstrInfo()); + const MipsRegisterInfo &RI = TII.getRegisterInfo(); + const BitVector Reserved = RI.getReservedRegs(MF); + bool SaveS2 = Reserved[Mips::S2]; + if (SaveS2) + SavedRegs.set(Mips::S2); + if (hasFP(MF)) + SavedRegs.set(Mips::S0); +} + +const MipsFrameLowering * +llvm::createMips16FrameLowering(const MipsSubtarget &ST) { + return new Mips16FrameLowering(ST); +} diff --git a/contrib/llvm/lib/Target/Mips/Mips16FrameLowering.h b/contrib/llvm/lib/Target/Mips/Mips16FrameLowering.h new file mode 100644 index 0000000..b48ed46 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16FrameLowering.h @@ -0,0 +1,47 @@ +//===-- Mips16FrameLowering.h - Mips16 frame lowering ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPS16FRAMELOWERING_H +#define LLVM_LIB_TARGET_MIPS_MIPS16FRAMELOWERING_H + +#include "MipsFrameLowering.h" + +namespace llvm { +class Mips16FrameLowering : public MipsFrameLowering { +public: + explicit Mips16FrameLowering(const MipsSubtarget &STI); + + /// emitProlog/emitEpilog - These methods insert prolog and epilog code into + /// the function. + void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + + bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const override; + + bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const override; + + bool hasReservedCallFrame(const MachineFunction &MF) const override; + + void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, + RegScavenger *RS) const override; +}; + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/Mips/Mips16HardFloat.cpp b/contrib/llvm/lib/Target/Mips/Mips16HardFloat.cpp new file mode 100644 index 0000000..b2bc7e7 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16HardFloat.cpp @@ -0,0 +1,557 @@ +//===---- Mips16HardFloat.cpp for Mips16 Hard Float --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a pass needed for Mips16 Hard Float +// +//===----------------------------------------------------------------------===// + +#include "MipsTargetMachine.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Value.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <string> + +using namespace llvm; + +#define DEBUG_TYPE "mips16-hard-float" + +namespace { + class Mips16HardFloat : public ModulePass { + public: + static char ID; + + Mips16HardFloat(MipsTargetMachine &TM_) : ModulePass(ID), TM(TM_) {} + + const char *getPassName() const override { + return "MIPS16 Hard Float Pass"; + } + + bool runOnModule(Module &M) override; + + protected: + const MipsTargetMachine &TM; + }; + + static void EmitInlineAsm(LLVMContext &C, BasicBlock *BB, StringRef AsmText) { + std::vector<llvm::Type *> AsmArgTypes; + std::vector<llvm::Value *> AsmArgs; + + llvm::FunctionType *AsmFTy = + llvm::FunctionType::get(Type::getVoidTy(C), AsmArgTypes, false); + llvm::InlineAsm *IA = + llvm::InlineAsm::get(AsmFTy, AsmText, "", true, + /* IsAlignStack */ false, llvm::InlineAsm::AD_ATT); + CallInst::Create(IA, AsmArgs, "", BB); + } + + char Mips16HardFloat::ID = 0; +} + +// +// Return types that matter for hard float are: +// float, double, complex float, and complex double +// +enum FPReturnVariant { + FRet, DRet, CFRet, CDRet, NoFPRet +}; + +// +// Determine which FP return type this function has +// +static FPReturnVariant whichFPReturnVariant(Type *T) { + switch (T->getTypeID()) { + case Type::FloatTyID: + return FRet; + case Type::DoubleTyID: + return DRet; + case Type::StructTyID: + if (T->getStructNumElements() != 2) + break; + if ((T->getContainedType(0)->isFloatTy()) && + (T->getContainedType(1)->isFloatTy())) + return CFRet; + if ((T->getContainedType(0)->isDoubleTy()) && + (T->getContainedType(1)->isDoubleTy())) + return CDRet; + break; + default: + break; + } + return NoFPRet; +} + +// +// Parameter type that matter are float, (float, float), (float, double), +// double, (double, double), (double, float) +// +enum FPParamVariant { + FSig, FFSig, FDSig, + DSig, DDSig, DFSig, NoSig +}; + +// which floating point parameter signature variant we are dealing with +// +typedef Type::TypeID TypeID; +const Type::TypeID FloatTyID = Type::FloatTyID; +const Type::TypeID DoubleTyID = Type::DoubleTyID; + +static FPParamVariant whichFPParamVariantNeeded(Function &F) { + switch (F.arg_size()) { + case 0: + return NoSig; + case 1:{ + TypeID ArgTypeID = F.getFunctionType()->getParamType(0)->getTypeID(); + switch (ArgTypeID) { + case FloatTyID: + return FSig; + case DoubleTyID: + return DSig; + default: + return NoSig; + } + } + default: { + TypeID ArgTypeID0 = F.getFunctionType()->getParamType(0)->getTypeID(); + TypeID ArgTypeID1 = F.getFunctionType()->getParamType(1)->getTypeID(); + switch(ArgTypeID0) { + case FloatTyID: { + switch (ArgTypeID1) { + case FloatTyID: + return FFSig; + case DoubleTyID: + return FDSig; + default: + return FSig; + } + } + case DoubleTyID: { + switch (ArgTypeID1) { + case FloatTyID: + return DFSig; + case DoubleTyID: + return DDSig; + default: + return DSig; + } + } + default: + return NoSig; + } + } + } + llvm_unreachable("can't get here"); +} + +// Figure out if we need float point based on the function parameters. +// We need to move variables in and/or out of floating point +// registers because of the ABI +// +static bool needsFPStubFromParams(Function &F) { + if (F.arg_size() >=1) { + Type *ArgType = F.getFunctionType()->getParamType(0); + switch (ArgType->getTypeID()) { + case Type::FloatTyID: + case Type::DoubleTyID: + return true; + default: + break; + } + } + return false; +} + +static bool needsFPReturnHelper(Function &F) { + Type* RetType = F.getReturnType(); + return whichFPReturnVariant(RetType) != NoFPRet; +} + +static bool needsFPReturnHelper(FunctionType &FT) { + Type* RetType = FT.getReturnType(); + return whichFPReturnVariant(RetType) != NoFPRet; +} + +static bool needsFPHelperFromSig(Function &F) { + return needsFPStubFromParams(F) || needsFPReturnHelper(F); +} + +// +// We swap between FP and Integer registers to allow Mips16 and Mips32 to +// interoperate +// +static std::string swapFPIntParams(FPParamVariant PV, Module *M, bool LE, + bool ToFP) { + std::string MI = ToFP ? "mtc1 ": "mfc1 "; + std::string AsmText; + + switch (PV) { + case FSig: + AsmText += MI + "$$4, $$f12\n"; + break; + + case FFSig: + AsmText += MI + "$$4, $$f12\n"; + AsmText += MI + "$$5, $$f14\n"; + break; + + case FDSig: + AsmText += MI + "$$4, $$f12\n"; + if (LE) { + AsmText += MI + "$$6, $$f14\n"; + AsmText += MI + "$$7, $$f15\n"; + } else { + AsmText += MI + "$$7, $$f14\n"; + AsmText += MI + "$$6, $$f15\n"; + } + break; + + case DSig: + if (LE) { + AsmText += MI + "$$4, $$f12\n"; + AsmText += MI + "$$5, $$f13\n"; + } else { + AsmText += MI + "$$5, $$f12\n"; + AsmText += MI + "$$4, $$f13\n"; + } + break; + + case DDSig: + if (LE) { + AsmText += MI + "$$4, $$f12\n"; + AsmText += MI + "$$5, $$f13\n"; + AsmText += MI + "$$6, $$f14\n"; + AsmText += MI + "$$7, $$f15\n"; + } else { + AsmText += MI + "$$5, $$f12\n"; + AsmText += MI + "$$4, $$f13\n"; + AsmText += MI + "$$7, $$f14\n"; + AsmText += MI + "$$6, $$f15\n"; + } + break; + + case DFSig: + if (LE) { + AsmText += MI + "$$4, $$f12\n"; + AsmText += MI + "$$5, $$f13\n"; + } else { + AsmText += MI + "$$5, $$f12\n"; + AsmText += MI + "$$4, $$f13\n"; + } + AsmText += MI + "$$6, $$f14\n"; + break; + + case NoSig: + break; + } + + return AsmText; +} + +// +// Make sure that we know we already need a stub for this function. +// Having called needsFPHelperFromSig +// +static void assureFPCallStub(Function &F, Module *M, + const MipsTargetMachine &TM) { + // for now we only need them for static relocation + if (TM.getRelocationModel() == Reloc::PIC_) + return; + LLVMContext &Context = M->getContext(); + bool LE = TM.isLittleEndian(); + std::string Name = F.getName(); + std::string SectionName = ".mips16.call.fp." + Name; + std::string StubName = "__call_stub_fp_" + Name; + // + // see if we already have the stub + // + Function *FStub = M->getFunction(StubName); + if (FStub && !FStub->isDeclaration()) return; + FStub = Function::Create(F.getFunctionType(), + Function::InternalLinkage, StubName, M); + FStub->addFnAttr("mips16_fp_stub"); + FStub->addFnAttr(llvm::Attribute::Naked); + FStub->addFnAttr(llvm::Attribute::NoInline); + FStub->addFnAttr(llvm::Attribute::NoUnwind); + FStub->addFnAttr("nomips16"); + FStub->setSection(SectionName); + BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub); + FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType()); + FPParamVariant PV = whichFPParamVariantNeeded(F); + + std::string AsmText; + AsmText += ".set reorder\n"; + AsmText += swapFPIntParams(PV, M, LE, true); + if (RV != NoFPRet) { + AsmText += "move $$18, $$31\n"; + AsmText += "jal " + Name + "\n"; + } else { + AsmText += "lui $$25, %hi(" + Name + ")\n"; + AsmText += "addiu $$25, $$25, %lo(" + Name + ")\n"; + } + + switch (RV) { + case FRet: + AsmText += "mfc1 $$2, $$f0\n"; + break; + + case DRet: + if (LE) { + AsmText += "mfc1 $$2, $$f0\n"; + AsmText += "mfc1 $$3, $$f1\n"; + } else { + AsmText += "mfc1 $$3, $$f0\n"; + AsmText += "mfc1 $$2, $$f1\n"; + } + break; + + case CFRet: + if (LE) { + AsmText += "mfc1 $$2, $$f0\n"; + AsmText += "mfc1 $$3, $$f2\n"; + } else { + AsmText += "mfc1 $$3, $$f0\n"; + AsmText += "mfc1 $$3, $$f2\n"; + } + break; + + case CDRet: + if (LE) { + AsmText += "mfc1 $$4, $$f2\n"; + AsmText += "mfc1 $$5, $$f3\n"; + AsmText += "mfc1 $$2, $$f0\n"; + AsmText += "mfc1 $$3, $$f1\n"; + + } else { + AsmText += "mfc1 $$5, $$f2\n"; + AsmText += "mfc1 $$4, $$f3\n"; + AsmText += "mfc1 $$3, $$f0\n"; + AsmText += "mfc1 $$2, $$f1\n"; + } + break; + + case NoFPRet: + break; + } + + if (RV != NoFPRet) + AsmText += "jr $$18\n"; + else + AsmText += "jr $$25\n"; + EmitInlineAsm(Context, BB, AsmText); + + new UnreachableInst(Context, BB); +} + +// +// Functions that are llvm intrinsics and don't need helpers. +// +static const char *const IntrinsicInline[] = { + "fabs", "fabsf", + "llvm.ceil.f32", "llvm.ceil.f64", + "llvm.copysign.f32", "llvm.copysign.f64", + "llvm.cos.f32", "llvm.cos.f64", + "llvm.exp.f32", "llvm.exp.f64", + "llvm.exp2.f32", "llvm.exp2.f64", + "llvm.fabs.f32", "llvm.fabs.f64", + "llvm.floor.f32", "llvm.floor.f64", + "llvm.fma.f32", "llvm.fma.f64", + "llvm.log.f32", "llvm.log.f64", + "llvm.log10.f32", "llvm.log10.f64", + "llvm.nearbyint.f32", "llvm.nearbyint.f64", + "llvm.pow.f32", "llvm.pow.f64", + "llvm.powi.f32", "llvm.powi.f64", + "llvm.rint.f32", "llvm.rint.f64", + "llvm.round.f32", "llvm.round.f64", + "llvm.sin.f32", "llvm.sin.f64", + "llvm.sqrt.f32", "llvm.sqrt.f64", + "llvm.trunc.f32", "llvm.trunc.f64", +}; + +static bool isIntrinsicInline(Function *F) { + return std::binary_search(std::begin(IntrinsicInline), + std::end(IntrinsicInline), F->getName()); +} +// +// Returns of float, double and complex need to be handled with a helper +// function. +// +static bool fixupFPReturnAndCall(Function &F, Module *M, + const MipsTargetMachine &TM) { + bool Modified = false; + LLVMContext &C = M->getContext(); + Type *MyVoid = Type::getVoidTy(C); + for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) + for (BasicBlock::iterator I = BB->begin(), E = BB->end(); + I != E; ++I) { + Instruction &Inst = *I; + if (const ReturnInst *RI = dyn_cast<ReturnInst>(I)) { + Value *RVal = RI->getReturnValue(); + if (!RVal) continue; + // + // If there is a return value and it needs a helper function, + // figure out which one and add a call before the actual + // return to this helper. The purpose of the helper is to move + // floating point values from their soft float return mapping to + // where they would have been mapped to in floating point registers. + // + Type *T = RVal->getType(); + FPReturnVariant RV = whichFPReturnVariant(T); + if (RV == NoFPRet) continue; + static const char *const Helper[NoFPRet] = { + "__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc", + "__mips16_ret_dc" + }; + const char *Name = Helper[RV]; + AttributeSet A; + Value *Params[] = {RVal}; + Modified = true; + // + // These helper functions have a different calling ABI so + // this __Mips16RetHelper indicates that so that later + // during call setup, the proper call lowering to the helper + // functions will take place. + // + A = A.addAttribute(C, AttributeSet::FunctionIndex, + "__Mips16RetHelper"); + A = A.addAttribute(C, AttributeSet::FunctionIndex, + Attribute::ReadNone); + A = A.addAttribute(C, AttributeSet::FunctionIndex, + Attribute::NoInline); + Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T, nullptr)); + CallInst::Create(F, Params, "", &Inst ); + } else if (const CallInst *CI = dyn_cast<CallInst>(I)) { + const Value* V = CI->getCalledValue(); + Type* T = nullptr; + if (V) T = V->getType(); + PointerType *PFT = nullptr; + if (T) PFT = dyn_cast<PointerType>(T); + FunctionType *FT = nullptr; + if (PFT) FT = dyn_cast<FunctionType>(PFT->getElementType()); + Function *F_ = CI->getCalledFunction(); + if (FT && needsFPReturnHelper(*FT) && + !(F_ && isIntrinsicInline(F_))) { + Modified=true; + F.addFnAttr("saveS2"); + } + if (F_ && !isIntrinsicInline(F_)) { + // pic mode calls are handled by already defined + // helper functions + if (needsFPReturnHelper(*F_)) { + Modified=true; + F.addFnAttr("saveS2"); + } + if (TM.getRelocationModel() != Reloc::PIC_ ) { + if (needsFPHelperFromSig(*F_)) { + assureFPCallStub(*F_, M, TM); + Modified=true; + } + } + } + } + } + return Modified; +} + +static void createFPFnStub(Function *F, Module *M, FPParamVariant PV, + const MipsTargetMachine &TM) { + bool PicMode = TM.getRelocationModel() == Reloc::PIC_; + bool LE = TM.isLittleEndian(); + LLVMContext &Context = M->getContext(); + std::string Name = F->getName(); + std::string SectionName = ".mips16.fn." + Name; + std::string StubName = "__fn_stub_" + Name; + std::string LocalName = "$$__fn_local_" + Name; + Function *FStub = Function::Create + (F->getFunctionType(), + Function::InternalLinkage, StubName, M); + FStub->addFnAttr("mips16_fp_stub"); + FStub->addFnAttr(llvm::Attribute::Naked); + FStub->addFnAttr(llvm::Attribute::NoUnwind); + FStub->addFnAttr(llvm::Attribute::NoInline); + FStub->addFnAttr("nomips16"); + FStub->setSection(SectionName); + BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub); + + std::string AsmText; + if (PicMode) { + AsmText += ".set noreorder\n"; + AsmText += ".cpload $$25\n"; + AsmText += ".set reorder\n"; + AsmText += ".reloc 0, R_MIPS_NONE, " + Name + "\n"; + AsmText += "la $$25, " + LocalName + "\n"; + } else + AsmText += "la $$25, " + Name + "\n"; + AsmText += swapFPIntParams(PV, M, LE, false); + AsmText += "jr $$25\n"; + AsmText += LocalName + " = " + Name + "\n"; + EmitInlineAsm(Context, BB, AsmText); + + new UnreachableInst(FStub->getContext(), BB); +} + +// +// remove the use-soft-float attribute +// +static void removeUseSoftFloat(Function &F) { + AttributeSet A; + DEBUG(errs() << "removing -use-soft-float\n"); + A = A.addAttribute(F.getContext(), AttributeSet::FunctionIndex, + "use-soft-float", "false"); + F.removeAttributes(AttributeSet::FunctionIndex, A); + if (F.hasFnAttribute("use-soft-float")) { + DEBUG(errs() << "still has -use-soft-float\n"); + } + F.addAttributes(AttributeSet::FunctionIndex, A); +} + + +// +// This pass only makes sense when the underlying chip has floating point but +// we are compiling as mips16. +// For all mips16 functions (that are not stubs we have already generated), or +// declared via attributes as nomips16, we must: +// 1) fixup all returns of float, double, single and double complex +// by calling a helper function before the actual return. +// 2) generate helper functions (stubs) that can be called by mips32 +// functions that will move parameters passed normally passed in +// floating point +// registers the soft float equivalents. +// 3) in the case of static relocation, generate helper functions so that +// mips16 functions can call extern functions of unknown type (mips16 or +// mips32). +// 4) TBD. For pic, calls to extern functions of unknown type are handled by +// predefined helper functions in libc but this work is currently done +// during call lowering but it should be moved here in the future. +// +bool Mips16HardFloat::runOnModule(Module &M) { + DEBUG(errs() << "Run on Module Mips16HardFloat\n"); + bool Modified = false; + for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { + if (F->hasFnAttribute("nomips16") && + F->hasFnAttribute("use-soft-float")) { + removeUseSoftFloat(*F); + continue; + } + if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") || + F->hasFnAttribute("nomips16")) continue; + Modified |= fixupFPReturnAndCall(*F, &M, TM); + FPParamVariant V = whichFPParamVariantNeeded(*F); + if (V != NoSig) { + Modified = true; + createFPFnStub(&*F, &M, V, TM); + } + } + return Modified; +} + + +ModulePass *llvm::createMips16HardFloatPass(MipsTargetMachine &TM) { + return new Mips16HardFloat(TM); +} diff --git a/contrib/llvm/lib/Target/Mips/Mips16HardFloatInfo.cpp b/contrib/llvm/lib/Target/Mips/Mips16HardFloatInfo.cpp new file mode 100644 index 0000000..2eb6e5d --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16HardFloatInfo.cpp @@ -0,0 +1,50 @@ +//===---- Mips16HardFloatInfo.cpp for Mips16 Hard Float -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips16 implementation of Mips16HardFloatInfo +// namespace. +// +//===----------------------------------------------------------------------===// + +#include "Mips16HardFloatInfo.h" +#include <string.h> + +namespace llvm { + +namespace Mips16HardFloatInfo { + +const FuncNameSignature PredefinedFuncs[] = { + { "__floatdidf", { NoSig, DRet } }, + { "__floatdisf", { NoSig, FRet } }, + { "__floatundidf", { NoSig, DRet } }, + { "__fixsfdi", { FSig, NoFPRet } }, + { "__fixunsdfsi", { DSig, NoFPRet } }, + { "__fixunsdfdi", { DSig, NoFPRet } }, + { "__fixdfdi", { DSig, NoFPRet } }, + { "__fixunssfsi", { FSig, NoFPRet } }, + { "__fixunssfdi", { FSig, NoFPRet } }, + { "__floatundisf", { NoSig, FRet } }, + { nullptr, { NoSig, NoFPRet } } +}; + +// just do a search for now. there are very few of these special cases. +// +extern FuncSignature const *findFuncSignature(const char *name) { + const char *name_; + int i = 0; + while (PredefinedFuncs[i].Name) { + name_ = PredefinedFuncs[i].Name; + if (strcmp(name, name_) == 0) + return &PredefinedFuncs[i].Signature; + i++; + } + return nullptr; +} +} +} diff --git a/contrib/llvm/lib/Target/Mips/Mips16HardFloatInfo.h b/contrib/llvm/lib/Target/Mips/Mips16HardFloatInfo.h new file mode 100644 index 0000000..7295c28 --- /dev/null +++ b/contrib/llvm/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 LLVM_LIB_TARGET_MIPS_MIPS16HARDFLOATINFO_H +#define LLVM_LIB_TARGET_MIPS_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/contrib/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp new file mode 100644 index 0000000..5a1c2c67 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp @@ -0,0 +1,322 @@ +//===-- Mips16ISelDAGToDAG.cpp - A Dag to Dag Inst Selector for Mips16 ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Subclass of MipsDAGToDAGISel specialized for mips16. +// +//===----------------------------------------------------------------------===// + +#include "Mips16ISelDAGToDAG.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "Mips.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsMachineFunction.h" +#include "MipsRegisterInfo.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/IR/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/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +using namespace llvm; + +#define DEBUG_TYPE "mips-isel" + +bool Mips16DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &static_cast<const MipsSubtarget &>(MF.getSubtarget()); + if (!Subtarget->inMips16Mode()) + return false; + return MipsDAGToDAGISel::runOnMachineFunction(MF); +} +/// Select multiply instructions. +std::pair<SDNode*, SDNode*> +Mips16DAGToDAGISel::selectMULT(SDNode *N, unsigned Opc, SDLoc DL, EVT Ty, + bool HasLo, bool HasHi) { + SDNode *Lo = nullptr, *Hi = nullptr; + SDNode *Mul = CurDAG->getMachineNode(Opc, DL, MVT::Glue, N->getOperand(0), + N->getOperand(1)); + SDValue InFlag = SDValue(Mul, 0); + + if (HasLo) { + unsigned Opcode = Mips::Mflo16; + Lo = CurDAG->getMachineNode(Opcode, DL, Ty, MVT::Glue, InFlag); + InFlag = SDValue(Lo, 1); + } + if (HasHi) { + unsigned Opcode = Mips::Mfhi16; + Hi = CurDAG->getMachineNode(Opcode, DL, Ty, InFlag); + } + return std::make_pair(Lo, Hi); +} + +void Mips16DAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) { + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + if (!MipsFI->globalBaseRegSet()) + return; + + MachineBasicBlock &MBB = MF.front(); + MachineBasicBlock::iterator I = MBB.begin(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); + DebugLoc DL; + unsigned V0, V1, V2, GlobalBaseReg = MipsFI->getGlobalBaseReg(); + const TargetRegisterClass *RC = &Mips::CPU16RegsRegClass; + + V0 = RegInfo.createVirtualRegister(RC); + V1 = RegInfo.createVirtualRegister(RC); + V2 = RegInfo.createVirtualRegister(RC); + + BuildMI(MBB, I, DL, TII.get(Mips::GotPrologue16), V0). + addReg(V1, RegState::Define). + addExternalSymbol("_gp_disp", MipsII::MO_ABS_HI). + addExternalSymbol("_gp_disp", MipsII::MO_ABS_LO); + + BuildMI(MBB, I, DL, TII.get(Mips::SllX16), V2).addReg(V0).addImm(16); + BuildMI(MBB, I, DL, TII.get(Mips::AdduRxRyRz16), GlobalBaseReg) + .addReg(V1).addReg(V2); +} + +// Insert instructions to initialize the Mips16 SP Alias register in the +// first MBB of the function. +// +void Mips16DAGToDAGISel::initMips16SPAliasReg(MachineFunction &MF) { + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + if (!MipsFI->mips16SPAliasRegSet()) + return; + + MachineBasicBlock &MBB = MF.front(); + MachineBasicBlock::iterator I = MBB.begin(); + const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); + DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); + unsigned Mips16SPAliasReg = MipsFI->getMips16SPAliasReg(); + + BuildMI(MBB, I, DL, TII.get(Mips::MoveR3216), Mips16SPAliasReg) + .addReg(Mips::SP); +} + +void Mips16DAGToDAGISel::processFunctionAfterISel(MachineFunction &MF) { + initGlobalBaseReg(MF); + initMips16SPAliasReg(MF); +} + +/// getMips16SPAliasReg - Output the instructions required to put the +/// SP into a Mips16 accessible aliased register. +SDValue Mips16DAGToDAGISel::getMips16SPAliasReg() { + unsigned Mips16SPAliasReg = + MF->getInfo<MipsFunctionInfo>()->getMips16SPAliasReg(); + auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout()); + return CurDAG->getRegister(Mips16SPAliasReg, PtrVT); +} + +void Mips16DAGToDAGISel::getMips16SPRefReg(SDNode *Parent, SDValue &AliasReg) { + auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout()); + SDValue AliasFPReg = CurDAG->getRegister(Mips::S0, PtrVT); + if (Parent) { + switch (Parent->getOpcode()) { + case ISD::LOAD: { + LoadSDNode *SD = dyn_cast<LoadSDNode>(Parent); + switch (SD->getMemoryVT().getSizeInBits()) { + case 8: + case 16: + AliasReg = Subtarget->getFrameLowering()->hasFP(*MF) + ? AliasFPReg + : getMips16SPAliasReg(); + return; + } + break; + } + case ISD::STORE: { + StoreSDNode *SD = dyn_cast<StoreSDNode>(Parent); + switch (SD->getMemoryVT().getSizeInBits()) { + case 8: + case 16: + AliasReg = Subtarget->getFrameLowering()->hasFP(*MF) + ? AliasFPReg + : getMips16SPAliasReg(); + return; + } + break; + } + } + } + AliasReg = CurDAG->getRegister(Mips::SP, PtrVT); + return; + +} + +bool Mips16DAGToDAGISel::selectAddr16( + SDNode *Parent, SDValue Addr, SDValue &Base, SDValue &Offset, + SDValue &Alias) { + SDLoc DL(Addr); + EVT ValTy = Addr.getValueType(); + + Alias = CurDAG->getTargetConstant(0, DL, ValTy); + + // if Address is FI, get the TargetFrameIndex. + if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); + Offset = CurDAG->getTargetConstant(0, DL, ValTy); + getMips16SPRefReg(Parent, Alias); + return true; + } + // on PIC code Load GA + if (Addr.getOpcode() == MipsISD::Wrapper) { + Base = Addr.getOperand(0); + Offset = Addr.getOperand(1); + return true; + } + if (TM.getRelocationModel() != Reloc::PIC_) { + if ((Addr.getOpcode() == ISD::TargetExternalSymbol || + Addr.getOpcode() == ISD::TargetGlobalAddress)) + return false; + } + // Addresses of the form FI+const or FI|const + if (CurDAG->isBaseWithConstantOffset(Addr)) { + ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)); + if (isInt<16>(CN->getSExtValue())) { + + // If the first operand is a FI, get the TargetFI Node + if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode> + (Addr.getOperand(0))) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); + getMips16SPRefReg(Parent, Alias); + } + else + Base = Addr.getOperand(0); + + Offset = CurDAG->getTargetConstant(CN->getZExtValue(), DL, ValTy); + return true; + } + } + // Operand is a result from an ADD. + if (Addr.getOpcode() == ISD::ADD) { + // When loading from constant pools, load the lower address part in + // the instruction itself. Example, instead of: + // lui $2, %hi($CPI1_0) + // addiu $2, $2, %lo($CPI1_0) + // lwc1 $f0, 0($2) + // Generate: + // lui $2, %hi($CPI1_0) + // lwc1 $f0, %lo($CPI1_0)($2) + if (Addr.getOperand(1).getOpcode() == MipsISD::Lo || + Addr.getOperand(1).getOpcode() == MipsISD::GPRel) { + SDValue Opnd0 = Addr.getOperand(1).getOperand(0); + if (isa<ConstantPoolSDNode>(Opnd0) || isa<GlobalAddressSDNode>(Opnd0) || + isa<JumpTableSDNode>(Opnd0)) { + Base = Addr.getOperand(0); + Offset = Opnd0; + return true; + } + } + + // If an indexed floating point load/store can be emitted, return false. + const LSBaseSDNode *LS = dyn_cast<LSBaseSDNode>(Parent); + + if (LS) { + if (LS->getMemoryVT() == MVT::f32 && Subtarget->hasMips4_32r2()) + return false; + if (LS->getMemoryVT() == MVT::f64 && Subtarget->hasMips4_32r2()) + return false; + } + } + Base = Addr; + Offset = CurDAG->getTargetConstant(0, DL, ValTy); + return true; +} + +/// Select instructions not customized! Used for +/// expanded, promoted and normal instructions +std::pair<bool, SDNode*> Mips16DAGToDAGISel::selectNode(SDNode *Node) { + unsigned Opcode = Node->getOpcode(); + SDLoc DL(Node); + + /// + // Instruction Selection not handled by the auto-generated + // tablegen selection should be handled here. + /// + EVT NodeTy = Node->getValueType(0); + unsigned MultOpc; + + switch(Opcode) { + default: break; + + case ISD::SUBE: + case ISD::ADDE: { + SDValue InFlag = Node->getOperand(2), CmpLHS; + unsigned Opc = InFlag.getOpcode(); (void)Opc; + assert(((Opc == ISD::ADDC || Opc == ISD::ADDE) || + (Opc == ISD::SUBC || Opc == ISD::SUBE)) && + "(ADD|SUB)E flag operand must come from (ADD|SUB)C/E insn"); + + unsigned MOp; + if (Opcode == ISD::ADDE) { + CmpLHS = InFlag.getValue(0); + MOp = Mips::AdduRxRyRz16; + } else { + CmpLHS = InFlag.getOperand(0); + MOp = Mips::SubuRxRyRz16; + } + + SDValue Ops[] = { CmpLHS, InFlag.getOperand(1) }; + + SDValue LHS = Node->getOperand(0); + SDValue RHS = Node->getOperand(1); + + EVT VT = LHS.getValueType(); + + unsigned Sltu_op = Mips::SltuRxRyRz16; + SDNode *Carry = CurDAG->getMachineNode(Sltu_op, DL, VT, Ops); + unsigned Addu_op = Mips::AdduRxRyRz16; + SDNode *AddCarry = CurDAG->getMachineNode(Addu_op, DL, VT, + SDValue(Carry,0), RHS); + + SDNode *Result = CurDAG->SelectNodeTo(Node, MOp, VT, MVT::Glue, LHS, + SDValue(AddCarry,0)); + return std::make_pair(true, Result); + } + + /// Mul with two results + case ISD::SMUL_LOHI: + case ISD::UMUL_LOHI: { + MultOpc = (Opcode == ISD::UMUL_LOHI ? Mips::MultuRxRy16 : Mips::MultRxRy16); + std::pair<SDNode*, SDNode*> LoHi = selectMULT(Node, MultOpc, DL, NodeTy, + true, true); + if (!SDValue(Node, 0).use_empty()) + ReplaceUses(SDValue(Node, 0), SDValue(LoHi.first, 0)); + + if (!SDValue(Node, 1).use_empty()) + ReplaceUses(SDValue(Node, 1), SDValue(LoHi.second, 0)); + + return std::make_pair(true, nullptr); + } + + case ISD::MULHS: + case ISD::MULHU: { + MultOpc = (Opcode == ISD::MULHU ? Mips::MultuRxRy16 : Mips::MultRxRy16); + SDNode *Result = selectMULT(Node, MultOpc, DL, NodeTy, false, true).second; + return std::make_pair(true, Result); + } + } + + return std::make_pair(false, nullptr); +} + +FunctionPass *llvm::createMips16ISelDag(MipsTargetMachine &TM) { + return new Mips16DAGToDAGISel(TM); +} diff --git a/contrib/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.h b/contrib/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.h new file mode 100644 index 0000000..ae0e61e --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.h @@ -0,0 +1,53 @@ +//===---- Mips16ISelDAGToDAG.h - A Dag to Dag Inst Selector for Mips ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Subclass of MipsDAGToDAGISel specialized for mips16. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPS16ISELDAGTODAG_H +#define LLVM_LIB_TARGET_MIPS_MIPS16ISELDAGTODAG_H + +#include "MipsISelDAGToDAG.h" + +namespace llvm { + +class Mips16DAGToDAGISel : public MipsDAGToDAGISel { +public: + explicit Mips16DAGToDAGISel(MipsTargetMachine &TM) : MipsDAGToDAGISel(TM) {} + +private: + std::pair<SDNode*, SDNode*> selectMULT(SDNode *N, unsigned Opc, SDLoc DL, + EVT Ty, bool HasLo, bool HasHi); + + SDValue getMips16SPAliasReg(); + + bool runOnMachineFunction(MachineFunction &MF) override; + + void getMips16SPRefReg(SDNode *Parent, SDValue &AliasReg); + + bool selectAddr16(SDNode *Parent, SDValue N, SDValue &Base, + SDValue &Offset, SDValue &Alias) override; + + std::pair<bool, SDNode*> selectNode(SDNode *Node) override; + + void processFunctionAfterISel(MachineFunction &MF) override; + + // Insert instructions to initialize the global base register in the + // first MBB of the function. + void initGlobalBaseReg(MachineFunction &MF); + + void initMips16SPAliasReg(MachineFunction &MF); +}; + +FunctionPass *createMips16ISelDag(MipsTargetMachine &TM); + +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/Mips16ISelLowering.cpp b/contrib/llvm/lib/Target/Mips/Mips16ISelLowering.cpp new file mode 100644 index 0000000..e748325 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16ISelLowering.cpp @@ -0,0 +1,795 @@ +//===-- Mips16ISelLowering.h - Mips16 DAG Lowering Interface ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Subclass of MipsTargetLowering specialized for mips16. +// +//===----------------------------------------------------------------------===// +#include "Mips16ISelLowering.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "Mips16HardFloatInfo.h" +#include "MipsMachineFunction.h" +#include "MipsRegisterInfo.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetInstrInfo.h" +#include <string> + +using namespace llvm; + +#define DEBUG_TYPE "mips-lower" + +static cl::opt<bool> DontExpandCondPseudos16( + "mips16-dont-expand-cond-pseudo", + cl::init(false), + cl::desc("Don't expand conditional move related " + "pseudos for Mips 16"), + cl::Hidden); + +namespace { +struct Mips16Libcall { + RTLIB::Libcall Libcall; + const char *Name; + + bool operator<(const Mips16Libcall &RHS) const { + return std::strcmp(Name, RHS.Name) < 0; + } +}; + +struct Mips16IntrinsicHelperType{ + const char* Name; + const char* Helper; + + bool operator<(const Mips16IntrinsicHelperType &RHS) const { + return std::strcmp(Name, RHS.Name) < 0; + } + bool operator==(const Mips16IntrinsicHelperType &RHS) const { + return std::strcmp(Name, RHS.Name) == 0; + } +}; +} + +// Libcalls for which no helper is generated. Sorted by name for binary search. +static const Mips16Libcall HardFloatLibCalls[] = { + { RTLIB::ADD_F64, "__mips16_adddf3" }, + { RTLIB::ADD_F32, "__mips16_addsf3" }, + { RTLIB::DIV_F64, "__mips16_divdf3" }, + { RTLIB::DIV_F32, "__mips16_divsf3" }, + { RTLIB::OEQ_F64, "__mips16_eqdf2" }, + { RTLIB::OEQ_F32, "__mips16_eqsf2" }, + { RTLIB::FPEXT_F32_F64, "__mips16_extendsfdf2" }, + { RTLIB::FPTOSINT_F64_I32, "__mips16_fix_truncdfsi" }, + { RTLIB::FPTOSINT_F32_I32, "__mips16_fix_truncsfsi" }, + { RTLIB::SINTTOFP_I32_F64, "__mips16_floatsidf" }, + { RTLIB::SINTTOFP_I32_F32, "__mips16_floatsisf" }, + { RTLIB::UINTTOFP_I32_F64, "__mips16_floatunsidf" }, + { RTLIB::UINTTOFP_I32_F32, "__mips16_floatunsisf" }, + { RTLIB::OGE_F64, "__mips16_gedf2" }, + { RTLIB::OGE_F32, "__mips16_gesf2" }, + { RTLIB::OGT_F64, "__mips16_gtdf2" }, + { RTLIB::OGT_F32, "__mips16_gtsf2" }, + { RTLIB::OLE_F64, "__mips16_ledf2" }, + { RTLIB::OLE_F32, "__mips16_lesf2" }, + { RTLIB::OLT_F64, "__mips16_ltdf2" }, + { RTLIB::OLT_F32, "__mips16_ltsf2" }, + { RTLIB::MUL_F64, "__mips16_muldf3" }, + { RTLIB::MUL_F32, "__mips16_mulsf3" }, + { RTLIB::UNE_F64, "__mips16_nedf2" }, + { RTLIB::UNE_F32, "__mips16_nesf2" }, + { RTLIB::UNKNOWN_LIBCALL, "__mips16_ret_dc" }, // No associated libcall. + { RTLIB::UNKNOWN_LIBCALL, "__mips16_ret_df" }, // No associated libcall. + { RTLIB::UNKNOWN_LIBCALL, "__mips16_ret_sc" }, // No associated libcall. + { RTLIB::UNKNOWN_LIBCALL, "__mips16_ret_sf" }, // No associated libcall. + { RTLIB::SUB_F64, "__mips16_subdf3" }, + { RTLIB::SUB_F32, "__mips16_subsf3" }, + { RTLIB::FPROUND_F64_F32, "__mips16_truncdfsf2" }, + { RTLIB::UO_F64, "__mips16_unorddf2" }, + { RTLIB::UO_F32, "__mips16_unordsf2" } +}; + +static const Mips16IntrinsicHelperType Mips16IntrinsicHelper[] = { + {"__fixunsdfsi", "__mips16_call_stub_2" }, + {"ceil", "__mips16_call_stub_df_2"}, + {"ceilf", "__mips16_call_stub_sf_1"}, + {"copysign", "__mips16_call_stub_df_10"}, + {"copysignf", "__mips16_call_stub_sf_5"}, + {"cos", "__mips16_call_stub_df_2"}, + {"cosf", "__mips16_call_stub_sf_1"}, + {"exp2", "__mips16_call_stub_df_2"}, + {"exp2f", "__mips16_call_stub_sf_1"}, + {"floor", "__mips16_call_stub_df_2"}, + {"floorf", "__mips16_call_stub_sf_1"}, + {"log2", "__mips16_call_stub_df_2"}, + {"log2f", "__mips16_call_stub_sf_1"}, + {"nearbyint", "__mips16_call_stub_df_2"}, + {"nearbyintf", "__mips16_call_stub_sf_1"}, + {"rint", "__mips16_call_stub_df_2"}, + {"rintf", "__mips16_call_stub_sf_1"}, + {"sin", "__mips16_call_stub_df_2"}, + {"sinf", "__mips16_call_stub_sf_1"}, + {"sqrt", "__mips16_call_stub_df_2"}, + {"sqrtf", "__mips16_call_stub_sf_1"}, + {"trunc", "__mips16_call_stub_df_2"}, + {"truncf", "__mips16_call_stub_sf_1"}, +}; + +Mips16TargetLowering::Mips16TargetLowering(const MipsTargetMachine &TM, + const MipsSubtarget &STI) + : MipsTargetLowering(TM, STI) { + + // Set up the register classes + addRegisterClass(MVT::i32, &Mips::CPU16RegsRegClass); + + if (!Subtarget.useSoftFloat()) + setMips16HardFloatLibCalls(); + + setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Expand); + setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_SWAP, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_ADD, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_SUB, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_AND, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_OR, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_XOR, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_NAND, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_MIN, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_MAX, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_UMIN, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_UMAX, MVT::i32, Expand); + + setOperationAction(ISD::ROTR, MVT::i32, Expand); + setOperationAction(ISD::ROTR, MVT::i64, Expand); + setOperationAction(ISD::BSWAP, MVT::i32, Expand); + setOperationAction(ISD::BSWAP, MVT::i64, Expand); + + computeRegisterProperties(STI.getRegisterInfo()); +} + +const MipsTargetLowering * +llvm::createMips16TargetLowering(const MipsTargetMachine &TM, + const MipsSubtarget &STI) { + return new Mips16TargetLowering(TM, STI); +} + +bool +Mips16TargetLowering::allowsMisalignedMemoryAccesses(EVT VT, + unsigned, + unsigned, + bool *Fast) const { + return false; +} + +MachineBasicBlock * +Mips16TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const { + switch (MI->getOpcode()) { + default: + return MipsTargetLowering::EmitInstrWithCustomInserter(MI, BB); + case Mips::SelBeqZ: + return emitSel16(Mips::BeqzRxImm16, MI, BB); + case Mips::SelBneZ: + return emitSel16(Mips::BnezRxImm16, MI, BB); + case Mips::SelTBteqZCmpi: + return emitSeliT16(Mips::Bteqz16, Mips::CmpiRxImmX16, MI, BB); + case Mips::SelTBteqZSlti: + return emitSeliT16(Mips::Bteqz16, Mips::SltiRxImmX16, MI, BB); + case Mips::SelTBteqZSltiu: + return emitSeliT16(Mips::Bteqz16, Mips::SltiuRxImmX16, MI, BB); + case Mips::SelTBtneZCmpi: + return emitSeliT16(Mips::Btnez16, Mips::CmpiRxImmX16, MI, BB); + case Mips::SelTBtneZSlti: + return emitSeliT16(Mips::Btnez16, Mips::SltiRxImmX16, MI, BB); + case Mips::SelTBtneZSltiu: + return emitSeliT16(Mips::Btnez16, Mips::SltiuRxImmX16, MI, BB); + case Mips::SelTBteqZCmp: + return emitSelT16(Mips::Bteqz16, Mips::CmpRxRy16, MI, BB); + case Mips::SelTBteqZSlt: + return emitSelT16(Mips::Bteqz16, Mips::SltRxRy16, MI, BB); + case Mips::SelTBteqZSltu: + return emitSelT16(Mips::Bteqz16, Mips::SltuRxRy16, MI, BB); + case Mips::SelTBtneZCmp: + return emitSelT16(Mips::Btnez16, Mips::CmpRxRy16, MI, BB); + case Mips::SelTBtneZSlt: + return emitSelT16(Mips::Btnez16, Mips::SltRxRy16, MI, BB); + case Mips::SelTBtneZSltu: + return emitSelT16(Mips::Btnez16, Mips::SltuRxRy16, MI, BB); + case Mips::BteqzT8CmpX16: + return emitFEXT_T8I816_ins(Mips::Bteqz16, Mips::CmpRxRy16, MI, BB); + case Mips::BteqzT8SltX16: + return emitFEXT_T8I816_ins(Mips::Bteqz16, Mips::SltRxRy16, MI, BB); + case Mips::BteqzT8SltuX16: + // TBD: figure out a way to get this or remove the instruction + // altogether. + return emitFEXT_T8I816_ins(Mips::Bteqz16, Mips::SltuRxRy16, MI, BB); + case Mips::BtnezT8CmpX16: + return emitFEXT_T8I816_ins(Mips::Btnez16, Mips::CmpRxRy16, MI, BB); + case Mips::BtnezT8SltX16: + return emitFEXT_T8I816_ins(Mips::Btnez16, Mips::SltRxRy16, MI, BB); + case Mips::BtnezT8SltuX16: + // TBD: figure out a way to get this or remove the instruction + // altogether. + return emitFEXT_T8I816_ins(Mips::Btnez16, Mips::SltuRxRy16, MI, BB); + case Mips::BteqzT8CmpiX16: return emitFEXT_T8I8I16_ins( + Mips::Bteqz16, Mips::CmpiRxImm16, Mips::CmpiRxImmX16, false, MI, BB); + case Mips::BteqzT8SltiX16: return emitFEXT_T8I8I16_ins( + Mips::Bteqz16, Mips::SltiRxImm16, Mips::SltiRxImmX16, true, MI, BB); + case Mips::BteqzT8SltiuX16: return emitFEXT_T8I8I16_ins( + Mips::Bteqz16, Mips::SltiuRxImm16, Mips::SltiuRxImmX16, false, MI, BB); + case Mips::BtnezT8CmpiX16: return emitFEXT_T8I8I16_ins( + Mips::Btnez16, Mips::CmpiRxImm16, Mips::CmpiRxImmX16, false, MI, BB); + case Mips::BtnezT8SltiX16: return emitFEXT_T8I8I16_ins( + Mips::Btnez16, Mips::SltiRxImm16, Mips::SltiRxImmX16, true, MI, BB); + case Mips::BtnezT8SltiuX16: return emitFEXT_T8I8I16_ins( + Mips::Btnez16, Mips::SltiuRxImm16, Mips::SltiuRxImmX16, false, MI, BB); + break; + case Mips::SltCCRxRy16: + return emitFEXT_CCRX16_ins(Mips::SltRxRy16, MI, BB); + break; + case Mips::SltiCCRxImmX16: + return emitFEXT_CCRXI16_ins + (Mips::SltiRxImm16, Mips::SltiRxImmX16, MI, BB); + case Mips::SltiuCCRxImmX16: + return emitFEXT_CCRXI16_ins + (Mips::SltiuRxImm16, Mips::SltiuRxImmX16, MI, BB); + case Mips::SltuCCRxRy16: + return emitFEXT_CCRX16_ins + (Mips::SltuRxRy16, MI, BB); + } +} + +bool Mips16TargetLowering::isEligibleForTailCallOptimization( + const CCState &CCInfo, unsigned NextStackOffset, + const MipsFunctionInfo &FI) const { + // No tail call optimization for mips16. + return false; +} + +void Mips16TargetLowering::setMips16HardFloatLibCalls() { + for (unsigned I = 0; I != array_lengthof(HardFloatLibCalls); ++I) { + assert((I == 0 || HardFloatLibCalls[I - 1] < HardFloatLibCalls[I]) && + "Array not sorted!"); + if (HardFloatLibCalls[I].Libcall != RTLIB::UNKNOWN_LIBCALL) + setLibcallName(HardFloatLibCalls[I].Libcall, HardFloatLibCalls[I].Name); + } + + setLibcallName(RTLIB::O_F64, "__mips16_unorddf2"); + setLibcallName(RTLIB::O_F32, "__mips16_unordsf2"); +} + +// +// The Mips16 hard float is a crazy quilt inherited from gcc. I have a much +// cleaner way to do all of this but it will have to wait until the traditional +// gcc mechanism is completed. +// +// For Pic, in order for Mips16 code to call Mips32 code which according the abi +// have either arguments or returned values placed in floating point registers, +// we use a set of helper functions. (This includes functions which return type +// complex which on Mips are returned in a pair of floating point registers). +// +// This is an encoding that we inherited from gcc. +// In Mips traditional O32, N32 ABI, floating point numbers are passed in +// floating point argument registers 1,2 only when the first and optionally +// the second arguments are float (sf) or double (df). +// For Mips16 we are only concerned with the situations where floating point +// arguments are being passed in floating point registers by the ABI, because +// Mips16 mode code cannot execute floating point instructions to load those +// values and hence helper functions are needed. +// The possibilities are (), (sf), (sf, sf), (sf, df), (df), (df, sf), (df, df) +// the helper function suffixs for these are: +// 0, 1, 5, 9, 2, 6, 10 +// this suffix can then be calculated as follows: +// for a given argument Arg: +// Arg1x, Arg2x = 1 : Arg is sf +// 2 : Arg is df +// 0: Arg is neither sf or df +// So this stub is the string for number Arg1x + Arg2x*4. +// However not all numbers between 0 and 10 are possible, we check anyway and +// assert if the impossible exists. +// + +unsigned int Mips16TargetLowering::getMips16HelperFunctionStubNumber + (ArgListTy &Args) const { + unsigned int resultNum = 0; + if (Args.size() >= 1) { + Type *t = Args[0].Ty; + if (t->isFloatTy()) { + resultNum = 1; + } + else if (t->isDoubleTy()) { + resultNum = 2; + } + } + if (resultNum) { + if (Args.size() >=2) { + Type *t = Args[1].Ty; + if (t->isFloatTy()) { + resultNum += 4; + } + else if (t->isDoubleTy()) { + resultNum += 8; + } + } + } + return resultNum; +} + +// +// Prefixes are attached to stub numbers depending on the return type. +// return type: float sf_ +// double df_ +// single complex sc_ +// double complext dc_ +// others NO PREFIX +// +// +// The full name of a helper function is__mips16_call_stub + +// return type dependent prefix + stub number +// +// FIXME: This is something that probably should be in a different source file +// and perhaps done differently but my main purpose is to not waste runtime +// on something that we can enumerate in the source. Another possibility is +// to have a python script to generate these mapping tables. This will do +// for now. There are a whole series of helper function mapping arrays, one +// for each return type class as outlined above. There there are 11 possible +// entries. Ones with 0 are ones which should never be selected. +// +// All the arrays are similar except for ones which return neither +// sf, df, sc, dc, in which we only care about ones which have sf or df as a +// first parameter. +// +#define P_ "__mips16_call_stub_" +#define MAX_STUB_NUMBER 10 +#define T1 P "1", P "2", 0, 0, P "5", P "6", 0, 0, P "9", P "10" +#define T P "0" , T1 +#define P P_ +static char const * vMips16Helper[MAX_STUB_NUMBER+1] = + {nullptr, T1 }; +#undef P +#define P P_ "sf_" +static char const * sfMips16Helper[MAX_STUB_NUMBER+1] = + { T }; +#undef P +#define P P_ "df_" +static char const * dfMips16Helper[MAX_STUB_NUMBER+1] = + { T }; +#undef P +#define P P_ "sc_" +static char const * scMips16Helper[MAX_STUB_NUMBER+1] = + { T }; +#undef P +#define P P_ "dc_" +static char const * dcMips16Helper[MAX_STUB_NUMBER+1] = + { T }; +#undef P +#undef P_ + + +const char* Mips16TargetLowering:: + getMips16HelperFunction + (Type* RetTy, ArgListTy &Args, bool &needHelper) const { + const unsigned int stubNum = getMips16HelperFunctionStubNumber(Args); +#ifndef NDEBUG + const unsigned int maxStubNum = 10; + assert(stubNum <= maxStubNum); + const bool validStubNum[maxStubNum+1] = + {true, true, true, false, false, true, true, false, false, true, true}; + assert(validStubNum[stubNum]); +#endif + const char *result; + if (RetTy->isFloatTy()) { + result = sfMips16Helper[stubNum]; + } + else if (RetTy ->isDoubleTy()) { + result = dfMips16Helper[stubNum]; + } + else if (RetTy->isStructTy()) { + // check if it's complex + if (RetTy->getNumContainedTypes() == 2) { + if ((RetTy->getContainedType(0)->isFloatTy()) && + (RetTy->getContainedType(1)->isFloatTy())) { + result = scMips16Helper[stubNum]; + } + else if ((RetTy->getContainedType(0)->isDoubleTy()) && + (RetTy->getContainedType(1)->isDoubleTy())) { + result = dcMips16Helper[stubNum]; + } + else { + llvm_unreachable("Uncovered condition"); + } + } + else { + llvm_unreachable("Uncovered condition"); + } + } + else { + if (stubNum == 0) { + needHelper = false; + return ""; + } + result = vMips16Helper[stubNum]; + } + needHelper = true; + return result; +} + +void Mips16TargetLowering:: +getOpndList(SmallVectorImpl<SDValue> &Ops, + std::deque< std::pair<unsigned, SDValue> > &RegsToPass, + bool IsPICCall, bool GlobalOrExternal, bool InternalLinkage, + bool IsCallReloc, CallLoweringInfo &CLI, SDValue Callee, + SDValue Chain) const { + SelectionDAG &DAG = CLI.DAG; + MachineFunction &MF = DAG.getMachineFunction(); + MipsFunctionInfo *FuncInfo = MF.getInfo<MipsFunctionInfo>(); + const char* Mips16HelperFunction = nullptr; + bool NeedMips16Helper = false; + + 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. + // and generate the helper + // + bool LookupHelper = true; + if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(CLI.Callee)) { + Mips16Libcall Find = { RTLIB::UNKNOWN_LIBCALL, S->getSymbol() }; + + if (std::binary_search(std::begin(HardFloatLibCalls), + std::end(HardFloatLibCalls), Find)) + LookupHelper = false; + else { + 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 + const Mips16IntrinsicHelperType *Helper = + std::lower_bound(std::begin(Mips16IntrinsicHelper), + std::end(Mips16IntrinsicHelper), IntrinsicFind); + if (Helper != std::end(Mips16IntrinsicHelper) && + *Helper == IntrinsicFind) { + Mips16HelperFunction = Helper->Helper; + NeedMips16Helper = true; + LookupHelper = false; + } + + } + } else if (GlobalAddressSDNode *G = + dyn_cast<GlobalAddressSDNode>(CLI.Callee)) { + Mips16Libcall Find = { RTLIB::UNKNOWN_LIBCALL, + G->getGlobal()->getName().data() }; + + if (std::binary_search(std::begin(HardFloatLibCalls), + std::end(HardFloatLibCalls), Find)) + LookupHelper = false; + } + if (LookupHelper) + Mips16HelperFunction = + getMips16HelperFunction(CLI.RetTy, CLI.getArgs(), NeedMips16Helper); + } + + SDValue JumpTarget = Callee; + + // T9 should contain the address of the callee function if + // -relocation-model=pic or it is an indirect call. + if (IsPICCall || !GlobalOrExternal) { + unsigned V0Reg = Mips::V0; + if (NeedMips16Helper) { + RegsToPass.push_front(std::make_pair(V0Reg, Callee)); + JumpTarget = DAG.getExternalSymbol(Mips16HelperFunction, + getPointerTy(DAG.getDataLayout())); + ExternalSymbolSDNode *S = cast<ExternalSymbolSDNode>(JumpTarget); + JumpTarget = getAddrGlobal(S, CLI.DL, JumpTarget.getValueType(), DAG, + MipsII::MO_GOT, Chain, + FuncInfo->callPtrInfo(S->getSymbol())); + } else + RegsToPass.push_front(std::make_pair((unsigned)Mips::T9, Callee)); + } + + Ops.push_back(JumpTarget); + + MipsTargetLowering::getOpndList(Ops, RegsToPass, IsPICCall, GlobalOrExternal, + InternalLinkage, IsCallReloc, CLI, Callee, + Chain); +} + +MachineBasicBlock *Mips16TargetLowering:: +emitSel16(unsigned Opc, MachineInstr *MI, MachineBasicBlock *BB) const { + if (DontExpandCondPseudos16) + return BB; + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + DebugLoc DL = MI->getDebugLoc(); + // To "insert" a SELECT_CC instruction, we actually have to insert the + // diamond control-flow pattern. The incoming instruction knows the + // destination vreg to set, the condition code register to branch on, the + // true/false values to select between, and a branch opcode to use. + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = ++BB->getIterator(); + + // thisMBB: + // ... + // TrueVal = ... + // setcc r1, r2, r3 + // bNE r1, r0, copy1MBB + // fallthrough --> copy0MBB + MachineBasicBlock *thisMBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, copy0MBB); + F->insert(It, sinkMBB); + + // Transfer the remainder of BB and its successor edges to sinkMBB. + sinkMBB->splice(sinkMBB->begin(), BB, + std::next(MachineBasicBlock::iterator(MI)), BB->end()); + sinkMBB->transferSuccessorsAndUpdatePHIs(BB); + + // Next, add the true and fallthrough blocks as its successors. + BB->addSuccessor(copy0MBB); + BB->addSuccessor(sinkMBB); + + BuildMI(BB, DL, TII->get(Opc)).addReg(MI->getOperand(3).getReg()) + .addMBB(sinkMBB); + + // copy0MBB: + // %FalseValue = ... + // # fallthrough to sinkMBB + BB = copy0MBB; + + // Update machine-CFG edges + BB->addSuccessor(sinkMBB); + + // sinkMBB: + // %Result = phi [ %TrueValue, thisMBB ], [ %FalseValue, copy0MBB ] + // ... + BB = sinkMBB; + + BuildMI(*BB, BB->begin(), DL, + TII->get(Mips::PHI), MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB) + .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +MachineBasicBlock * +Mips16TargetLowering::emitSelT16(unsigned Opc1, unsigned Opc2, MachineInstr *MI, + MachineBasicBlock *BB) const { + if (DontExpandCondPseudos16) + return BB; + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + DebugLoc DL = MI->getDebugLoc(); + // To "insert" a SELECT_CC instruction, we actually have to insert the + // diamond control-flow pattern. The incoming instruction knows the + // destination vreg to set, the condition code register to branch on, the + // true/false values to select between, and a branch opcode to use. + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = ++BB->getIterator(); + + // thisMBB: + // ... + // TrueVal = ... + // setcc r1, r2, r3 + // bNE r1, r0, copy1MBB + // fallthrough --> copy0MBB + MachineBasicBlock *thisMBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, copy0MBB); + F->insert(It, sinkMBB); + + // Transfer the remainder of BB and its successor edges to sinkMBB. + sinkMBB->splice(sinkMBB->begin(), BB, + std::next(MachineBasicBlock::iterator(MI)), BB->end()); + sinkMBB->transferSuccessorsAndUpdatePHIs(BB); + + // Next, add the true and fallthrough blocks as its successors. + BB->addSuccessor(copy0MBB); + BB->addSuccessor(sinkMBB); + + BuildMI(BB, DL, TII->get(Opc2)).addReg(MI->getOperand(3).getReg()) + .addReg(MI->getOperand(4).getReg()); + BuildMI(BB, DL, TII->get(Opc1)).addMBB(sinkMBB); + + // copy0MBB: + // %FalseValue = ... + // # fallthrough to sinkMBB + BB = copy0MBB; + + // Update machine-CFG edges + BB->addSuccessor(sinkMBB); + + // sinkMBB: + // %Result = phi [ %TrueValue, thisMBB ], [ %FalseValue, copy0MBB ] + // ... + BB = sinkMBB; + + BuildMI(*BB, BB->begin(), DL, + TII->get(Mips::PHI), MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB) + .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; + +} + +MachineBasicBlock * +Mips16TargetLowering::emitSeliT16(unsigned Opc1, unsigned Opc2, + MachineInstr *MI, + MachineBasicBlock *BB) const { + if (DontExpandCondPseudos16) + return BB; + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + DebugLoc DL = MI->getDebugLoc(); + // To "insert" a SELECT_CC instruction, we actually have to insert the + // diamond control-flow pattern. The incoming instruction knows the + // destination vreg to set, the condition code register to branch on, the + // true/false values to select between, and a branch opcode to use. + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = ++BB->getIterator(); + + // thisMBB: + // ... + // TrueVal = ... + // setcc r1, r2, r3 + // bNE r1, r0, copy1MBB + // fallthrough --> copy0MBB + MachineBasicBlock *thisMBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, copy0MBB); + F->insert(It, sinkMBB); + + // Transfer the remainder of BB and its successor edges to sinkMBB. + sinkMBB->splice(sinkMBB->begin(), BB, + std::next(MachineBasicBlock::iterator(MI)), BB->end()); + sinkMBB->transferSuccessorsAndUpdatePHIs(BB); + + // Next, add the true and fallthrough blocks as its successors. + BB->addSuccessor(copy0MBB); + BB->addSuccessor(sinkMBB); + + BuildMI(BB, DL, TII->get(Opc2)).addReg(MI->getOperand(3).getReg()) + .addImm(MI->getOperand(4).getImm()); + BuildMI(BB, DL, TII->get(Opc1)).addMBB(sinkMBB); + + // copy0MBB: + // %FalseValue = ... + // # fallthrough to sinkMBB + BB = copy0MBB; + + // Update machine-CFG edges + BB->addSuccessor(sinkMBB); + + // sinkMBB: + // %Result = phi [ %TrueValue, thisMBB ], [ %FalseValue, copy0MBB ] + // ... + BB = sinkMBB; + + BuildMI(*BB, BB->begin(), DL, + TII->get(Mips::PHI), MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB) + .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; + +} + +MachineBasicBlock * +Mips16TargetLowering::emitFEXT_T8I816_ins(unsigned BtOpc, unsigned CmpOpc, + MachineInstr *MI, + MachineBasicBlock *BB) const { + if (DontExpandCondPseudos16) + return BB; + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + unsigned regX = MI->getOperand(0).getReg(); + unsigned regY = MI->getOperand(1).getReg(); + MachineBasicBlock *target = MI->getOperand(2).getMBB(); + BuildMI(*BB, MI, MI->getDebugLoc(), TII->get(CmpOpc)).addReg(regX) + .addReg(regY); + BuildMI(*BB, MI, MI->getDebugLoc(), TII->get(BtOpc)).addMBB(target); + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +MachineBasicBlock *Mips16TargetLowering::emitFEXT_T8I8I16_ins( + unsigned BtOpc, unsigned CmpiOpc, unsigned CmpiXOpc, bool ImmSigned, + MachineInstr *MI, MachineBasicBlock *BB) const { + if (DontExpandCondPseudos16) + return BB; + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + unsigned regX = MI->getOperand(0).getReg(); + int64_t imm = MI->getOperand(1).getImm(); + MachineBasicBlock *target = MI->getOperand(2).getMBB(); + unsigned CmpOpc; + if (isUInt<8>(imm)) + CmpOpc = CmpiOpc; + else if ((!ImmSigned && isUInt<16>(imm)) || + (ImmSigned && isInt<16>(imm))) + CmpOpc = CmpiXOpc; + else + llvm_unreachable("immediate field not usable"); + BuildMI(*BB, MI, MI->getDebugLoc(), TII->get(CmpOpc)).addReg(regX) + .addImm(imm); + BuildMI(*BB, MI, MI->getDebugLoc(), TII->get(BtOpc)).addMBB(target); + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +static unsigned Mips16WhichOp8uOr16simm + (unsigned shortOp, unsigned longOp, int64_t Imm) { + if (isUInt<8>(Imm)) + return shortOp; + else if (isInt<16>(Imm)) + return longOp; + else + llvm_unreachable("immediate field not usable"); +} + +MachineBasicBlock * +Mips16TargetLowering::emitFEXT_CCRX16_ins(unsigned SltOpc, MachineInstr *MI, + MachineBasicBlock *BB) const { + if (DontExpandCondPseudos16) + return BB; + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + unsigned CC = MI->getOperand(0).getReg(); + unsigned regX = MI->getOperand(1).getReg(); + unsigned regY = MI->getOperand(2).getReg(); + BuildMI(*BB, MI, MI->getDebugLoc(), TII->get(SltOpc)).addReg(regX).addReg( + regY); + BuildMI(*BB, MI, MI->getDebugLoc(), + TII->get(Mips::MoveR3216), CC).addReg(Mips::T8); + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +MachineBasicBlock * +Mips16TargetLowering::emitFEXT_CCRXI16_ins(unsigned SltiOpc, unsigned SltiXOpc, + MachineInstr *MI, + MachineBasicBlock *BB) const { + if (DontExpandCondPseudos16) + return BB; + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + unsigned CC = MI->getOperand(0).getReg(); + unsigned regX = MI->getOperand(1).getReg(); + int64_t Imm = MI->getOperand(2).getImm(); + unsigned SltOpc = Mips16WhichOp8uOr16simm(SltiOpc, SltiXOpc, Imm); + BuildMI(*BB, MI, MI->getDebugLoc(), + TII->get(SltOpc)).addReg(regX).addImm(Imm); + BuildMI(*BB, MI, MI->getDebugLoc(), + TII->get(Mips::MoveR3216), CC).addReg(Mips::T8); + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; + +} diff --git a/contrib/llvm/lib/Target/Mips/Mips16ISelLowering.h b/contrib/llvm/lib/Target/Mips/Mips16ISelLowering.h new file mode 100644 index 0000000..d3b9f75 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16ISelLowering.h @@ -0,0 +1,82 @@ +//===-- Mips16ISelLowering.h - Mips16 DAG Lowering Interface ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Subclass of MipsTargetLowering specialized for mips16. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPS16ISELLOWERING_H +#define LLVM_LIB_TARGET_MIPS_MIPS16ISELLOWERING_H + +#include "MipsISelLowering.h" + +namespace llvm { + class Mips16TargetLowering : public MipsTargetLowering { + public: + explicit Mips16TargetLowering(const MipsTargetMachine &TM, + const MipsSubtarget &STI); + + bool allowsMisalignedMemoryAccesses(EVT VT, unsigned AddrSpace, + unsigned Align, + bool *Fast) const override; + + MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *MBB) const override; + + private: + bool isEligibleForTailCallOptimization( + const CCState &CCInfo, unsigned NextStackOffset, + const MipsFunctionInfo &FI) const override; + + void setMips16HardFloatLibCalls(); + + unsigned int + getMips16HelperFunctionStubNumber(ArgListTy &Args) const; + + const char *getMips16HelperFunction + (Type* RetTy, ArgListTy &Args, bool &needHelper) const; + + void + getOpndList(SmallVectorImpl<SDValue> &Ops, + std::deque< std::pair<unsigned, SDValue> > &RegsToPass, + bool IsPICCall, bool GlobalOrExternal, bool InternalLinkage, + bool IsCallReloc, CallLoweringInfo &CLI, SDValue Callee, + SDValue Chain) const override; + + MachineBasicBlock *emitSel16(unsigned Opc, MachineInstr *MI, + MachineBasicBlock *BB) const; + + MachineBasicBlock *emitSeliT16(unsigned Opc1, unsigned Opc2, + MachineInstr *MI, + MachineBasicBlock *BB) const; + + MachineBasicBlock *emitSelT16(unsigned Opc1, unsigned Opc2, + MachineInstr *MI, + MachineBasicBlock *BB) const; + + MachineBasicBlock *emitFEXT_T8I816_ins(unsigned BtOpc, unsigned CmpOpc, + MachineInstr *MI, + MachineBasicBlock *BB) const; + + MachineBasicBlock *emitFEXT_T8I8I16_ins( + unsigned BtOpc, unsigned CmpiOpc, unsigned CmpiXOpc, bool ImmSigned, + MachineInstr *MI, MachineBasicBlock *BB) const; + + MachineBasicBlock *emitFEXT_CCRX16_ins( + unsigned SltOpc, + MachineInstr *MI, MachineBasicBlock *BB) const; + + MachineBasicBlock *emitFEXT_CCRXI16_ins( + unsigned SltiOpc, unsigned SltiXOpc, + MachineInstr *MI, MachineBasicBlock *BB )const; + }; +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/Mips16InstrFormats.td b/contrib/llvm/lib/Target/Mips/Mips16InstrFormats.td new file mode 100644 index 0000000..4ff68be --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16InstrFormats.td @@ -0,0 +1,640 @@ +//===- Mips16InstrFormats.td - Mips Instruction Formats ----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Describe MIPS instructions format +// +// CPU INSTRUCTION FORMATS +// +// funct or f Function field +// +// immediate 4-,5-,8- or 11-bit immediate, branch displacement, or +// or imm address displacement +// +// op 5-bit major operation code +// +// rx 3-bit source or destination register +// +// ry 3-bit source or destination register +// +// rz 3-bit source or destination register +// +// sa 3- or 5-bit shift amount +// +//===----------------------------------------------------------------------===// + + +// Base class for Mips 16 Format +// This class does not depend on the instruction size +// +class MipsInst16_Base<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin>: Instruction +{ + + let Namespace = "Mips"; + + let OutOperandList = outs; + let InOperandList = ins; + + let AsmString = asmstr; + let Pattern = pattern; + let Itinerary = itin; + + let Predicates = [InMips16Mode]; +} + +// +// Generic Mips 16 Format +// +class MipsInst16<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin>: + MipsInst16_Base<outs, ins, asmstr, pattern, itin> +{ + field bits<16> Inst; + bits<5> Opcode = 0; + + // Top 5 bits are the 'opcode' field + let Inst{15-11} = Opcode; + + let Size=2; + field bits<16> SoftFail = 0; +} + +// +// For 32 bit extended instruction forms. +// +class MipsInst16_32<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin>: + MipsInst16_Base<outs, ins, asmstr, pattern, itin> +{ + field bits<32> Inst; + + let Size=4; + field bits<32> SoftFail = 0; +} + +class MipsInst16_EXTEND<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin>: + MipsInst16_32<outs, ins, asmstr, pattern, itin> +{ + let Inst{31-27} = 0b11110; +} + + + +// Mips Pseudo Instructions Format +class MipsPseudo16<dag outs, dag ins, string asmstr, list<dag> pattern>: + MipsInst16<outs, ins, asmstr, pattern, IIPseudo> { + let isCodeGenOnly = 1; + let isPseudo = 1; +} + + +//===----------------------------------------------------------------------===// +// Format I instruction class in Mips : <|opcode|imm11|> +//===----------------------------------------------------------------------===// + +class FI16<bits<5> op, dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<11> imm11; + + let Opcode = op; + + let Inst{10-0} = imm11; +} + +//===----------------------------------------------------------------------===// +// Format RI instruction class in Mips : <|opcode|rx|imm8|> +//===----------------------------------------------------------------------===// + +class FRI16<bits<5> op, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> rx; + bits<8> imm8; + + let Opcode = op; + + let Inst{10-8} = rx; + let Inst{7-0} = imm8; +} + +//===----------------------------------------------------------------------===// +// Format RR instruction class in Mips : <|opcode|rx|ry|funct|> +//===----------------------------------------------------------------------===// + +class FRR16<bits<5> _funct, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> rx; + bits<3> ry; + bits<5> funct; + + let Opcode = 0b11101; + let funct = _funct; + + let Inst{10-8} = rx; + let Inst{7-5} = ry; + let Inst{4-0} = funct; +} + +class FRRBreak16<dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<6> Code; + bits<5> funct; + + let Opcode = 0b11101; + let funct = 0b00101; + + let Inst{10-5} = Code; + let Inst{4-0} = funct; +} + +// +// For conversion functions. +// +class FRR_SF16<bits<5> _funct, bits<3> _subfunct, dag outs, dag ins, + string asmstr, list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> rx; + bits<3> subfunct; + bits<5> funct; + + let Opcode = 0b11101; // RR + let funct = _funct; + let subfunct = _subfunct; + + let Inst{10-8} = rx; + let Inst{7-5} = subfunct; + let Inst{4-0} = funct; +} + +// +// just used for breakpoint (hardware and software) instructions. +// +class FC16<bits<5> _funct, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<6> _code; // code is a keyword in tablegen + bits<5> funct; + + let Opcode = 0b11101; // RR + let funct = _funct; + + let Inst{10-5} = _code; + let Inst{4-0} = funct; +} + +// +// J(AL)R(C) subformat +// +class FRR16_JALRC<bits<1> _nd, bits<1> _l, bits<1> r_a, + dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> rx; + bits<1> nd; + bits<1> l; + bits<1> ra; + + let nd = _nd; + let l = _l; + let ra = r_a; + + let Opcode = 0b11101; + + let Inst{10-8} = rx; + let Inst{7} = nd; + let Inst{6} = l; + let Inst{5} = ra; + let Inst{4-0} = 0; +} + +//===----------------------------------------------------------------------===// +// Format RRI instruction class in Mips : <|opcode|rx|ry|imm5|> +//===----------------------------------------------------------------------===// + +class FRRI16<bits<5> op, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> rx; + bits<3> ry; + bits<5> imm5; + + let Opcode = op; + + + let Inst{10-8} = rx; + let Inst{7-5} = ry; + let Inst{4-0} = imm5; +} + +//===----------------------------------------------------------------------===// +// Format RRR instruction class in Mips : <|opcode|rx|ry|rz|f|> +//===----------------------------------------------------------------------===// + +class FRRR16<bits<2> _f, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> rx; + bits<3> ry; + bits<3> rz; + bits<2> f; + + let Opcode = 0b11100; + let f = _f; + + let Inst{10-8} = rx; + let Inst{7-5} = ry; + let Inst{4-2} = rz; + let Inst{1-0} = f; +} + +//===----------------------------------------------------------------------===// +// Format RRI-A instruction class in Mips : <|opcode|rx|ry|f|imm4|> +//===----------------------------------------------------------------------===// + +class FRRI_A16<bits<1> _f, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> rx; + bits<3> ry; + bits<1> f; + bits<4> imm4; + + let Opcode = 0b01000; + let f = _f; + + let Inst{10-8} = rx; + let Inst{7-5} = ry; + let Inst{4} = f; + let Inst{3-0} = imm4; +} + +//===----------------------------------------------------------------------===// +// Format Shift instruction class in Mips : <|opcode|rx|ry|sa|f|> +//===----------------------------------------------------------------------===// + +class FSHIFT16<bits<2> _f, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> rx; + bits<3> ry; + bits<3> sa; + bits<2> f; + + let Opcode = 0b00110; + let f = _f; + + let Inst{10-8} = rx; + let Inst{7-5} = ry; + let Inst{4-2} = sa; + let Inst{1-0} = f; +} + +//===----------------------------------------------------------------------===// +// Format i8 instruction class in Mips : <|opcode|funct|imm8> +//===----------------------------------------------------------------------===// + +class FI816<bits<3> _func, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> func; + bits<8> imm8; + + let Opcode = 0b01100; + let func = _func; + + let Inst{10-8} = func; + let Inst{7-0} = imm8; +} + +//===----------------------------------------------------------------------===// +// Format i8_MOVR32 instruction class in Mips : <|opcode|func|ry|r32> +//===----------------------------------------------------------------------===// + +class FI8_MOVR3216<dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + + bits<4> ry; + bits<4> r32; + + let Opcode = 0b01100; + + let Inst{10-8} = 0b111; + let Inst{7-4} = ry; + let Inst{3-0} = r32; + +} + + + +//===----------------------------------------------------------------------===// +// Format i8_MOV32R instruction class in Mips : <|opcode|func|r32|rz> +//===----------------------------------------------------------------------===// + +class FI8_MOV32R16<dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + + bits<3> func; + bits<5> r32; + bits<3> rz; + + + let Opcode = 0b01100; + + let Inst{10-8} = 0b101; + let Inst{7-5} = r32{2-0}; + let Inst{4-3} = r32{4-3}; + let Inst{2-0} = rz; + +} + +//===----------------------------------------------------------------------===// +// Format i8_SVRS instruction class in Mips : +// <|opcode|svrs|s|ra|s0|s1|framesize> +//===----------------------------------------------------------------------===// + +class FI8_SVRS16<bits<1> _s, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<1> s; + bits<1> ra = 0; + bits<1> s0 = 0; + bits<1> s1 = 0; + bits<4> framesize = 0; + + let s =_s; + let Opcode = 0b01100; + + let Inst{10-8} = 0b100; + let Inst{7} = s; + let Inst{6} = ra; + let Inst{5} = s0; + let Inst{4} = s1; + let Inst{3-0} = framesize; + +} + +//===----------------------------------------------------------------------===// +// Format JAL instruction class in Mips16 : +// <|opcode|svrs|s|ra|s0|s1|framesize> +//===----------------------------------------------------------------------===// + +class FJAL16<bits<1> _X, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_32<outs, ins, asmstr, pattern, itin> +{ + bits<1> X; + bits<26> imm26; + + + let X = _X; + + let Inst{31-27} = 0b00011; + let Inst{26} = X; + let Inst{25-21} = imm26{20-16}; + let Inst{20-16} = imm26{25-21}; + let Inst{15-0} = imm26{15-0}; + +} + +//===----------------------------------------------------------------------===// +// Format EXT-I instruction class in Mips16 : +// <|EXTEND|imm10:5|imm15:11|op|0|0|0|0|0|0|imm4:0> +//===----------------------------------------------------------------------===// + +class FEXT_I16<bits<5> _eop, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin> +{ + bits<16> imm16; + bits<5> eop; + + let eop = _eop; + + let Inst{26-21} = imm16{10-5}; + let Inst{20-16} = imm16{15-11}; + let Inst{15-11} = eop; + let Inst{10-5} = 0; + let Inst{4-0} = imm16{4-0}; + +} + +//===----------------------------------------------------------------------===// +// Format ASMACRO instruction class in Mips16 : +// <EXTEND|select|p4|p3|RRR|p2|p1|p0> +//===----------------------------------------------------------------------===// + +class FASMACRO16<dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin> +{ + bits<3> select; + bits<3> p4; + bits<5> p3; + bits<5> RRR = 0b11100; + bits<3> p2; + bits<3> p1; + bits<5> p0; + + + let Inst{26-24} = select; + let Inst{23-21} = p4; + let Inst{20-16} = p3; + let Inst{15-11} = RRR; + let Inst{10-8} = p2; + let Inst{7-5} = p1; + let Inst{4-0} = p0; + +} + + +//===----------------------------------------------------------------------===// +// Format EXT-RI instruction class in Mips16 : +// <|EXTEND|imm10:5|imm15:11|op|rx|0|0|0|imm4:0> +//===----------------------------------------------------------------------===// + +class FEXT_RI16<bits<5> _op, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin> +{ + bits<16> imm16; + bits<5> op; + bits<3> rx; + + let op = _op; + + let Inst{26-21} = imm16{10-5}; + let Inst{20-16} = imm16{15-11}; + let Inst{15-11} = op; + let Inst{10-8} = rx; + let Inst{7-5} = 0; + let Inst{4-0} = imm16{4-0}; + +} + +//===----------------------------------------------------------------------===// +// Format EXT-RRI instruction class in Mips16 : +// <|EXTEND|imm10:5|imm15:11|op|rx|ry|imm4:0> +//===----------------------------------------------------------------------===// + +class FEXT_RRI16<bits<5> _op, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin> +{ + bits<5> op; + bits<16> imm16; + bits<3> rx; + bits<3> ry; + + let op=_op; + + let Inst{26-21} = imm16{10-5}; + let Inst{20-16} = imm16{15-11}; + let Inst{15-11} = op; + let Inst{10-8} = rx; + let Inst{7-5} = ry; + let Inst{4-0} = imm16{4-0}; + +} + +//===----------------------------------------------------------------------===// +// Format EXT-RRI-A instruction class in Mips16 : +// <|EXTEND|imm10:4|imm14:11|RRI-A|rx|ry|f|imm3:0> +//===----------------------------------------------------------------------===// + +class FEXT_RRI_A16<bits<1> _f, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin> +{ + bits<15> imm15; + bits<3> rx; + bits<3> ry; + bits<1> f; + + let f = _f; + + let Inst{26-20} = imm15{10-4}; + let Inst{19-16} = imm15{14-11}; + let Inst{15-11} = 0b01000; + let Inst{10-8} = rx; + let Inst{7-5} = ry; + let Inst{4} = f; + let Inst{3-0} = imm15{3-0}; + +} + +//===----------------------------------------------------------------------===// +// Format EXT-SHIFT instruction class in Mips16 : +// <|EXTEND|sa 4:0|s5|0|SHIFT|rx|ry|0|f> +//===----------------------------------------------------------------------===// + +class FEXT_SHIFT16<bits<2> _f, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin> +{ + bits<6> sa6; + bits<3> rx; + bits<3> ry; + bits<2> f; + + let f = _f; + + let Inst{26-22} = sa6{4-0}; + let Inst{21} = sa6{5}; + let Inst{20-16} = 0; + let Inst{15-11} = 0b00110; + let Inst{10-8} = rx; + let Inst{7-5} = ry; + let Inst{4-2} = 0; + let Inst{1-0} = f; + +} + +//===----------------------------------------------------------------------===// +// Format EXT-I8 instruction class in Mips16 : +// <|EXTEND|imm10:5|imm15:11|I8|funct|0|imm4:0> +//===----------------------------------------------------------------------===// + +class FEXT_I816<bits<3> _funct, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin> +{ + bits<16> imm16; + bits<5> I8; + bits<3> funct; + + let funct = _funct; + let I8 = 0b00110; + + let Inst{26-21} = imm16{10-5}; + let Inst{20-16} = imm16{15-11}; + let Inst{15-11} = I8; + let Inst{10-8} = funct; + let Inst{7-5} = 0; + let Inst{4-0} = imm16{4-0}; + +} + +//===----------------------------------------------------------------------===// +// Format EXT-I8_SVRS instruction class in Mips16 : +// <|EXTEND|xsregs|framesize7:4|aregs|I8|SVRS|s|ra|s0|s1|framesize3:0> +//===----------------------------------------------------------------------===// + +class FEXT_I8_SVRS16<bits<1> s_, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin> +{ + bits<3> xsregs =0; + bits<8> framesize =0; + bits<3> aregs =0; + bits<5> I8 = 0b01100; + bits<3> SVRS = 0b100; + bits<1> s; + bits<1> ra = 0; + bits<1> s0 = 0; + bits<1> s1 = 0; + + let s= s_; + + let Inst{26-24} = xsregs; + let Inst{23-20} = framesize{7-4}; + let Inst{19} = 0; + let Inst{18-16} = aregs; + let Inst{15-11} = I8; + let Inst{10-8} = SVRS; + let Inst{7} = s; + let Inst{6} = ra; + let Inst{5} = s0; + let Inst{4} = s1; + let Inst{3-0} = framesize{3-0}; + + +} + diff --git a/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.cpp b/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.cpp new file mode 100644 index 0000000..da8ada4 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.cpp @@ -0,0 +1,520 @@ +//===-- Mips16InstrInfo.cpp - Mips16 Instruction Information --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips16 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// +#include "Mips16InstrInfo.h" +#include "InstPrinter/MipsInstPrinter.h" +#include "MipsMachineFunction.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +#include <cctype> + +using namespace llvm; + +#define DEBUG_TYPE "mips16-instrinfo" + +Mips16InstrInfo::Mips16InstrInfo(const MipsSubtarget &STI) + : MipsInstrInfo(STI, Mips::Bimm16), RI() {} + +const MipsRegisterInfo &Mips16InstrInfo::getRegisterInfo() const { + return RI; +} + +/// isLoadFromStackSlot - If the specified machine instruction is a direct +/// load from a stack slot, return the virtual or physical register number of +/// the destination along with the FrameIndex of the loaded stack slot. If +/// not, return 0. This predicate must return 0 if the instruction has +/// any side effects other than loading from the stack slot. +unsigned Mips16InstrInfo::isLoadFromStackSlot(const MachineInstr *MI, + int &FrameIndex) const { + return 0; +} + +/// isStoreToStackSlot - If the specified machine instruction is a direct +/// store to a stack slot, return the virtual or physical register number of +/// the source reg along with the FrameIndex of the loaded stack slot. If +/// not, return 0. This predicate must return 0 if the instruction has +/// any side effects other than storing to the stack slot. +unsigned Mips16InstrInfo::isStoreToStackSlot(const MachineInstr *MI, + int &FrameIndex) const { + return 0; +} + +void Mips16InstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const { + unsigned Opc = 0; + + if (Mips::CPU16RegsRegClass.contains(DestReg) && + Mips::GPR32RegClass.contains(SrcReg)) + Opc = Mips::MoveR3216; + else if (Mips::GPR32RegClass.contains(DestReg) && + Mips::CPU16RegsRegClass.contains(SrcReg)) + Opc = Mips::Move32R16; + else if ((SrcReg == Mips::HI0) && + (Mips::CPU16RegsRegClass.contains(DestReg))) + Opc = Mips::Mfhi16, SrcReg = 0; + + else if ((SrcReg == Mips::LO0) && + (Mips::CPU16RegsRegClass.contains(DestReg))) + Opc = Mips::Mflo16, SrcReg = 0; + + + assert(Opc && "Cannot copy registers"); + + MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(Opc)); + + if (DestReg) + MIB.addReg(DestReg, RegState::Define); + + if (SrcReg) + MIB.addReg(SrcReg, getKillRegState(KillSrc)); +} + +void Mips16InstrInfo::storeRegToStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned SrcReg, bool isKill, int FI, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const { + DebugLoc DL; + if (I != MBB.end()) DL = I->getDebugLoc(); + MachineMemOperand *MMO = GetMemOperand(MBB, FI, MachineMemOperand::MOStore); + unsigned Opc = 0; + if (Mips::CPU16RegsRegClass.hasSubClassEq(RC)) + Opc = Mips::SwRxSpImmX16; + assert(Opc && "Register class not handled!"); + BuildMI(MBB, I, DL, get(Opc)).addReg(SrcReg, getKillRegState(isKill)). + addFrameIndex(FI).addImm(Offset) + .addMemOperand(MMO); +} + +void Mips16InstrInfo::loadRegFromStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned DestReg, int FI, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const { + DebugLoc DL; + if (I != MBB.end()) DL = I->getDebugLoc(); + MachineMemOperand *MMO = GetMemOperand(MBB, FI, MachineMemOperand::MOLoad); + unsigned Opc = 0; + + if (Mips::CPU16RegsRegClass.hasSubClassEq(RC)) + Opc = Mips::LwRxSpImmX16; + assert(Opc && "Register class not handled!"); + BuildMI(MBB, I, DL, get(Opc), DestReg).addFrameIndex(FI).addImm(Offset) + .addMemOperand(MMO); +} + +bool Mips16InstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { + MachineBasicBlock &MBB = *MI->getParent(); + switch(MI->getDesc().getOpcode()) { + default: + return false; + case Mips::RetRA16: + ExpandRetRA16(MBB, MI, Mips::JrcRa16); + break; + } + + MBB.erase(MI); + return true; +} + +/// GetOppositeBranchOpc - Return the inverse of the specified +/// opcode, e.g. turning BEQ to BNE. +unsigned Mips16InstrInfo::getOppositeBranchOpc(unsigned Opc) const { + switch (Opc) { + case Mips::BeqzRxImmX16: return Mips::BnezRxImmX16; + case Mips::BnezRxImmX16: return Mips::BeqzRxImmX16; + case Mips::BeqzRxImm16: return Mips::BnezRxImm16; + case Mips::BnezRxImm16: return Mips::BeqzRxImm16; + case Mips::BteqzT8CmpX16: return Mips::BtnezT8CmpX16; + case Mips::BteqzT8SltX16: return Mips::BtnezT8SltX16; + case Mips::BteqzT8SltiX16: return Mips::BtnezT8SltiX16; + case Mips::Btnez16: return Mips::Bteqz16; + case Mips::BtnezX16: return Mips::BteqzX16; + case Mips::BtnezT8CmpiX16: return Mips::BteqzT8CmpiX16; + case Mips::BtnezT8SltuX16: return Mips::BteqzT8SltuX16; + case Mips::BtnezT8SltiuX16: return Mips::BteqzT8SltiuX16; + case Mips::Bteqz16: return Mips::Btnez16; + case Mips::BteqzX16: return Mips::BtnezX16; + case Mips::BteqzT8CmpiX16: return Mips::BtnezT8CmpiX16; + case Mips::BteqzT8SltuX16: return Mips::BtnezT8SltuX16; + case Mips::BteqzT8SltiuX16: return Mips::BtnezT8SltiuX16; + case Mips::BtnezT8CmpX16: return Mips::BteqzT8CmpX16; + case Mips::BtnezT8SltX16: return Mips::BteqzT8SltX16; + case Mips::BtnezT8SltiX16: return Mips::BteqzT8SltiX16; + } + llvm_unreachable("Illegal opcode!"); +} + +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; + 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 { + 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); + } +} + +// Adjust SP by FrameSize bytes. Restore RA, S0, S1 +void Mips16InstrInfo::restoreFrame(unsigned SP, int64_t FrameSize, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); + 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. +// This can only be called at times that we know that there is at least one free +// register. +// This is clearly safe at prologue and epilogue. +// +void Mips16InstrInfo::adjustStackPtrBig(unsigned SP, int64_t Amount, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned Reg1, unsigned Reg2) const { + DebugLoc DL; + // + // li reg1, constant + // move reg2, sp + // add reg1, reg1, reg2 + // move sp, reg1 + // + // + MachineInstrBuilder MIB1 = BuildMI(MBB, I, DL, get(Mips::LwConstant32), Reg1); + MIB1.addImm(Amount).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); + MIB3.addReg(Reg1); + MIB3.addReg(Reg2, RegState::Kill); + MachineInstrBuilder MIB4 = BuildMI(MBB, I, DL, get(Mips::Move32R16), + Mips::SP); + MIB4.addReg(Reg1, RegState::Kill); +} + +void Mips16InstrInfo::adjustStackPtrBigUnrestricted( + unsigned SP, int64_t Amount, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + llvm_unreachable("adjust stack pointer amount exceeded"); +} + +/// Adjust SP by Amount bytes. +void Mips16InstrInfo::adjustStackPtr(unsigned SP, int64_t Amount, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + if (Amount == 0) + return; + + if (isInt<16>(Amount)) // need to change to addiu sp, ....and isInt<16> + BuildAddiuSpImm(MBB, I, Amount); + else + adjustStackPtrBigUnrestricted(SP, Amount, MBB, I); +} + +/// This function generates the sequence of instructions needed to get the +/// result of adding register REG and immediate IMM. +unsigned Mips16InstrInfo::loadImmediate(unsigned FrameReg, int64_t Imm, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator II, + DebugLoc DL, unsigned &NewImm) const { + // + // given original instruction is: + // Instr rx, T[offset] where offset is too big. + // + // lo = offset & 0xFFFF + // hi = ((offset >> 16) + (lo >> 15)) & 0xFFFF; + // + // let T = temporary register + // li T, hi + // shl T, 16 + // add T, Rx, T + // + RegScavenger rs; + int32_t lo = Imm & 0xFFFF; + NewImm = lo; + int Reg =0; + int SpReg = 0; + + rs.enterBasicBlock(&MBB); + rs.forward(II); + // + // We need to know which registers can be used, in the case where there + // are not enough free registers. We exclude all registers that + // are used in the instruction that we are helping. + // // Consider all allocatable registers in the register class initially + BitVector Candidates = + RI.getAllocatableSet + (*II->getParent()->getParent(), &Mips::CPU16RegsRegClass); + // Exclude all the registers being used by the instruction. + for (unsigned i = 0, e = II->getNumOperands(); i != e; ++i) { + MachineOperand &MO = II->getOperand(i); + if (MO.isReg() && MO.getReg() != 0 && !MO.isDef() && + !TargetRegisterInfo::isVirtualRegister(MO.getReg())) + Candidates.reset(MO.getReg()); + } + + // If the same register was used and defined in an instruction, then + // it will not be in the list of candidates. + // + // we need to analyze the instruction that we are helping. + // we need to know if it defines register x but register x is not + // present as an operand of the instruction. this tells + // whether the register is live before the instruction. if it's not + // then we don't need to save it in case there are no free registers. + int DefReg = 0; + for (unsigned i = 0, e = II->getNumOperands(); i != e; ++i) { + MachineOperand &MO = II->getOperand(i); + if (MO.isReg() && MO.isDef()) { + DefReg = MO.getReg(); + break; + } + } + + BitVector Available = rs.getRegsAvailable(&Mips::CPU16RegsRegClass); + Available &= Candidates; + // + // we use T0 for the first register, if we need to save something away. + // we use T1 for the second register, if we need to save something away. + // + unsigned FirstRegSaved =0, SecondRegSaved=0; + unsigned FirstRegSavedTo = 0, SecondRegSavedTo = 0; + + Reg = Available.find_first(); + + if (Reg == -1) { + Reg = Candidates.find_first(); + Candidates.reset(Reg); + if (DefReg != Reg) { + FirstRegSaved = Reg; + FirstRegSavedTo = Mips::T0; + copyPhysReg(MBB, II, DL, FirstRegSavedTo, FirstRegSaved, true); + } + } + else + Available.reset(Reg); + BuildMI(MBB, II, DL, get(Mips::LwConstant32), Reg).addImm(Imm).addImm(-1); + NewImm = 0; + if (FrameReg == Mips::SP) { + SpReg = Available.find_first(); + if (SpReg == -1) { + SpReg = Candidates.find_first(); + // Candidates.reset(SpReg); // not really needed + if (DefReg!= SpReg) { + SecondRegSaved = SpReg; + SecondRegSavedTo = Mips::T1; + } + if (SecondRegSaved) + copyPhysReg(MBB, II, DL, SecondRegSavedTo, SecondRegSaved, true); + } + else + Available.reset(SpReg); + copyPhysReg(MBB, II, DL, SpReg, Mips::SP, false); + BuildMI(MBB, II, DL, get(Mips:: AdduRxRyRz16), Reg).addReg(SpReg, RegState::Kill) + .addReg(Reg); + } + else + BuildMI(MBB, II, DL, get(Mips:: AdduRxRyRz16), Reg).addReg(FrameReg) + .addReg(Reg, RegState::Kill); + if (FirstRegSaved || SecondRegSaved) { + II = std::next(II); + if (FirstRegSaved) + copyPhysReg(MBB, II, DL, FirstRegSaved, FirstRegSavedTo, true); + if (SecondRegSaved) + copyPhysReg(MBB, II, DL, SecondRegSaved, SecondRegSavedTo, true); + } + return Reg; +} + +unsigned Mips16InstrInfo::getAnalyzableBrOpc(unsigned Opc) const { + return (Opc == Mips::BeqzRxImmX16 || Opc == Mips::BimmX16 || + Opc == Mips::Bimm16 || + Opc == Mips::Bteqz16 || Opc == Mips::Btnez16 || + Opc == Mips::BeqzRxImm16 || Opc == Mips::BnezRxImm16 || + Opc == Mips::BnezRxImmX16 || Opc == Mips::BteqzX16 || + Opc == Mips::BteqzT8CmpX16 || Opc == Mips::BteqzT8CmpiX16 || + Opc == Mips::BteqzT8SltX16 || Opc == Mips::BteqzT8SltuX16 || + Opc == Mips::BteqzT8SltiX16 || Opc == Mips::BteqzT8SltiuX16 || + Opc == Mips::BtnezX16 || Opc == Mips::BtnezT8CmpX16 || + Opc == Mips::BtnezT8CmpiX16 || Opc == Mips::BtnezT8SltX16 || + Opc == Mips::BtnezT8SltuX16 || Opc == Mips::BtnezT8SltiX16 || + Opc == Mips::BtnezT8SltiuX16 ) ? Opc : 0; +} + +void Mips16InstrInfo::ExpandRetRA16(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned Opc) const { + BuildMI(MBB, I, I->getDebugLoc(), get(Opc)); +} + +const MCInstrDesc &Mips16InstrInfo::AddiuSpImm(int64_t Imm) const { + if (validSpImm8(Imm)) + return get(Mips::AddiuSpImm16); + else + return get(Mips::AddiuSpImmX16); +} + +void Mips16InstrInfo::BuildAddiuSpImm + (MachineBasicBlock &MBB, MachineBasicBlock::iterator I, int64_t Imm) const { + DebugLoc DL; + BuildMI(MBB, I, DL, AddiuSpImm(Imm)).addImm(Imm); +} + +const MipsInstrInfo *llvm::createMips16InstrInfo(const MipsSubtarget &STI) { + return new Mips16InstrInfo(STI); +} + +bool Mips16InstrInfo::validImmediate(unsigned Opcode, unsigned Reg, + int64_t Amount) { + switch (Opcode) { + case Mips::LbRxRyOffMemX16: + case Mips::LbuRxRyOffMemX16: + case Mips::LhRxRyOffMemX16: + case Mips::LhuRxRyOffMemX16: + case Mips::SbRxRyOffMemX16: + case Mips::ShRxRyOffMemX16: + case Mips::LwRxRyOffMemX16: + case Mips::SwRxRyOffMemX16: + case Mips::SwRxSpImmX16: + case Mips::LwRxSpImmX16: + return isInt<16>(Amount); + case Mips::AddiuRxRyOffMemX16: + if ((Reg == Mips::PC) || (Reg == Mips::SP)) + return isInt<16>(Amount); + return isInt<15>(Amount); + } + llvm_unreachable("unexpected Opcode in validImmediate"); +} + +/// Measure the specified inline asm to determine an approximation of its +/// length. +/// Comments (which run till the next SeparatorString or newline) do not +/// count as an instruction. +/// Any other non-whitespace text is considered an instruction, with +/// multiple instructions separated by SeparatorString or newlines. +/// Variable-length instructions are not handled here; this function +/// may be overloaded in the target code to do that. +/// We implement the special case of the .space directive taking only an +/// integer argument, which is the size in bytes. This is used for creating +/// inline code spacing for testing purposes using inline assembly. +/// +unsigned Mips16InstrInfo::getInlineAsmLength(const char *Str, + const MCAsmInfo &MAI) const { + + // Count the number of instructions in the asm. + bool atInsnStart = true; + unsigned Length = 0; + for (; *Str; ++Str) { + if (*Str == '\n' || strncmp(Str, MAI.getSeparatorString(), + strlen(MAI.getSeparatorString())) == 0) + atInsnStart = true; + if (atInsnStart && !std::isspace(static_cast<unsigned char>(*Str))) { + if (strncmp(Str, ".space", 6)==0) { + char *EStr; int Sz; + Sz = strtol(Str+6, &EStr, 10); + while (isspace(*EStr)) ++EStr; + if (*EStr=='\0') { + DEBUG(dbgs() << "parsed .space " << Sz << '\n'); + return Sz; + } + } + Length += MAI.getMaxInstLength(); + atInsnStart = false; + } + if (atInsnStart && strncmp(Str, MAI.getCommentString(), + strlen(MAI.getCommentString())) == 0) + atInsnStart = false; + } + + return Length; +} diff --git a/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.h b/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.h new file mode 100644 index 0000000..6540b40 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.h @@ -0,0 +1,128 @@ +//===-- Mips16InstrInfo.h - Mips16 Instruction Information ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips16 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPS16INSTRINFO_H +#define LLVM_LIB_TARGET_MIPS_MIPS16INSTRINFO_H + +#include "Mips16RegisterInfo.h" +#include "MipsInstrInfo.h" + +namespace llvm { +class MipsSubtarget; +class Mips16InstrInfo : public MipsInstrInfo { + const Mips16RegisterInfo RI; + +public: + explicit Mips16InstrInfo(const MipsSubtarget &STI); + + const MipsRegisterInfo &getRegisterInfo() const override; + + /// isLoadFromStackSlot - If the specified machine instruction is a direct + /// load from a stack slot, return the virtual or physical register number of + /// the destination along with the FrameIndex of the loaded stack slot. If + /// not, return 0. This predicate must return 0 if the instruction has + /// any side effects other than loading from the stack slot. + unsigned isLoadFromStackSlot(const MachineInstr *MI, + int &FrameIndex) const override; + + /// isStoreToStackSlot - If the specified machine instruction is a direct + /// store to a stack slot, return the virtual or physical register number of + /// the source reg along with the FrameIndex of the loaded stack slot. If + /// not, return 0. This predicate must return 0 if the instruction has + /// any side effects other than storing to the stack slot. + unsigned isStoreToStackSlot(const MachineInstr *MI, + int &FrameIndex) const override; + + void copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const override; + + void storeRegToStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const override; + + void loadRegFromStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const override; + + bool expandPostRAPseudo(MachineBasicBlock::iterator MI) const override; + + unsigned getOppositeBranchOpc(unsigned Opc) const override; + + // Adjust SP by FrameSize bytes. Save RA, S0, S1 + void makeFrame(unsigned SP, int64_t FrameSize, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + // Adjust SP by FrameSize bytes. Restore RA, S0, S1 + void restoreFrame(unsigned SP, int64_t FrameSize, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + + /// Adjust SP by Amount bytes. + void adjustStackPtr(unsigned SP, int64_t Amount, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const override; + + /// Emit a series of instructions to load an immediate. + // This is to adjust some FrameReg. We return the new register to be used + // in place of FrameReg and the adjusted immediate field (&NewImm) + // + unsigned loadImmediate(unsigned FrameReg, + int64_t Imm, MachineBasicBlock &MBB, + MachineBasicBlock::iterator II, DebugLoc DL, + unsigned &NewImm) const; + + static bool validImmediate(unsigned Opcode, unsigned Reg, int64_t Amount); + + static bool validSpImm8(int offset) { + return ((offset & 7) == 0) && isInt<11>(offset); + } + + // + // build the proper one based on the Imm field + // + + const MCInstrDesc& AddiuSpImm(int64_t Imm) const; + + void BuildAddiuSpImm + (MachineBasicBlock &MBB, MachineBasicBlock::iterator I, int64_t Imm) const; + + unsigned getInlineAsmLength(const char *Str, + const MCAsmInfo &MAI) const override; +private: + unsigned getAnalyzableBrOpc(unsigned Opc) const override; + + void ExpandRetRA16(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned Opc) const; + + // Adjust SP by Amount bytes where bytes can be up to 32bit number. + void adjustStackPtrBig(unsigned SP, int64_t Amount, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned Reg1, unsigned Reg2) const; + + // Adjust SP by Amount bytes where bytes can be up to 32bit number. + void adjustStackPtrBigUnrestricted(unsigned SP, int64_t Amount, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + +}; + +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.td b/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.td new file mode 100644 index 0000000..dad6ea4 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.td @@ -0,0 +1,1917 @@ +//===- Mips16InstrInfo.td - Target Description for Mips16 -*- tablegen -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes Mips16 instructions. +// +//===----------------------------------------------------------------------===// +// +// +// Mips Address +// +def addr16 : + ComplexPattern<iPTR, 3, "selectAddr16", [frameindex], [SDNPWantParent]>; + +// +// Address operand +def mem16 : Operand<i32> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops CPU16Regs, simm16, CPU16RegsPlusSP); + let EncoderMethod = "getMemEncoding"; +} + +def mem16_ea : Operand<i32> { + let PrintMethod = "printMemOperandEA"; + let MIOperandInfo = (ops CPU16RegsPlusSP, simm16); + let EncoderMethod = "getMemEncoding"; +} + +// +// I-type instruction format +// +// this is only used by bimm. the actual assembly value is a 12 bit signed +// number +// +class FI16_ins<bits<5> op, string asmstr, InstrItinClass itin>: + FI16<op, (outs), (ins brtarget:$imm16), + !strconcat(asmstr, "\t$imm16 # 16 bit inst"), [], itin>; + +// +// +// I8 instruction format +// + +class FI816_ins_base<bits<3> _func, string asmstr, + string asmstr2, InstrItinClass itin>: + FI816<_func, (outs), (ins simm16:$imm), !strconcat(asmstr, asmstr2), + [], itin>; + +class FI816_ins<bits<3> _func, string asmstr, + InstrItinClass itin>: + FI816_ins_base<_func, asmstr, "\t$imm # 16 bit inst", itin>; + +class FI816_SP_ins<bits<3> _func, string asmstr, + InstrItinClass itin>: + FI816_ins_base<_func, asmstr, "\t$$sp, $imm # 16 bit inst", itin>; + +// +// RI instruction format +// + + +class FRI16_ins_base<bits<5> op, string asmstr, string asmstr2, + InstrItinClass itin>: + FRI16<op, (outs CPU16Regs:$rx), (ins simm16:$imm), + !strconcat(asmstr, asmstr2), [], itin>; + +class FRI16_ins<bits<5> op, string asmstr, + InstrItinClass itin>: + FRI16_ins_base<op, asmstr, "\t$rx, $imm \t# 16 bit inst", itin>; + +class FRI16_TCP_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FRI16<_op, (outs CPU16Regs:$rx), (ins pcrel16:$imm, i32imm:$size), + !strconcat(asmstr, "\t$rx, $imm\t# 16 bit inst"), [], itin>; + +class FRI16R_ins_base<bits<5> op, string asmstr, string asmstr2, + InstrItinClass itin>: + FRI16<op, (outs), (ins CPU16Regs:$rx, simm16:$imm), + !strconcat(asmstr, asmstr2), [], itin>; + +class FRI16R_ins<bits<5> op, string asmstr, + InstrItinClass itin>: + FRI16R_ins_base<op, asmstr, "\t$rx, $imm \t# 16 bit inst", itin>; + +class F2RI16_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FRI16<_op, (outs CPU16Regs:$rx), (ins CPU16Regs:$rx_, simm16:$imm), + !strconcat(asmstr, "\t$rx, $imm\t# 16 bit inst"), [], itin> { + let Constraints = "$rx_ = $rx"; +} + +class FRI16_B_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FRI16<_op, (outs), (ins CPU16Regs:$rx, brtarget:$imm), + !strconcat(asmstr, "\t$rx, $imm # 16 bit inst"), [], itin>; +// +// Compare a register and immediate and place result in CC +// Implicit use of T8 +// +// EXT-CCRR Instruction format +// +class FEXT_CCRXI16_ins<string asmstr>: + MipsPseudo16<(outs CPU16Regs:$cc), (ins CPU16Regs:$rx, simm16:$imm), + !strconcat(asmstr, "\t$rx, $imm\n\tmove\t$cc, $$t8"), []> { + let isCodeGenOnly=1; + let usesCustomInserter = 1; +} + +// JAL and JALX instruction format +// +class FJAL16_ins<bits<1> _X, string asmstr, + InstrItinClass itin>: + FJAL16<_X, (outs), (ins simm20:$imm), + !strconcat(asmstr, "\t$imm\n\tnop"),[], + itin> { + let isCodeGenOnly=1; + 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 +// +class FEXT_I16_ins<bits<5> eop, string asmstr, InstrItinClass itin> : + FEXT_I16<eop, (outs), (ins brtarget:$imm16), + !strconcat(asmstr, "\t$imm16"),[], itin>; + +// +// EXT-I8 instruction format +// + +class FEXT_I816_ins_base<bits<3> _func, string asmstr, + string asmstr2, InstrItinClass itin>: + FEXT_I816<_func, (outs), (ins simm16:$imm), !strconcat(asmstr, asmstr2), + [], itin>; + +class FEXT_I816_ins<bits<3> _func, string asmstr, + InstrItinClass itin>: + FEXT_I816_ins_base<_func, asmstr, "\t$imm", itin>; + +class FEXT_I816_SP_ins<bits<3> _func, string asmstr, + InstrItinClass itin>: + FEXT_I816_ins_base<_func, asmstr, "\t$$sp, $imm", itin>; + +// +// Assembler formats in alphabetical order. +// Natural and pseudos are mixed together. +// +// Compare two registers and place result in CC +// Implicit use of T8 +// +// CC-RR Instruction format +// +class FCCRR16_ins<string asmstr> : + MipsPseudo16<(outs CPU16Regs:$cc), (ins CPU16Regs:$rx, CPU16Regs:$ry), + !strconcat(asmstr, "\t$rx, $ry\n\tmove\t$cc, $$t8"), []> { + let isCodeGenOnly=1; + let usesCustomInserter = 1; +} + +// +// EXT-RI instruction format +// + +class FEXT_RI16_ins_base<bits<5> _op, string asmstr, string asmstr2, + InstrItinClass itin>: + FEXT_RI16<_op, (outs CPU16Regs:$rx), (ins simm16:$imm), + !strconcat(asmstr, asmstr2), [], itin>; + +class FEXT_RI16_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FEXT_RI16_ins_base<_op, asmstr, "\t$rx, $imm", itin>; + +class FEXT_RI16R_ins_base<bits<5> _op, string asmstr, string asmstr2, + InstrItinClass itin>: + FEXT_RI16<_op, (outs ), (ins CPU16Regs:$rx, simm16:$imm), + !strconcat(asmstr, asmstr2), [], itin>; + +class FEXT_RI16R_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FEXT_RI16R_ins_base<_op, asmstr, "\t$rx, $imm", itin>; + +class FEXT_RI16_PC_ins<bits<5> _op, string asmstr, InstrItinClass itin>: + FEXT_RI16_ins_base<_op, asmstr, "\t$rx, $$pc, $imm", itin>; + +class FEXT_RI16_B_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FEXT_RI16<_op, (outs), (ins CPU16Regs:$rx, brtarget:$imm), + !strconcat(asmstr, "\t$rx, $imm"), [], itin>; + +class FEXT_RI16_TCP_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FEXT_RI16<_op, (outs CPU16Regs:$rx), (ins pcrel16:$imm, i32imm:$size), + !strconcat(asmstr, "\t$rx, $imm"), [], itin>; + +class FEXT_2RI16_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FEXT_RI16<_op, (outs CPU16Regs:$rx), (ins CPU16Regs:$rx_, simm16:$imm), + !strconcat(asmstr, "\t$rx, $imm"), [], itin> { + let Constraints = "$rx_ = $rx"; +} + + +// this has an explicit sp argument that we ignore to work around a problem +// in the compiler +class FEXT_RI16_SP_explicit_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FEXT_RI16<_op, (outs CPU16Regs:$rx), (ins CPUSPReg:$ry, simm16:$imm), + !strconcat(asmstr, "\t$rx, $imm ( $ry ); "), [], itin>; + +class FEXT_RI16_SP_Store_explicit_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FEXT_RI16<_op, (outs), (ins CPU16Regs:$rx, CPUSPReg:$ry, simm16:$imm), + !strconcat(asmstr, "\t$rx, $imm ( $ry ); "), [], itin>; + +// +// EXT-RRI instruction format +// + +class FEXT_RRI16_mem_ins<bits<5> op, string asmstr, Operand MemOpnd, + InstrItinClass itin>: + FEXT_RRI16<op, (outs CPU16Regs:$ry), (ins MemOpnd:$addr), + !strconcat(asmstr, "\t$ry, $addr"), [], itin>; + +class FEXT_RRI16_mem2_ins<bits<5> op, string asmstr, Operand MemOpnd, + InstrItinClass itin>: + FEXT_RRI16<op, (outs ), (ins CPU16Regs:$ry, MemOpnd:$addr), + !strconcat(asmstr, "\t$ry, $addr"), [], itin>; + +// +// +// EXT-RRI-A instruction format +// + +class FEXT_RRI_A16_mem_ins<bits<1> op, string asmstr, Operand MemOpnd, + InstrItinClass itin>: + FEXT_RRI_A16<op, (outs CPU16Regs:$ry), (ins MemOpnd:$addr), + !strconcat(asmstr, "\t$ry, $addr"), [], itin>; + +// +// EXT-SHIFT instruction format +// +class FEXT_SHIFT16_ins<bits<2> _f, string asmstr, InstrItinClass itin>: + FEXT_SHIFT16<_f, (outs CPU16Regs:$rx), (ins CPU16Regs:$ry, uimm5:$sa), + !strconcat(asmstr, "\t$rx, $ry, $sa"), [], itin>; + +// +// EXT-T8I8 +// +class FEXT_T8I816_ins<string asmstr, string asmstr2>: + MipsPseudo16<(outs), + (ins CPU16Regs:$rx, CPU16Regs:$ry, brtarget:$imm), + !strconcat(asmstr2, !strconcat("\t$rx, $ry\n\t", + !strconcat(asmstr, "\t$imm"))),[]> { + let isCodeGenOnly=1; + let usesCustomInserter = 1; +} + +// +// EXT-T8I8I +// +class FEXT_T8I8I16_ins<string asmstr, string asmstr2>: + MipsPseudo16<(outs), + (ins CPU16Regs:$rx, simm16:$imm, brtarget:$targ), + !strconcat(asmstr2, !strconcat("\t$rx, $imm\n\t", + !strconcat(asmstr, "\t$targ"))), []> { + let isCodeGenOnly=1; + let usesCustomInserter = 1; +} +// + + +// +// I8_MOVR32 instruction format (used only by the MOVR32 instructio +// +class FI8_MOVR3216_ins<string asmstr, InstrItinClass itin>: + FI8_MOVR3216<(outs CPU16Regs:$rz), (ins GPR32:$r32), + !strconcat(asmstr, "\t$rz, $r32"), [], itin>; + +// +// I8_MOV32R instruction format (used only by MOV32R instruction) +// + +class FI8_MOV32R16_ins<string asmstr, InstrItinClass itin>: + FI8_MOV32R16<(outs GPR32:$r32), (ins CPU16Regs:$rz), + !strconcat(asmstr, "\t$r32, $rz"), [], itin>; + +// +// This are pseudo formats for multiply +// This first one can be changed to non-pseudo now. +// +// MULT +// +class FMULT16_ins<string asmstr, InstrItinClass itin> : + MipsPseudo16<(outs), (ins CPU16Regs:$rx, CPU16Regs:$ry), + !strconcat(asmstr, "\t$rx, $ry"), []>; + +// +// MULT-LO +// +class FMULT16_LO_ins<string asmstr, InstrItinClass itin> : + MipsPseudo16<(outs CPU16Regs:$rz), (ins CPU16Regs:$rx, CPU16Regs:$ry), + !strconcat(asmstr, "\t$rx, $ry\n\tmflo\t$rz"), []> { + let isCodeGenOnly=1; +} + +// +// RR-type instruction format +// + +class FRR16_ins<bits<5> f, string asmstr, InstrItinClass itin> : + FRR16<f, (outs CPU16Regs:$rx), (ins CPU16Regs:$ry), + !strconcat(asmstr, "\t$rx, $ry"), [], itin> { +} + +class FRRBreakNull16_ins<string asmstr, InstrItinClass itin> : + FRRBreak16<(outs), (ins), asmstr, [], itin> { + let Code=0; +} + +class FRR16R_ins<bits<5> f, string asmstr, InstrItinClass itin> : + FRR16<f, (outs), (ins CPU16Regs:$rx, CPU16Regs:$ry), + !strconcat(asmstr, "\t$rx, $ry"), [], itin> { +} + +class FRRTR16_ins<string asmstr> : + MipsPseudo16<(outs CPU16Regs:$rz), (ins CPU16Regs:$rx, CPU16Regs:$ry), + !strconcat(asmstr, "\t$rx, $ry\n\tmove\t$rz, $$t8"), []> ; + +// +// maybe refactor but need a $zero as a dummy first parameter +// +class FRR16_div_ins<bits<5> f, string asmstr, InstrItinClass itin> : + FRR16<f, (outs ), (ins CPU16Regs:$rx, CPU16Regs:$ry), + !strconcat(asmstr, "\t$$zero, $rx, $ry"), [], itin> ; + +class FUnaryRR16_ins<bits<5> f, string asmstr, InstrItinClass itin> : + FRR16<f, (outs CPU16Regs:$rx), (ins CPU16Regs:$ry), + !strconcat(asmstr, "\t$rx, $ry"), [], itin> ; + + +class FRR16_M_ins<bits<5> f, string asmstr, + InstrItinClass itin> : + FRR16<f, (outs CPU16Regs:$rx), (ins), + !strconcat(asmstr, "\t$rx"), [], itin>; + +class FRxRxRy16_ins<bits<5> f, string asmstr, + InstrItinClass itin> : + FRR16<f, (outs CPU16Regs:$rz), (ins CPU16Regs:$rx, CPU16Regs:$ry), + !strconcat(asmstr, "\t$rz, $ry"), + [], itin> { + let Constraints = "$rx = $rz"; +} + +let rx=0 in +class FRR16_JALRC_RA_only_ins<bits<1> nd_, bits<1> l_, + string asmstr, InstrItinClass itin>: + FRR16_JALRC<nd_, l_, 1, (outs), (ins), !strconcat(asmstr, "\t $$ra"), + [], itin> ; + + +class FRR16_JALRC_ins<bits<1> nd, bits<1> l, bits<1> ra, + string asmstr, InstrItinClass itin>: + FRR16_JALRC<nd, l, ra, (outs), (ins CPU16Regs:$rx), + !strconcat(asmstr, "\t $rx"), [], itin> ; + +class FRR_SF16_ins + <bits<5> _funct, bits<3> _subfunc, + string asmstr, InstrItinClass itin>: + FRR_SF16<_funct, _subfunc, (outs CPU16Regs:$rx), (ins CPU16Regs:$rx_), + !strconcat(asmstr, "\t $rx"), + [], itin> { + let Constraints = "$rx_ = $rx"; + } +// +// RRR-type instruction format +// + +class FRRR16_ins<bits<2> _f, string asmstr, InstrItinClass itin> : + FRRR16<_f, (outs CPU16Regs:$rz), (ins CPU16Regs:$rx, CPU16Regs:$ry), + !strconcat(asmstr, "\t$rz, $rx, $ry"), [], itin>; + +// +// These Sel patterns support the generation of conditional move +// pseudo instructions. +// +// The nomenclature uses the components making up the pseudo and may +// be a bit counter intuitive when compared with the end result we seek. +// For example using a bqez in the example directly below results in the +// conditional move being done if the tested register is not zero. +// I considered in easier to check by keeping the pseudo consistent with +// it's components but it could have been done differently. +// +// The simplest case is when can test and operand directly and do the +// conditional move based on a simple mips16 conditional +// branch instruction. +// for example: +// if $op == beqz or bnez: +// +// $op1 $rt, .+4 +// move $rd, $rs +// +// if $op == beqz, then if $rt != 0, then the conditional assignment +// $rd = $rs is done. + +// if $op == bnez, then if $rt == 0, then the conditional assignment +// $rd = $rs is done. +// +// So this pseudo class only has one operand, i.e. op +// +class Sel<string op>: + MipsPseudo16<(outs CPU16Regs:$rd_), (ins CPU16Regs:$rd, CPU16Regs:$rs, + CPU16Regs:$rt), + !strconcat(op, "\t$rt, .+4\n\t\n\tmove $rd, $rs"), []> { + //let isCodeGenOnly=1; + let Constraints = "$rd = $rd_"; + let usesCustomInserter = 1; +} + +// +// The next two instruction classes allow for an operand which tests +// two operands and returns a value in register T8 and +//then does a conditional branch based on the value of T8 +// + +// op2 can be cmpi or slti/sltiu +// op1 can bteqz or btnez +// the operands for op2 are a register and a signed constant +// +// $op2 $t, $imm ;test register t and branch conditionally +// $op1 .+4 ;op1 is a conditional branch +// move $rd, $rs +// +// +class SeliT<string op1, string op2>: + MipsPseudo16<(outs CPU16Regs:$rd_), (ins CPU16Regs:$rd, CPU16Regs:$rs, + CPU16Regs:$rl, simm16:$imm), + !strconcat(op2, + !strconcat("\t$rl, $imm\n\t", + !strconcat(op1, "\t.+4\n\tmove $rd, $rs"))), []> { + let isCodeGenOnly=1; + let Constraints = "$rd = $rd_"; + let usesCustomInserter = 1; +} + +// +// op2 can be cmp or slt/sltu +// op1 can be bteqz or btnez +// the operands for op2 are two registers +// op1 is a conditional branch +// +// +// $op2 $rl, $rr ;test registers rl,rr +// $op1 .+4 ;op2 is a conditional branch +// move $rd, $rs +// +// +class SelT<string op1, string op2>: + MipsPseudo16<(outs CPU16Regs:$rd_), + (ins CPU16Regs:$rd, CPU16Regs:$rs, + CPU16Regs:$rl, CPU16Regs:$rr), + !strconcat(op2, + !strconcat("\t$rl, $rr\n\t", + !strconcat(op1, "\t.+4\n\tmove $rd, $rs"))), []> { + let isCodeGenOnly=1; + let Constraints = "$rd = $rd_"; + let usesCustomInserter = 1; +} + +// +// 32 bit constant +// +def imm32: Operand<i32>; + +def Constant32: + MipsPseudo16<(outs), (ins imm32:$imm), "\t.word $imm", []>; + +def LwConstant32: + MipsPseudo16<(outs CPU16Regs:$rx), (ins imm32:$imm, imm32:$constid), + "lw\t$rx, 1f\n\tb\t2f\n\t.align\t2\n1: \t.word\t$imm\n2:", []>; + + +// +// Some general instruction class info +// +// + +class ArithLogic16Defs<bit isCom=0> { + bits<5> shamt = 0; + bit isCommutable = isCom; + bit isReMaterializable = 1; + bit hasSideEffects = 0; +} + +class branch16 { + bit isBranch = 1; + bit isTerminator = 1; + bit isBarrier = 1; +} + +class cbranch16 { + bit isBranch = 1; + bit isTerminator = 1; +} + +class MayLoad { + bit mayLoad = 1; +} + +class MayStore { + bit mayStore = 1; +} +// + + +// Format: ADDIU rx, immediate MIPS16e +// Purpose: Add Immediate Unsigned Word (2-Operand, Extended) +// To add a constant to a 32-bit integer. +// +def AddiuRxImmX16: FEXT_RI16_ins<0b01001, "addiu", IIM16Alu>; + +def AddiuRxRxImm16: F2RI16_ins<0b01001, "addiu", IIM16Alu>, + ArithLogic16Defs<0> { + let AddedComplexity = 5; +} +def AddiuRxRxImmX16: FEXT_2RI16_ins<0b01001, "addiu", IIM16Alu>, + ArithLogic16Defs<0> { + let isCodeGenOnly = 1; +} + +def AddiuRxRyOffMemX16: + FEXT_RRI_A16_mem_ins<0, "addiu", mem16_ea, IIM16Alu>; + +// + +// Format: ADDIU rx, pc, immediate MIPS16e +// Purpose: Add Immediate Unsigned Word (3-Operand, PC-Relative, Extended) +// To add a constant to the program counter. +// +def AddiuRxPcImmX16: FEXT_RI16_PC_ins<0b00001, "addiu", IIM16Alu>; + +// +// Format: ADDIU sp, immediate MIPS16e +// Purpose: Add Immediate Unsigned Word (2-Operand, SP-Relative, Extended) +// To add a constant to the stack pointer. +// +def AddiuSpImm16 + : FI816_SP_ins<0b011, "addiu", IIM16Alu> { + let Defs = [SP]; + let Uses = [SP]; + let AddedComplexity = 5; +} + +def AddiuSpImmX16 + : FEXT_I816_SP_ins<0b011, "addiu", IIM16Alu> { + let Defs = [SP]; + let Uses = [SP]; +} + +// +// Format: ADDU rz, rx, ry MIPS16e +// Purpose: Add Unsigned Word (3-Operand) +// To add 32-bit integers. +// + +def AdduRxRyRz16: FRRR16_ins<01, "addu", IIM16Alu>, ArithLogic16Defs<1>; + +// +// Format: AND rx, ry MIPS16e +// Purpose: AND +// To do a bitwise logical AND. + +def AndRxRxRy16: FRxRxRy16_ins<0b01100, "and", IIM16Alu>, ArithLogic16Defs<1>; + + +// +// Format: BEQZ rx, offset MIPS16e +// Purpose: Branch on Equal to Zero +// To test a GPR then do a PC-relative conditional branch. +// +def BeqzRxImm16: FRI16_B_ins<0b00100, "beqz", IIM16Alu>, cbranch16; + + +// +// Format: BEQZ rx, offset MIPS16e +// Purpose: Branch on Equal to Zero (Extended) +// To test a GPR then do a PC-relative conditional branch. +// +def BeqzRxImmX16: FEXT_RI16_B_ins<0b00100, "beqz", IIM16Alu>, cbranch16; + +// +// Format: B offset MIPS16e +// Purpose: Unconditional Branch (Extended) +// To do an unconditional PC-relative branch. +// + +def Bimm16: FI16_ins<0b00010, "b", IIM16Alu>, branch16; + +// Format: B offset MIPS16e +// Purpose: Unconditional Branch +// To do an unconditional PC-relative branch. +// +def BimmX16: FEXT_I16_ins<0b00010, "b", IIM16Alu>, branch16; + +// +// Format: BNEZ rx, offset MIPS16e +// Purpose: Branch on Not Equal to Zero +// To test a GPR then do a PC-relative conditional branch. +// +def BnezRxImm16: FRI16_B_ins<0b00101, "bnez", IIM16Alu>, cbranch16; + +// +// Format: BNEZ rx, offset MIPS16e +// Purpose: Branch on Not Equal to Zero (Extended) +// To test a GPR then do a PC-relative conditional branch. +// +def BnezRxImmX16: FEXT_RI16_B_ins<0b00101, "bnez", IIM16Alu>, cbranch16; + + +// +//Format: BREAK immediate +// Purpose: Breakpoint +// To cause a Breakpoint exception. + +def Break16: FRRBreakNull16_ins<"break 0", NoItinerary>; +// +// Format: BTEQZ offset MIPS16e +// Purpose: Branch on T Equal to Zero (Extended) +// To test special register T then do a PC-relative conditional branch. +// +def Bteqz16: FI816_ins<0b000, "bteqz", IIM16Alu>, cbranch16 { + let Uses = [T8]; +} + +def BteqzX16: FEXT_I816_ins<0b000, "bteqz", IIM16Alu>, cbranch16 { + let Uses = [T8]; +} + +def BteqzT8CmpX16: FEXT_T8I816_ins<"bteqz", "cmp">, cbranch16; + +def BteqzT8CmpiX16: FEXT_T8I8I16_ins<"bteqz", "cmpi">, + cbranch16; + +def BteqzT8SltX16: FEXT_T8I816_ins<"bteqz", "slt">, cbranch16; + +def BteqzT8SltuX16: FEXT_T8I816_ins<"bteqz", "sltu">, cbranch16; + +def BteqzT8SltiX16: FEXT_T8I8I16_ins<"bteqz", "slti">, cbranch16; + +def BteqzT8SltiuX16: FEXT_T8I8I16_ins<"bteqz", "sltiu">, + cbranch16; + +// +// Format: BTNEZ offset MIPS16e +// Purpose: Branch on T Not Equal to Zero (Extended) +// To test special register T then do a PC-relative conditional branch. +// + +def Btnez16: FI816_ins<0b001, "btnez", IIM16Alu>, cbranch16 { + let Uses = [T8]; +} + +def BtnezX16: FEXT_I816_ins<0b001, "btnez", IIM16Alu> ,cbranch16 { + let Uses = [T8]; +} + +def BtnezT8CmpX16: FEXT_T8I816_ins<"btnez", "cmp">, cbranch16; + +def BtnezT8CmpiX16: FEXT_T8I8I16_ins<"btnez", "cmpi">, cbranch16; + +def BtnezT8SltX16: FEXT_T8I816_ins<"btnez", "slt">, cbranch16; + +def BtnezT8SltuX16: FEXT_T8I816_ins<"btnez", "sltu">, cbranch16; + +def BtnezT8SltiX16: FEXT_T8I8I16_ins<"btnez", "slti">, cbranch16; + +def BtnezT8SltiuX16: FEXT_T8I8I16_ins<"btnez", "sltiu">, + cbranch16; + +// +// Format: CMP rx, ry MIPS16e +// Purpose: Compare +// To compare the contents of two GPRs. +// +def CmpRxRy16: FRR16R_ins<0b01010, "cmp", IIM16Alu> { + let Defs = [T8]; +} + +// +// Format: CMPI rx, immediate MIPS16e +// Purpose: Compare Immediate +// To compare a constant with the contents of a GPR. +// +def CmpiRxImm16: FRI16R_ins<0b01110, "cmpi", IIM16Alu> { + let Defs = [T8]; +} + +// +// Format: CMPI rx, immediate MIPS16e +// Purpose: Compare Immediate (Extended) +// To compare a constant with the contents of a GPR. +// +def CmpiRxImmX16: FEXT_RI16R_ins<0b01110, "cmpi", IIM16Alu> { + let Defs = [T8]; +} + + +// +// Format: DIV rx, ry MIPS16e +// Purpose: Divide Word +// To divide 32-bit signed integers. +// +def DivRxRy16: FRR16_div_ins<0b11010, "div", IIM16Alu> { + let Defs = [HI0, LO0]; +} + +// +// Format: DIVU rx, ry MIPS16e +// Purpose: Divide Unsigned Word +// To divide 32-bit unsigned integers. +// +def DivuRxRy16: FRR16_div_ins<0b11011, "divu", IIM16Alu> { + let Defs = [HI0, LO0]; +} +// +// Format: JAL target MIPS16e +// Purpose: Jump and Link +// To execute a procedure call within the current 256 MB-aligned +// region and preserve the current ISA. +// + +def Jal16 : FJAL16_ins<0b0, "jal", IIM16Alu> { + let hasDelaySlot = 0; // not true, but we add the nop for now + let isCall=1; + let Defs = [RA]; +} + +def JalB16 : FJALB16_ins<0b0, "jal", IIM16Alu>, branch16 { + let hasDelaySlot = 0; // not true, but we add the nop for now + let isBranch=1; + let Defs = [RA]; +} + +// +// Format: JR ra MIPS16e +// Purpose: Jump Register Through Register ra +// To execute a branch to the instruction address in the return +// address register. +// + +def JrRa16: FRR16_JALRC_RA_only_ins<0, 0, "jr", IIM16Alu> { + let isBranch = 1; + let isIndirectBranch = 1; + let hasDelaySlot = 1; + let isTerminator=1; + let isBarrier=1; +} + +def JrcRa16: FRR16_JALRC_RA_only_ins<1, 1, "jrc", IIM16Alu> { + let isBranch = 1; + let isIndirectBranch = 1; + let isTerminator=1; + let isBarrier=1; +} + +def JrcRx16: FRR16_JALRC_ins<1, 1, 0, "jrc", IIM16Alu> { + let isBranch = 1; + let isIndirectBranch = 1; + let isTerminator=1; + let isBarrier=1; +} +// +// Format: LB ry, offset(rx) MIPS16e +// Purpose: Load Byte (Extended) +// To load a byte from memory as a signed value. +// +def LbRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10011, "lb", mem16, II_LB>, MayLoad{ + let isCodeGenOnly = 1; +} + +// +// Format: LBU ry, offset(rx) MIPS16e +// Purpose: Load Byte Unsigned (Extended) +// To load a byte from memory as a unsigned value. +// +def LbuRxRyOffMemX16: + FEXT_RRI16_mem_ins<0b10100, "lbu", mem16, II_LBU>, MayLoad { + let isCodeGenOnly = 1; +} + +// +// Format: LH ry, offset(rx) MIPS16e +// Purpose: Load Halfword signed (Extended) +// To load a halfword from memory as a signed value. +// +def LhRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10100, "lh", mem16, II_LH>, MayLoad{ + let isCodeGenOnly = 1; +} + +// +// Format: LHU ry, offset(rx) MIPS16e +// Purpose: Load Halfword unsigned (Extended) +// To load a halfword from memory as an unsigned value. +// +def LhuRxRyOffMemX16: + FEXT_RRI16_mem_ins<0b10100, "lhu", mem16, II_LHU>, MayLoad { + let isCodeGenOnly = 1; +} + +// +// Format: LI rx, immediate MIPS16e +// Purpose: Load Immediate +// To load a constant into a GPR. +// +def LiRxImm16: FRI16_ins<0b01101, "li", IIM16Alu>; + +// +// Format: LI rx, immediate MIPS16e +// Purpose: Load Immediate (Extended) +// To load a constant into a GPR. +// +def LiRxImmX16: FEXT_RI16_ins<0b01101, "li", IIM16Alu>; + +def LiRxImmAlignX16: FEXT_RI16_ins<0b01101, ".align 2\n\tli", IIM16Alu> { + let isCodeGenOnly = 1; +} + +// +// Format: LW ry, offset(rx) MIPS16e +// Purpose: Load Word (Extended) +// To load a word from memory as a signed value. +// +def LwRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10011, "lw", mem16, II_LW>, MayLoad{ + let isCodeGenOnly = 1; +} + +// Format: LW rx, offset(sp) MIPS16e +// Purpose: Load Word (SP-Relative, Extended) +// To load an SP-relative word from memory as a signed value. +// +def LwRxSpImmX16: FEXT_RI16_SP_explicit_ins<0b10010, "lw", II_LW>, MayLoad{ + let Uses = [SP]; +} + +def LwRxPcTcp16: FRI16_TCP_ins<0b10110, "lw", II_LW>, MayLoad; + +def LwRxPcTcpX16: FEXT_RI16_TCP_ins<0b10110, "lw", II_LW>, MayLoad; +// +// Format: MOVE r32, rz MIPS16e +// Purpose: Move +// To move the contents of a GPR to a GPR. +// +def Move32R16: FI8_MOV32R16_ins<"move", IIM16Alu>; + +// +// Format: MOVE ry, r32 MIPS16e +//Purpose: Move +// To move the contents of a GPR to a GPR. +// +def MoveR3216: FI8_MOVR3216_ins<"move", IIM16Alu>; + +// +// Format: MFHI rx MIPS16e +// Purpose: Move From HI Register +// To copy the special purpose HI register to a GPR. +// +def Mfhi16: FRR16_M_ins<0b10000, "mfhi", IIM16Alu> { + let Uses = [HI0]; + let hasSideEffects = 0; +} + +// +// Format: MFLO rx MIPS16e +// Purpose: Move From LO Register +// To copy the special purpose LO register to a GPR. +// +def Mflo16: FRR16_M_ins<0b10010, "mflo", IIM16Alu> { + let Uses = [LO0]; + let hasSideEffects = 0; +} + +// +// Pseudo Instruction for mult +// +def MultRxRy16: FMULT16_ins<"mult", IIM16Alu> { + let isCommutable = 1; + let hasSideEffects = 0; + let Defs = [HI0, LO0]; +} + +def MultuRxRy16: FMULT16_ins<"multu", IIM16Alu> { + let isCommutable = 1; + let hasSideEffects = 0; + let Defs = [HI0, LO0]; +} + +// +// Format: MULT rx, ry MIPS16e +// Purpose: Multiply Word +// To multiply 32-bit signed integers. +// +def MultRxRyRz16: FMULT16_LO_ins<"mult", IIM16Alu> { + let isCommutable = 1; + let hasSideEffects = 0; + let Defs = [HI0, LO0]; +} + +// +// Format: MULTU rx, ry MIPS16e +// Purpose: Multiply Unsigned Word +// To multiply 32-bit unsigned integers. +// +def MultuRxRyRz16: FMULT16_LO_ins<"multu", IIM16Alu> { + let isCommutable = 1; + let hasSideEffects = 0; + let Defs = [HI0, LO0]; +} + +// +// Format: NEG rx, ry MIPS16e +// Purpose: Negate +// To negate an integer value. +// +def NegRxRy16: FUnaryRR16_ins<0b11101, "neg", IIM16Alu>; + +// +// Format: NOT rx, ry MIPS16e +// Purpose: Not +// To complement an integer value +// +def NotRxRy16: FUnaryRR16_ins<0b01111, "not", IIM16Alu>; + +// +// Format: OR rx, ry MIPS16e +// Purpose: Or +// To do a bitwise logical OR. +// +def OrRxRxRy16: FRxRxRy16_ins<0b01101, "or", IIM16Alu>, ArithLogic16Defs<1>; + +// +// Format: RESTORE {ra,}{s0/s1/s0-1,}{framesize} +// (All args are optional) MIPS16e +// Purpose: Restore Registers and Deallocate Stack Frame +// To deallocate a stack frame before exit from a subroutine, +// restoring return address and static registers, and adjusting +// stack +// + +def Restore16: + FI8_SVRS16<0b1, (outs), (ins variable_ops), + "", [], II_RESTORE >, MayLoad { + let isCodeGenOnly = 1; + let Defs = [SP]; + let Uses = [SP]; +} + + +def RestoreX16: + FI8_SVRS16<0b1, (outs), (ins variable_ops), + "", [], II_RESTORE >, MayLoad { + let isCodeGenOnly = 1; + let Defs = [SP]; + let Uses = [SP]; +} + +// +// Format: SAVE {ra,}{s0/s1/s0-1,}{framesize} (All arguments are optional) +// MIPS16e +// Purpose: Save Registers and Set Up Stack Frame +// To set up a stack frame on entry to a subroutine, +// saving return address and static registers, and adjusting stack +// +def Save16: + FI8_SVRS16<0b1, (outs), (ins variable_ops), + "", [], II_SAVE >, MayStore { + let isCodeGenOnly = 1; + let Uses = [SP]; + let Defs = [SP]; +} + +def SaveX16: + FI8_SVRS16<0b1, (outs), (ins variable_ops), + "", [], II_SAVE >, MayStore { + let isCodeGenOnly = 1; + let Uses = [SP]; + let Defs = [SP]; +} +// +// Format: SB ry, offset(rx) MIPS16e +// Purpose: Store Byte (Extended) +// To store a byte to memory. +// +def SbRxRyOffMemX16: + FEXT_RRI16_mem2_ins<0b11000, "sb", mem16, II_SB>, MayStore; + +// +// Format: SEB rx MIPS16e +// Purpose: Sign-Extend Byte +// Sign-extend least significant byte in register rx. +// +def SebRx16 + : FRR_SF16_ins<0b10001, 0b100, "seb", IIM16Alu>; + +// +// Format: SEH rx MIPS16e +// Purpose: Sign-Extend Halfword +// Sign-extend least significant word in register rx. +// +def SehRx16 + : FRR_SF16_ins<0b10001, 0b101, "seh", IIM16Alu>; + +// +// The Sel(T) instructions are pseudos +// T means that they use T8 implicitly. +// +// +// Format: SelBeqZ rd, rs, rt +// Purpose: if rt==0, do nothing +// else rs = rt +// +def SelBeqZ: Sel<"beqz">; + +// +// Format: SelTBteqZCmp rd, rs, rl, rr +// Purpose: b = Cmp rl, rr. +// If b==0 then do nothing. +// if b!=0 then rd = rs +// +def SelTBteqZCmp: SelT<"bteqz", "cmp">; + +// +// Format: SelTBteqZCmpi rd, rs, rl, rr +// Purpose: b = Cmpi rl, imm. +// If b==0 then do nothing. +// if b!=0 then rd = rs +// +def SelTBteqZCmpi: SeliT<"bteqz", "cmpi">; + +// +// Format: SelTBteqZSlt rd, rs, rl, rr +// Purpose: b = Slt rl, rr. +// If b==0 then do nothing. +// if b!=0 then rd = rs +// +def SelTBteqZSlt: SelT<"bteqz", "slt">; + +// +// Format: SelTBteqZSlti rd, rs, rl, rr +// Purpose: b = Slti rl, imm. +// If b==0 then do nothing. +// if b!=0 then rd = rs +// +def SelTBteqZSlti: SeliT<"bteqz", "slti">; + +// +// Format: SelTBteqZSltu rd, rs, rl, rr +// Purpose: b = Sltu rl, rr. +// If b==0 then do nothing. +// if b!=0 then rd = rs +// +def SelTBteqZSltu: SelT<"bteqz", "sltu">; + +// +// Format: SelTBteqZSltiu rd, rs, rl, rr +// Purpose: b = Sltiu rl, imm. +// If b==0 then do nothing. +// if b!=0 then rd = rs +// +def SelTBteqZSltiu: SeliT<"bteqz", "sltiu">; + +// +// Format: SelBnez rd, rs, rt +// Purpose: if rt!=0, do nothing +// else rs = rt +// +def SelBneZ: Sel<"bnez">; + +// +// Format: SelTBtneZCmp rd, rs, rl, rr +// Purpose: b = Cmp rl, rr. +// If b!=0 then do nothing. +// if b0=0 then rd = rs +// +def SelTBtneZCmp: SelT<"btnez", "cmp">; + +// +// Format: SelTBtnezCmpi rd, rs, rl, rr +// Purpose: b = Cmpi rl, imm. +// If b!=0 then do nothing. +// if b==0 then rd = rs +// +def SelTBtneZCmpi: SeliT<"btnez", "cmpi">; + +// +// Format: SelTBtneZSlt rd, rs, rl, rr +// Purpose: b = Slt rl, rr. +// If b!=0 then do nothing. +// if b==0 then rd = rs +// +def SelTBtneZSlt: SelT<"btnez", "slt">; + +// +// Format: SelTBtneZSlti rd, rs, rl, rr +// Purpose: b = Slti rl, imm. +// If b!=0 then do nothing. +// if b==0 then rd = rs +// +def SelTBtneZSlti: SeliT<"btnez", "slti">; + +// +// Format: SelTBtneZSltu rd, rs, rl, rr +// Purpose: b = Sltu rl, rr. +// If b!=0 then do nothing. +// if b==0 then rd = rs +// +def SelTBtneZSltu: SelT<"btnez", "sltu">; + +// +// Format: SelTBtneZSltiu rd, rs, rl, rr +// Purpose: b = Slti rl, imm. +// If b!=0 then do nothing. +// if b==0 then rd = rs +// +def SelTBtneZSltiu: SeliT<"btnez", "sltiu">; +// +// +// Format: SH ry, offset(rx) MIPS16e +// Purpose: Store Halfword (Extended) +// To store a halfword to memory. +// +def ShRxRyOffMemX16: + FEXT_RRI16_mem2_ins<0b11001, "sh", mem16, II_SH>, MayStore; + +// +// Format: SLL rx, ry, sa MIPS16e +// Purpose: Shift Word Left Logical (Extended) +// To execute a left-shift of a word by a fixed number of bits-0 to 31 bits. +// +def SllX16: FEXT_SHIFT16_ins<0b00, "sll", IIM16Alu>; + +// +// Format: SLLV ry, rx MIPS16e +// Purpose: Shift Word Left Logical Variable +// To execute a left-shift of a word by a variable number of bits. +// +def SllvRxRy16 : FRxRxRy16_ins<0b00100, "sllv", IIM16Alu>; + +// Format: SLTI rx, immediate MIPS16e +// Purpose: Set on Less Than Immediate +// To record the result of a less-than comparison with a constant. +// +// +def SltiRxImm16: FRI16R_ins<0b01010, "slti", IIM16Alu> { + let Defs = [T8]; +} + +// +// Format: SLTI rx, immediate MIPS16e +// Purpose: Set on Less Than Immediate (Extended) +// To record the result of a less-than comparison with a constant. +// +// +def SltiRxImmX16: FEXT_RI16R_ins<0b01010, "slti", IIM16Alu> { + let Defs = [T8]; +} + +def SltiCCRxImmX16: FEXT_CCRXI16_ins<"slti">; + +// Format: SLTIU rx, immediate MIPS16e +// Purpose: Set on Less Than Immediate Unsigned +// To record the result of a less-than comparison with a constant. +// +// +def SltiuRxImm16: FRI16R_ins<0b01011, "sltiu", IIM16Alu> { + let Defs = [T8]; +} + +// +// Format: SLTI rx, immediate MIPS16e +// Purpose: Set on Less Than Immediate Unsigned (Extended) +// To record the result of a less-than comparison with a constant. +// +// +def SltiuRxImmX16: FEXT_RI16R_ins<0b01011, "sltiu", IIM16Alu> { + let Defs = [T8]; +} +// +// Format: SLTIU rx, immediate MIPS16e +// Purpose: Set on Less Than Immediate Unsigned (Extended) +// To record the result of a less-than comparison with a constant. +// +def SltiuCCRxImmX16: FEXT_CCRXI16_ins<"sltiu">; + +// +// Format: SLT rx, ry MIPS16e +// Purpose: Set on Less Than +// To record the result of a less-than comparison. +// +def SltRxRy16: FRR16R_ins<0b00010, "slt", IIM16Alu>{ + let Defs = [T8]; +} + +def SltCCRxRy16: FCCRR16_ins<"slt">; + +// Format: SLTU rx, ry MIPS16e +// Purpose: Set on Less Than Unsigned +// To record the result of an unsigned less-than comparison. +// +def SltuRxRy16: FRR16R_ins<0b00011, "sltu", IIM16Alu>{ + let Defs = [T8]; +} + +def SltuRxRyRz16: FRRTR16_ins<"sltu"> { + let isCodeGenOnly=1; + let Defs = [T8]; +} + + +def SltuCCRxRy16: FCCRR16_ins<"sltu">; +// +// Format: SRAV ry, rx MIPS16e +// Purpose: Shift Word Right Arithmetic Variable +// To execute an arithmetic right-shift of a word by a variable +// number of bits. +// +def SravRxRy16: FRxRxRy16_ins<0b00111, "srav", IIM16Alu>; + + +// +// Format: SRA rx, ry, sa MIPS16e +// Purpose: Shift Word Right Arithmetic (Extended) +// To execute an arithmetic right-shift of a word by a fixed +// number of bits-1 to 8 bits. +// +def SraX16: FEXT_SHIFT16_ins<0b11, "sra", IIM16Alu>; + + +// +// Format: SRLV ry, rx MIPS16e +// Purpose: Shift Word Right Logical Variable +// To execute a logical right-shift of a word by a variable +// number of bits. +// +def SrlvRxRy16: FRxRxRy16_ins<0b00110, "srlv", IIM16Alu>; + + +// +// Format: SRL rx, ry, sa MIPS16e +// Purpose: Shift Word Right Logical (Extended) +// To execute a logical right-shift of a word by a fixed +// number of bits-1 to 31 bits. +// +def SrlX16: FEXT_SHIFT16_ins<0b10, "srl", IIM16Alu>; + +// +// Format: SUBU rz, rx, ry MIPS16e +// Purpose: Subtract Unsigned Word +// To subtract 32-bit integers +// +def SubuRxRyRz16: FRRR16_ins<0b11, "subu", IIM16Alu>, ArithLogic16Defs<0>; + +// +// Format: SW ry, offset(rx) MIPS16e +// Purpose: Store Word (Extended) +// To store a word to memory. +// +def SwRxRyOffMemX16: + FEXT_RRI16_mem2_ins<0b11011, "sw", mem16, II_SW>, MayStore; + +// +// Format: SW rx, offset(sp) MIPS16e +// Purpose: Store Word rx (SP-Relative) +// To store an SP-relative word to memory. +// +def SwRxSpImmX16: FEXT_RI16_SP_Store_explicit_ins + <0b11010, "sw", II_SW>, MayStore; + +// +// +// Format: XOR rx, ry MIPS16e +// Purpose: Xor +// To do a bitwise logical XOR. +// +def XorRxRxRy16: FRxRxRy16_ins<0b01110, "xor", IIM16Alu>, ArithLogic16Defs<1>; + +class Mips16Pat<dag pattern, dag result> : Pat<pattern, result> { + let Predicates = [InMips16Mode]; +} + +// Unary Arith/Logic +// +class ArithLogicU_pat<PatFrag OpNode, Instruction I> : + Mips16Pat<(OpNode CPU16Regs:$r), + (I CPU16Regs:$r)>; + +def: ArithLogicU_pat<not, NotRxRy16>; +def: ArithLogicU_pat<ineg, NegRxRy16>; + +class ArithLogic16_pat<SDNode OpNode, Instruction I> : + Mips16Pat<(OpNode CPU16Regs:$l, CPU16Regs:$r), + (I CPU16Regs:$l, CPU16Regs:$r)>; + +def: ArithLogic16_pat<add, AdduRxRyRz16>; +def: ArithLogic16_pat<and, AndRxRxRy16>; +def: ArithLogic16_pat<mul, MultRxRyRz16>; +def: ArithLogic16_pat<or, OrRxRxRy16>; +def: ArithLogic16_pat<sub, SubuRxRyRz16>; +def: ArithLogic16_pat<xor, XorRxRxRy16>; + +// Arithmetic and logical instructions with 2 register operands. + +class ArithLogicI16_pat<SDNode OpNode, PatFrag imm_type, Instruction I> : + Mips16Pat<(OpNode CPU16Regs:$in, imm_type:$imm), + (I CPU16Regs:$in, imm_type:$imm)>; + +def: ArithLogicI16_pat<add, immSExt8, AddiuRxRxImm16>; +def: ArithLogicI16_pat<add, immSExt16, AddiuRxRxImmX16>; +def: ArithLogicI16_pat<shl, immZExt5, SllX16>; +def: ArithLogicI16_pat<srl, immZExt5, SrlX16>; +def: ArithLogicI16_pat<sra, immZExt5, SraX16>; + +class shift_rotate_reg16_pat<SDNode OpNode, Instruction I> : + Mips16Pat<(OpNode CPU16Regs:$r, CPU16Regs:$ra), + (I CPU16Regs:$r, CPU16Regs:$ra)>; + +def: shift_rotate_reg16_pat<shl, SllvRxRy16>; +def: shift_rotate_reg16_pat<sra, SravRxRy16>; +def: shift_rotate_reg16_pat<srl, SrlvRxRy16>; + +class LoadM16_pat<PatFrag OpNode, Instruction I> : + Mips16Pat<(OpNode addr16:$addr), (I addr16:$addr)>; + +def: LoadM16_pat<sextloadi8, LbRxRyOffMemX16>; +def: LoadM16_pat<zextloadi8, LbuRxRyOffMemX16>; +def: LoadM16_pat<sextloadi16, LhRxRyOffMemX16>; +def: LoadM16_pat<zextloadi16, LhuRxRyOffMemX16>; +def: LoadM16_pat<load, LwRxRyOffMemX16>; + +class StoreM16_pat<PatFrag OpNode, Instruction I> : + Mips16Pat<(OpNode CPU16Regs:$r, addr16:$addr), + (I CPU16Regs:$r, addr16:$addr)>; + +def: StoreM16_pat<truncstorei8, SbRxRyOffMemX16>; +def: StoreM16_pat<truncstorei16, ShRxRyOffMemX16>; +def: StoreM16_pat<store, SwRxRyOffMemX16>; + +// Unconditional branch +class UncondBranch16_pat<SDNode OpNode, Instruction I>: + Mips16Pat<(OpNode bb:$imm16), (I bb:$imm16)> { + let Predicates = [InMips16Mode]; + } + +def : Mips16Pat<(MipsJmpLink (i32 tglobaladdr:$dst)), + (Jal16 tglobaladdr:$dst)>; + +def : Mips16Pat<(MipsJmpLink (i32 texternalsym:$dst)), + (Jal16 texternalsym:$dst)>; + +// Indirect branch +def: Mips16Pat<(brind CPU16Regs:$rs), (JrcRx16 CPU16Regs:$rs)> { + // Ensure that the addition of MIPS32r6/MIPS64r6 support does not change + // MIPS16's behaviour. + let AddedComplexity = 1; +} + +// Jump and Link (Call) +let isCall=1, hasDelaySlot=0 in +def JumpLinkReg16: + FRR16_JALRC<0, 0, 0, (outs), (ins CPU16Regs:$rs), + "jalrc \t$rs", [(MipsJmpLink CPU16Regs:$rs)], II_JALRC> { + let Defs = [RA]; +} + +// Mips16 pseudos +let isReturn=1, isTerminator=1, hasDelaySlot=1, isBarrier=1, hasCtrlDep=1, + hasExtraSrcRegAllocReq = 1 in +def RetRA16 : MipsPseudo16<(outs), (ins), "", [(MipsRet)]>; + + +// setcc patterns + +class SetCC_R16<PatFrag cond_op, Instruction I>: + Mips16Pat<(cond_op CPU16Regs:$rx, CPU16Regs:$ry), + (I CPU16Regs:$rx, CPU16Regs:$ry)>; + +class SetCC_I16<PatFrag cond_op, PatLeaf imm_type, Instruction I>: + Mips16Pat<(cond_op CPU16Regs:$rx, imm_type:$imm16), + (I CPU16Regs:$rx, imm_type:$imm16)>; + + +def: Mips16Pat<(i32 addr16:$addr), + (AddiuRxRyOffMemX16 addr16:$addr)>; + + +// Large (>16 bit) immediate loads +def : Mips16Pat<(i32 imm:$imm), (LwConstant32 imm:$imm, -1)>; + +// Carry MipsPatterns +def : Mips16Pat<(subc CPU16Regs:$lhs, CPU16Regs:$rhs), + (SubuRxRyRz16 CPU16Regs:$lhs, CPU16Regs:$rhs)>; +def : Mips16Pat<(addc CPU16Regs:$lhs, CPU16Regs:$rhs), + (AdduRxRyRz16 CPU16Regs:$lhs, CPU16Regs:$rhs)>; +def : Mips16Pat<(addc CPU16Regs:$src, immSExt16:$imm), + (AddiuRxRxImmX16 CPU16Regs:$src, imm:$imm)>; + +// +// Some branch conditional patterns are not generated by llvm at this time. +// Some are for seemingly arbitrary reasons not used: i.e. with signed number +// comparison they are used and for unsigned a different pattern is used. +// I am pushing upstream from the full mips16 port and it seemed that I needed +// these earlier and the mips32 port has these but now I cannot create test +// cases that use these patterns. While I sort this all out I will leave these +// extra patterns commented out and if I can be sure they are really not used, +// I will delete the code. I don't want to check the code in uncommented without +// a valid test case. In some cases, the compiler is generating patterns with +// setcc instead and earlier I had implemented setcc first so may have masked +// the problem. The setcc variants are suboptimal for mips16 so I may wantto +// figure out how to enable the brcond patterns or else possibly new +// combinations of of brcond and setcc. +// +// +// bcond-seteq +// +def: Mips16Pat + <(brcond (i32 (seteq CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), + (BteqzT8CmpX16 CPU16Regs:$rx, CPU16Regs:$ry, bb:$imm16) + >; + + +def: Mips16Pat + <(brcond (i32 (seteq CPU16Regs:$rx, immZExt16:$imm)), bb:$targ16), + (BteqzT8CmpiX16 CPU16Regs:$rx, immSExt16:$imm, bb:$targ16) + >; + +def: Mips16Pat + <(brcond (i32 (seteq CPU16Regs:$rx, 0)), bb:$targ16), + (BeqzRxImm16 CPU16Regs:$rx, bb:$targ16) + >; + +// +// bcond-setgt (do we need to have this pair of setlt, setgt??) +// +def: Mips16Pat + <(brcond (i32 (setgt CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), + (BtnezT8SltX16 CPU16Regs:$ry, CPU16Regs:$rx, bb:$imm16) + >; + +// +// bcond-setge +// +def: Mips16Pat + <(brcond (i32 (setge CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), + (BteqzT8SltX16 CPU16Regs:$rx, CPU16Regs:$ry, bb:$imm16) + >; + +// +// never called because compiler transforms a >= k to a > (k-1) +def: Mips16Pat + <(brcond (i32 (setge CPU16Regs:$rx, immSExt16:$imm)), bb:$imm16), + (BteqzT8SltiX16 CPU16Regs:$rx, immSExt16:$imm, bb:$imm16) + >; + +// +// bcond-setlt +// +def: Mips16Pat + <(brcond (i32 (setlt CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), + (BtnezT8SltX16 CPU16Regs:$rx, CPU16Regs:$ry, bb:$imm16) + >; + +def: Mips16Pat + <(brcond (i32 (setlt CPU16Regs:$rx, immSExt16:$imm)), bb:$imm16), + (BtnezT8SltiX16 CPU16Regs:$rx, immSExt16:$imm, bb:$imm16) + >; + +// +// bcond-setle +// +def: Mips16Pat + <(brcond (i32 (setle CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), + (BteqzT8SltX16 CPU16Regs:$ry, CPU16Regs:$rx, bb:$imm16) + >; + +// +// bcond-setne +// +def: Mips16Pat + <(brcond (i32 (setne CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), + (BtnezT8CmpX16 CPU16Regs:$rx, CPU16Regs:$ry, bb:$imm16) + >; + +def: Mips16Pat + <(brcond (i32 (setne CPU16Regs:$rx, immZExt16:$imm)), bb:$targ16), + (BtnezT8CmpiX16 CPU16Regs:$rx, immSExt16:$imm, bb:$targ16) + >; + +def: Mips16Pat + <(brcond (i32 (setne CPU16Regs:$rx, 0)), bb:$targ16), + (BnezRxImm16 CPU16Regs:$rx, bb:$targ16) + >; + +// +// This needs to be there but I forget which code will generate it +// +def: Mips16Pat + <(brcond CPU16Regs:$rx, bb:$targ16), + (BnezRxImm16 CPU16Regs:$rx, bb:$targ16) + >; + +// + +// +// bcond-setugt +// +//def: Mips16Pat +// <(brcond (i32 (setugt CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), +// (BtnezT8SltuX16 CPU16Regs:$ry, CPU16Regs:$rx, bb:$imm16) +// >; + +// +// bcond-setuge +// +//def: Mips16Pat +// <(brcond (i32 (setuge CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), +// (BteqzT8SltuX16 CPU16Regs:$rx, CPU16Regs:$ry, bb:$imm16) +// >; + + +// +// bcond-setult +// +//def: Mips16Pat +// <(brcond (i32 (setult CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), +// (BtnezT8SltuX16 CPU16Regs:$rx, CPU16Regs:$ry, bb:$imm16) +// >; + +def: UncondBranch16_pat<br, Bimm16>; + +// Small immediates +def: Mips16Pat<(i32 immSExt16:$in), + (AddiuRxRxImmX16 (Move32R16 ZERO), immSExt16:$in)>; + +def: Mips16Pat<(i32 immZExt16:$in), (LiRxImmX16 immZExt16:$in)>; + +// +// MipsDivRem +// +def: Mips16Pat + <(MipsDivRem16 CPU16Regs:$rx, CPU16Regs:$ry), + (DivRxRy16 CPU16Regs:$rx, CPU16Regs:$ry)>; + +// +// MipsDivRemU +// +def: Mips16Pat + <(MipsDivRemU16 CPU16Regs:$rx, CPU16Regs:$ry), + (DivuRxRy16 CPU16Regs:$rx, CPU16Regs:$ry)>; + +// signed a,b +// x = (a>=b)?x:y +// +// if !(a < b) x = y +// +def : Mips16Pat<(select (i32 (setge CPU16Regs:$a, CPU16Regs:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBteqZSlt CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$a, CPU16Regs:$b)>; + +// signed a,b +// x = (a>b)?x:y +// +// if (b < a) x = y +// +def : Mips16Pat<(select (i32 (setgt CPU16Regs:$a, CPU16Regs:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBtneZSlt CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$b, CPU16Regs:$a)>; + +// unsigned a,b +// x = (a>=b)?x:y +// +// if !(a < b) x = y; +// +def : Mips16Pat< + (select (i32 (setuge CPU16Regs:$a, CPU16Regs:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBteqZSltu CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$a, CPU16Regs:$b)>; + +// unsigned a,b +// x = (a>b)?x:y +// +// if (b < a) x = y +// +def : Mips16Pat<(select (i32 (setugt CPU16Regs:$a, CPU16Regs:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBtneZSltu CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$b, CPU16Regs:$a)>; + +// signed +// x = (a >= k)?x:y +// due to an llvm optimization, i don't think that this will ever +// be used. This is transformed into x = (a > k-1)?x:y +// +// + +//def : Mips16Pat< +// (select (i32 (setge CPU16Regs:$lhs, immSExt16:$rhs)), +// CPU16Regs:$T, CPU16Regs:$F), +// (SelTBteqZSlti CPU16Regs:$T, CPU16Regs:$F, +// CPU16Regs:$lhs, immSExt16:$rhs)>; + +//def : Mips16Pat< +// (select (i32 (setuge CPU16Regs:$lhs, immSExt16:$rhs)), +// CPU16Regs:$T, CPU16Regs:$F), +// (SelTBteqZSltiu CPU16Regs:$T, CPU16Regs:$F, +// CPU16Regs:$lhs, immSExt16:$rhs)>; + +// signed +// x = (a < k)?x:y +// +// if !(a < k) x = y; +// +def : Mips16Pat< + (select (i32 (setlt CPU16Regs:$a, immSExt16:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBtneZSlti CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$a, immSExt16:$b)>; + + +// +// +// signed +// x = (a <= b)? x : y +// +// if (b < a) x = y +// +def : Mips16Pat<(select (i32 (setle CPU16Regs:$a, CPU16Regs:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBteqZSlt CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$b, CPU16Regs:$a)>; + +// +// unnsigned +// x = (a <= b)? x : y +// +// if (b < a) x = y +// +def : Mips16Pat<(select (i32 (setule CPU16Regs:$a, CPU16Regs:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBteqZSltu CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$b, CPU16Regs:$a)>; + +// +// signed/unsigned +// x = (a == b)? x : y +// +// if (a != b) x = y +// +def : Mips16Pat<(select (i32 (seteq CPU16Regs:$a, CPU16Regs:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBteqZCmp CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$b, CPU16Regs:$a)>; + +// +// signed/unsigned +// x = (a == 0)? x : y +// +// if (a != 0) x = y +// +def : Mips16Pat<(select (i32 (seteq CPU16Regs:$a, 0)), + CPU16Regs:$x, CPU16Regs:$y), + (SelBeqZ CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$a)>; + + +// +// signed/unsigned +// x = (a == k)? x : y +// +// if (a != k) x = y +// +def : Mips16Pat<(select (i32 (seteq CPU16Regs:$a, immZExt16:$k)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBteqZCmpi CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$a, immZExt16:$k)>; + + +// +// signed/unsigned +// x = (a != b)? x : y +// +// if (a == b) x = y +// +// +def : Mips16Pat<(select (i32 (setne CPU16Regs:$a, CPU16Regs:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBtneZCmp CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$b, CPU16Regs:$a)>; + +// +// signed/unsigned +// x = (a != 0)? x : y +// +// if (a == 0) x = y +// +def : Mips16Pat<(select (i32 (setne CPU16Regs:$a, 0)), + CPU16Regs:$x, CPU16Regs:$y), + (SelBneZ CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$a)>; + +// signed/unsigned +// x = (a)? x : y +// +// if (!a) x = y +// +def : Mips16Pat<(select CPU16Regs:$a, + CPU16Regs:$x, CPU16Regs:$y), + (SelBneZ CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$a)>; + + +// +// signed/unsigned +// x = (a != k)? x : y +// +// if (a == k) x = y +// +def : Mips16Pat<(select (i32 (setne CPU16Regs:$a, immZExt16:$k)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBtneZCmpi CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$a, immZExt16:$k)>; + +// +// When writing C code to test setxx these patterns, +// some will be transformed into +// other things. So we test using C code but using -O3 and -O0 +// +// seteq +// +def : Mips16Pat + <(seteq CPU16Regs:$lhs,CPU16Regs:$rhs), + (SltiuCCRxImmX16 (XorRxRxRy16 CPU16Regs:$lhs, CPU16Regs:$rhs), 1)>; + +def : Mips16Pat + <(seteq CPU16Regs:$lhs, 0), + (SltiuCCRxImmX16 CPU16Regs:$lhs, 1)>; + + +// +// setge +// + +def: Mips16Pat + <(setge CPU16Regs:$lhs, CPU16Regs:$rhs), + (XorRxRxRy16 (SltCCRxRy16 CPU16Regs:$lhs, CPU16Regs:$rhs), + (LiRxImmX16 1))>; + +// +// For constants, llvm transforms this to: +// x > (k - 1) and then reverses the operands to use setlt. So this pattern +// is not used now by the compiler. (Presumably checking that k-1 does not +// overflow). The compiler never uses this at the current time, due to +// other optimizations. +// +//def: Mips16Pat +// <(setge CPU16Regs:$lhs, immSExt16:$rhs), +// (XorRxRxRy16 (SltiCCRxImmX16 CPU16Regs:$lhs, immSExt16:$rhs), +// (LiRxImmX16 1))>; + +// This catches the x >= -32768 case by transforming it to x > -32769 +// +def: Mips16Pat + <(setgt CPU16Regs:$lhs, -32769), + (XorRxRxRy16 (SltiCCRxImmX16 CPU16Regs:$lhs, -32768), + (LiRxImmX16 1))>; + +// +// setgt +// +// + +def: Mips16Pat + <(setgt CPU16Regs:$lhs, CPU16Regs:$rhs), + (SltCCRxRy16 CPU16Regs:$rhs, CPU16Regs:$lhs)>; + +// +// setle +// +def: Mips16Pat + <(setle CPU16Regs:$lhs, CPU16Regs:$rhs), + (XorRxRxRy16 (SltCCRxRy16 CPU16Regs:$rhs, CPU16Regs:$lhs), (LiRxImm16 1))>; + +// +// setlt +// +def: SetCC_R16<setlt, SltCCRxRy16>; + +def: SetCC_I16<setlt, immSExt16, SltiCCRxImmX16>; + +// +// setne +// +def : Mips16Pat + <(setne CPU16Regs:$lhs,CPU16Regs:$rhs), + (SltuCCRxRy16 (LiRxImmX16 0), + (XorRxRxRy16 CPU16Regs:$lhs, CPU16Regs:$rhs))>; + + +// +// setuge +// +def: Mips16Pat + <(setuge CPU16Regs:$lhs, CPU16Regs:$rhs), + (XorRxRxRy16 (SltuCCRxRy16 CPU16Regs:$lhs, CPU16Regs:$rhs), + (LiRxImmX16 1))>; + +// this pattern will never be used because the compiler will transform +// x >= k to x > (k - 1) and then use SLT +// +//def: Mips16Pat +// <(setuge CPU16Regs:$lhs, immZExt16:$rhs), +// (XorRxRxRy16 (SltiuCCRxImmX16 CPU16Regs:$lhs, immZExt16:$rhs), +// (LiRxImmX16 1))>; + +// +// setugt +// +def: Mips16Pat + <(setugt CPU16Regs:$lhs, CPU16Regs:$rhs), + (SltuCCRxRy16 CPU16Regs:$rhs, CPU16Regs:$lhs)>; + +// +// setule +// +def: Mips16Pat + <(setule CPU16Regs:$lhs, CPU16Regs:$rhs), + (XorRxRxRy16 (SltuCCRxRy16 CPU16Regs:$rhs, CPU16Regs:$lhs), (LiRxImmX16 1))>; + +// +// setult +// +def: SetCC_R16<setult, SltuCCRxRy16>; + +def: SetCC_I16<setult, immSExt16, SltiuCCRxImmX16>; + +def: Mips16Pat<(add CPU16Regs:$hi, (MipsLo tglobaladdr:$lo)), + (AddiuRxRxImmX16 CPU16Regs:$hi, tglobaladdr:$lo)>; + +// hi/lo relocs +def : Mips16Pat<(MipsHi tblockaddress:$in), + (SllX16 (LiRxImmX16 tblockaddress:$in), 16)>; +def : Mips16Pat<(MipsHi tglobaladdr:$in), + (SllX16 (LiRxImmX16 tglobaladdr:$in), 16)>; +def : Mips16Pat<(MipsHi tjumptable:$in), + (SllX16 (LiRxImmX16 tjumptable:$in), 16)>; +def : Mips16Pat<(MipsHi tglobaltlsaddr:$in), + (SllX16 (LiRxImmX16 tglobaltlsaddr:$in), 16)>; + +def : Mips16Pat<(MipsLo tblockaddress:$in), (LiRxImmX16 tblockaddress:$in)>; + +// wrapper_pic +class Wrapper16Pat<SDNode node, Instruction ADDiuOp, RegisterClass RC>: + Mips16Pat<(MipsWrapper RC:$gp, node:$in), + (ADDiuOp RC:$gp, node:$in)>; + + +def : Wrapper16Pat<tglobaladdr, AddiuRxRxImmX16, CPU16Regs>; +def : Wrapper16Pat<tglobaltlsaddr, AddiuRxRxImmX16, CPU16Regs>; + +def : Mips16Pat<(i32 (extloadi8 addr16:$src)), + (LbuRxRyOffMemX16 addr16:$src)>; +def : Mips16Pat<(i32 (extloadi16 addr16:$src)), + (LhuRxRyOffMemX16 addr16:$src)>; + +def: Mips16Pat<(trap), (Break16)>; + +def : Mips16Pat<(sext_inreg CPU16Regs:$val, i8), + (SebRx16 CPU16Regs:$val)>; + +def : Mips16Pat<(sext_inreg CPU16Regs:$val, i16), + (SehRx16 CPU16Regs:$val)>; + +def GotPrologue16: + MipsPseudo16< + (outs CPU16Regs:$rh, CPU16Regs:$rl), + (ins simm16:$immHi, simm16:$immLo), + "li\t$rh, $immHi\n\taddiu\t$rl, $$pc, $immLo\n ",[]> ; + +// An operand for the CONSTPOOL_ENTRY pseudo-instruction. +def cpinst_operand : Operand<i32> { + // let PrintMethod = "printCPInstOperand"; +} + +// CONSTPOOL_ENTRY - This instruction represents a floating constant pool in +// the function. The first operand is the ID# for this instruction, the second +// is the index into the MachineConstantPool that this is, the third is the +// size in bytes of this constant pool entry. +// +let hasSideEffects = 0, isNotDuplicable = 1 in +def CONSTPOOL_ENTRY : +MipsPseudo16<(outs), (ins cpinst_operand:$instid, cpinst_operand:$cpidx, + i32imm:$size), "foo", []>; + diff --git a/contrib/llvm/lib/Target/Mips/Mips16RegisterInfo.cpp b/contrib/llvm/lib/Target/Mips/Mips16RegisterInfo.cpp new file mode 100644 index 0000000..ebd51d7 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16RegisterInfo.cpp @@ -0,0 +1,151 @@ +//===-- Mips16RegisterInfo.cpp - MIPS16 Register Information --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the MIPS16 implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#include "Mips16RegisterInfo.h" +#include "Mips.h" +#include "Mips16InstrInfo.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsInstrInfo.h" +#include "MipsMachineFunction.h" +#include "MipsSubtarget.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/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" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" + +using namespace llvm; + +#define DEBUG_TYPE "mips16-registerinfo" + +Mips16RegisterInfo::Mips16RegisterInfo() : MipsRegisterInfo() {} + +bool Mips16RegisterInfo::requiresRegisterScavenging + (const MachineFunction &MF) const { + return false; +} +bool Mips16RegisterInfo::requiresFrameIndexScavenging + (const MachineFunction &MF) const { + return false; +} + +bool Mips16RegisterInfo::useFPForScavengingIndex + (const MachineFunction &MF) const { + return false; +} + +bool Mips16RegisterInfo::saveScavengerRegister + (MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + MachineBasicBlock::iterator &UseMI, + const TargetRegisterClass *RC, + unsigned Reg) const { + DebugLoc DL; + const TargetInstrInfo &TII = *MBB.getParent()->getSubtarget().getInstrInfo(); + TII.copyPhysReg(MBB, I, DL, Mips::T0, Reg, true); + TII.copyPhysReg(MBB, UseMI, DL, Reg, Mips::T0, true); + return true; +} + +const TargetRegisterClass * +Mips16RegisterInfo::intRegClass(unsigned Size) const { + assert(Size == 4); + return &Mips::CPU16RegsRegClass; +} + +void Mips16RegisterInfo::eliminateFI(MachineBasicBlock::iterator II, + unsigned OpNo, int FrameIndex, + uint64_t StackSize, + int64_t SPOffset) const { + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + + const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); + int MinCSFI = 0; + int MaxCSFI = -1; + + if (CSI.size()) { + MinCSFI = CSI[0].getFrameIdx(); + MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); + } + + // The following stack frame objects are always + // referenced relative to $sp: + // 1. Outgoing arguments. + // 2. Pointer to dynamically allocated stack space. + // 3. Locations for callee-saved registers. + // Everything else is referenced relative to whatever register + // getFrameRegister() returns. + unsigned FrameReg; + + if (FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI) + FrameReg = Mips::SP; + else { + const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering(); + if (TFI->hasFP(MF)) { + FrameReg = Mips::S0; + } + else { + if ((MI.getNumOperands()> OpNo+2) && MI.getOperand(OpNo+2).isReg()) + FrameReg = MI.getOperand(OpNo+2).getReg(); + else + FrameReg = Mips::SP; + } + } + // Calculate final offset. + // - There is no need to change the offset if the frame object + // is one of the + // following: an outgoing argument, pointer to a dynamically allocated + // stack space or a $gp restore location, + // - If the frame object is any of the following, + // its offset must be adjusted + // by adding the size of the stack: + // incoming argument, callee-saved register location or local variable. + int64_t Offset; + bool IsKill = false; + Offset = SPOffset + (int64_t)StackSize; + Offset += MI.getOperand(OpNo + 1).getImm(); + + + DEBUG(errs() << "Offset : " << Offset << "\n" << "<--------->\n"); + + if (!MI.isDebugValue() && + !Mips16InstrInfo::validImmediate(MI.getOpcode(), FrameReg, Offset)) { + MachineBasicBlock &MBB = *MI.getParent(); + DebugLoc DL = II->getDebugLoc(); + unsigned NewImm; + const Mips16InstrInfo &TII = + *static_cast<const Mips16InstrInfo *>(MF.getSubtarget().getInstrInfo()); + FrameReg = TII.loadImmediate(FrameReg, Offset, MBB, II, DL, NewImm); + Offset = SignExtend64<16>(NewImm); + IsKill = true; + } + MI.getOperand(OpNo).ChangeToRegister(FrameReg, false, false, IsKill); + MI.getOperand(OpNo + 1).ChangeToImmediate(Offset); + + +} diff --git a/contrib/llvm/lib/Target/Mips/Mips16RegisterInfo.h b/contrib/llvm/lib/Target/Mips/Mips16RegisterInfo.h new file mode 100644 index 0000000..d67a79b --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16RegisterInfo.h @@ -0,0 +1,48 @@ +//===-- Mips16RegisterInfo.h - Mips16 Register Information ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips16 implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPS16REGISTERINFO_H +#define LLVM_LIB_TARGET_MIPS_MIPS16REGISTERINFO_H + +#include "MipsRegisterInfo.h" + +namespace llvm { +class Mips16InstrInfo; + +class Mips16RegisterInfo : public MipsRegisterInfo { +public: + Mips16RegisterInfo(); + + bool requiresRegisterScavenging(const MachineFunction &MF) const override; + + bool requiresFrameIndexScavenging(const MachineFunction &MF) const override; + + bool useFPForScavengingIndex(const MachineFunction &MF) const override; + + bool saveScavengerRegister(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + MachineBasicBlock::iterator &UseMI, + const TargetRegisterClass *RC, + unsigned Reg) const override; + + const TargetRegisterClass *intRegClass(unsigned Size) const override; + +private: + void eliminateFI(MachineBasicBlock::iterator II, unsigned OpNo, + int FrameIndex, uint64_t StackSize, + int64_t SPOffset) const override; +}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Mips/Mips32r6InstrFormats.td b/contrib/llvm/lib/Target/Mips/Mips32r6InstrFormats.td new file mode 100644 index 0000000..13216be --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips32r6InstrFormats.td @@ -0,0 +1,562 @@ +//=- Mips32r6InstrFormats.td - Mips32r6 Instruction Formats -*- tablegen -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes Mips32r6 instruction formats. +// +//===----------------------------------------------------------------------===// + +class R6MMR6Rel; + +def MipsR62MicroMipsR6 : InstrMapping { + let FilterClass = "R6MMR6Rel"; + // Instructions with the same BaseOpcode and isNVStore values form a row. + let RowFields = ["BaseOpcode"]; + // Instructions with the same predicate sense form a column. + let ColFields = ["Arch"]; + // The key column is the unpredicated instructions. + let KeyCol = ["mipsr6"]; + // Value columns are PredSense=true and PredSense=false + let ValueCols = [["mipsr6"], ["micromipsr6"]]; +} + +class MipsR6Arch<string opstr> { + string Arch = "mipsr6"; + string BaseOpcode = opstr; +} + +class MipsR6Inst : MipsInst<(outs), (ins), "", [], NoItinerary, FrmOther>, + PredicateControl { + let DecoderNamespace = "Mips32r6_64r6"; + let EncodingPredicates = [HasStdEnc]; +} + +//===----------------------------------------------------------------------===// +// +// Field Values +// +//===----------------------------------------------------------------------===// + +class OPGROUP<bits<6> Val> { + bits<6> Value = Val; +} +def OPGROUP_COP1 : OPGROUP<0b010001>; +def OPGROUP_COP2 : OPGROUP<0b010010>; +def OPGROUP_ADDI : OPGROUP<0b001000>; +def OPGROUP_AUI : OPGROUP<0b001111>; +def OPGROUP_BLEZ : OPGROUP<0b000110>; +def OPGROUP_BGTZ : OPGROUP<0b000111>; +def OPGROUP_BLEZL : OPGROUP<0b010110>; +def OPGROUP_BGTZL : OPGROUP<0b010111>; +def OPGROUP_DADDI : OPGROUP<0b011000>; +def OPGROUP_DAUI : OPGROUP<0b011101>; +def OPGROUP_PCREL : OPGROUP<0b111011>; +def OPGROUP_REGIMM : OPGROUP<0b000001>; +def OPGROUP_SPECIAL : OPGROUP<0b000000>; +// The spec occasionally names this value LL, LLD, SC, or SCD. +def OPGROUP_SPECIAL3 : OPGROUP<0b011111>; +// The spec names this constant LWC2, LDC2, SWC2, and SDC2 in different places. +def OPGROUP_COP2LDST : OPGROUP<0b010010>; + +class OPCODE2<bits<2> Val> { + bits<2> Value = Val; +} +def OPCODE2_ADDIUPC : OPCODE2<0b00>; +def OPCODE2_LWPC : OPCODE2<0b01>; +def OPCODE2_LWUPC : OPCODE2<0b10>; + +class OPCODE3<bits<3> Val> { + bits<3> Value = Val; +} +def OPCODE3_LDPC : OPCODE3<0b110>; + +class OPCODE5<bits<5> Val> { + bits<5> Value = Val; +} +def OPCODE5_ALUIPC : OPCODE5<0b11111>; +def OPCODE5_AUIPC : OPCODE5<0b11110>; +def OPCODE5_DAHI : OPCODE5<0b00110>; +def OPCODE5_DATI : OPCODE5<0b11110>; +def OPCODE5_BC1EQZ : OPCODE5<0b01001>; +def OPCODE5_BC1NEZ : OPCODE5<0b01101>; +def OPCODE5_BC2EQZ : OPCODE5<0b01001>; +def OPCODE5_BC2NEZ : OPCODE5<0b01101>; +def OPCODE5_BGEZAL : OPCODE5<0b10001>; +// The next four constants are unnamed in the spec. These names are taken from +// the OPGROUP names they are used with. +def OPCODE5_LDC2 : OPCODE5<0b01110>; +def OPCODE5_LWC2 : OPCODE5<0b01010>; +def OPCODE5_SDC2 : OPCODE5<0b01111>; +def OPCODE5_SWC2 : OPCODE5<0b01011>; + +class OPCODE6<bits<6> Val> { + bits<6> Value = Val; +} +def OPCODE6_ALIGN : OPCODE6<0b100000>; +def OPCODE6_DALIGN : OPCODE6<0b100100>; +def OPCODE6_BITSWAP : OPCODE6<0b100000>; +def OPCODE6_DBITSWAP : OPCODE6<0b100100>; +def OPCODE6_JALR : OPCODE6<0b001001>; +def OPCODE6_CACHE : OPCODE6<0b100101>; +def OPCODE6_PREF : OPCODE6<0b110101>; +// The next four constants are unnamed in the spec. These names are taken from +// the OPGROUP names they are used with. +def OPCODE6_LL : OPCODE6<0b110110>; +def OPCODE6_LLD : OPCODE6<0b110111>; +def OPCODE6_SC : OPCODE6<0b100110>; +def OPCODE6_SCD : OPCODE6<0b100111>; +def OPCODE6_CLO : OPCODE6<0b010001>; +def OPCODE6_CLZ : OPCODE6<0b010000>; +def OPCODE6_DCLO : OPCODE6<0b010011>; +def OPCODE6_DCLZ : OPCODE6<0b010010>; +def OPCODE6_LSA : OPCODE6<0b000101>; +def OPCODE6_DLSA : OPCODE6<0b010101>; +def OPCODE6_SDBBP : OPCODE6<0b001110>; + +class FIELD_FMT<bits<5> Val> { + bits<5> Value = Val; +} +def FIELD_FMT_S : FIELD_FMT<0b10000>; +def FIELD_FMT_D : FIELD_FMT<0b10001>; + +class FIELD_CMP_COND<bits<5> Val> { + bits<5> Value = Val; +} +// Note: The CMP_COND_FMT names differ from the C_COND_FMT names. +def FIELD_CMP_COND_AF : FIELD_CMP_COND<0b00000>; +def FIELD_CMP_COND_UN : FIELD_CMP_COND<0b00001>; +def FIELD_CMP_COND_EQ : FIELD_CMP_COND<0b00010>; +def FIELD_CMP_COND_UEQ : FIELD_CMP_COND<0b00011>; +def FIELD_CMP_COND_LT : FIELD_CMP_COND<0b00100>; +def FIELD_CMP_COND_ULT : FIELD_CMP_COND<0b00101>; +def FIELD_CMP_COND_LE : FIELD_CMP_COND<0b00110>; +def FIELD_CMP_COND_ULE : FIELD_CMP_COND<0b00111>; +def FIELD_CMP_COND_SAF : FIELD_CMP_COND<0b01000>; +def FIELD_CMP_COND_SUN : FIELD_CMP_COND<0b01001>; +def FIELD_CMP_COND_SEQ : FIELD_CMP_COND<0b01010>; +def FIELD_CMP_COND_SUEQ : FIELD_CMP_COND<0b01011>; +def FIELD_CMP_COND_SLT : FIELD_CMP_COND<0b01100>; +def FIELD_CMP_COND_SULT : FIELD_CMP_COND<0b01101>; +def FIELD_CMP_COND_SLE : FIELD_CMP_COND<0b01110>; +def FIELD_CMP_COND_SULE : FIELD_CMP_COND<0b01111>; + +class FIELD_CMP_FORMAT<bits<5> Val> { + bits<5> Value = Val; +} +def FIELD_CMP_FORMAT_S : FIELD_CMP_FORMAT<0b10100>; +def FIELD_CMP_FORMAT_D : FIELD_CMP_FORMAT<0b10101>; + +//===----------------------------------------------------------------------===// +// +// Disambiguators +// +//===----------------------------------------------------------------------===// +// +// Some encodings are ambiguous except by comparing field values. + +class DecodeDisambiguates<string Name> { + string DecoderMethod = !strconcat("Decode", Name); +} + +class DecodeDisambiguatedBy<string Name> : DecodeDisambiguates<Name> { + string DecoderNamespace = "Mips32r6_64r6_Ambiguous"; +} + +//===----------------------------------------------------------------------===// +// +// Encoding Formats +// +//===----------------------------------------------------------------------===// + +class AUI_FM : MipsR6Inst { + bits<5> rs; + bits<5> rt; + bits<16> imm; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_AUI.Value; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-0} = imm; +} + +class DAUI_FM : AUI_FM { + let Inst{31-26} = OPGROUP_DAUI.Value; +} + +class BAL_FM : MipsR6Inst { + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_REGIMM.Value; + let Inst{25-21} = 0b00000; + let Inst{20-16} = OPCODE5_BGEZAL.Value; + let Inst{15-0} = offset; +} + +class COP1_2R_FM<bits<6> funct, FIELD_FMT Format> : MipsR6Inst { + bits<5> fs; + bits<5> fd; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_COP1.Value; + let Inst{25-21} = Format.Value; + let Inst{20-16} = 0b00000; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5-0} = funct; +} + +class COP1_3R_FM<bits<6> funct, FIELD_FMT Format> : MipsR6Inst { + bits<5> ft; + bits<5> fs; + bits<5> fd; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_COP1.Value; + let Inst{25-21} = Format.Value; + let Inst{20-16} = ft; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5-0} = funct; +} + +class COP1_BCCZ_FM<OPCODE5 Operation> : MipsR6Inst { + bits<5> ft; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_COP1.Value; + let Inst{25-21} = Operation.Value; + let Inst{20-16} = ft; + let Inst{15-0} = offset; +} + +class COP2_BCCZ_FM<OPCODE5 Operation> : MipsR6Inst { + bits<5> ct; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_COP2.Value; + let Inst{25-21} = Operation.Value; + let Inst{20-16} = ct; + let Inst{15-0} = offset; +} + +class PCREL16_FM<OPCODE5 Operation> : MipsR6Inst { + bits<5> rs; + bits<16> imm; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_PCREL.Value; + let Inst{25-21} = rs; + let Inst{20-16} = Operation.Value; + let Inst{15-0} = imm; +} + +class PCREL19_FM<OPCODE2 Operation> : MipsR6Inst { + bits<5> rs; + bits<19> imm; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_PCREL.Value; + let Inst{25-21} = rs; + let Inst{20-19} = Operation.Value; + let Inst{18-0} = imm; +} + +class PCREL18_FM<OPCODE3 Operation> : MipsR6Inst { + bits<5> rs; + bits<18> imm; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_PCREL.Value; + let Inst{25-21} = rs; + let Inst{20-18} = Operation.Value; + let Inst{17-0} = imm; +} + +class SPECIAL3_2R_FM<OPCODE6 Operation> : MipsR6Inst { + bits<5> rd; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL3.Value; + let Inst{25-21} = 0b00000; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = 0b00000; + let Inst{5-0} = Operation.Value; +} + +class SPECIAL3_MEM_FM<OPCODE6 Operation> : MipsR6Inst { + bits<21> addr; + bits<5> hint; + bits<5> base = addr{20-16}; + bits<9> offset = addr{8-0}; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL3.Value; + let Inst{25-21} = base; + let Inst{20-16} = hint; + let Inst{15-7} = offset; + let Inst{6} = 0; + let Inst{5-0} = Operation.Value; +} + +class SPECIAL_2R_FM<OPCODE6 Operation> : MipsR6Inst { + bits<5> rd; + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL.Value; + let Inst{25-21} = rs; + let Inst{20-16} = 0b00000; + let Inst{15-11} = rd; + let Inst{10-6} = 0b00001; + let Inst{5-0} = Operation.Value; +} + +class SPECIAL_3R_FM<bits<5> mulop, bits<6> funct> : MipsR6Inst { + bits<5> rd; + bits<5> rs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL.Value; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = mulop; + let Inst{5-0} = funct; +} + +class SPECIAL_SDBBP_FM : MipsR6Inst { + bits<20> code_; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL.Value; + let Inst{25-6} = code_; + let Inst{5-0} = OPCODE6_SDBBP.Value; +} + +// This class is ambiguous with other branches: +// BEQC/BNEC require that rs > rt +class CMP_BRANCH_2R_OFF16_FM<OPGROUP funct> : MipsR6Inst { + bits<5> rs; + bits<5> rt; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = funct.Value; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-0} = offset; +} + +// This class is ambiguous with other branches: +// BLEZC/BGEZC/BEQZALC/BNEZALC/BGTZALC require that rs == 0 && rt != 0 +// The '1R_RT' in the name means 1 register in the rt field. +class CMP_BRANCH_1R_RT_OFF16_FM<OPGROUP funct> : MipsR6Inst { + bits<5> rt; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = funct.Value; + let Inst{25-21} = 0b00000; + let Inst{20-16} = rt; + let Inst{15-0} = offset; +} + +// This class is ambiguous with other branches: +// BLTZC/BGTZC/BLTZALC/BGEZALC require that rs == rt && rt != 0 +// The '1R_BOTH' in the name means 1 register in both the rs and rt fields. +class CMP_BRANCH_1R_BOTH_OFF16_FM<OPGROUP funct> : MipsR6Inst { + bits<5> rt; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = funct.Value; + let Inst{25-21} = rt; + let Inst{20-16} = rt; + let Inst{15-0} = offset; +} + +class CMP_BRANCH_OFF21_FM<bits<6> funct> : MipsR6Inst { + bits<5> rs; // rs != 0 + bits<21> offset; + + bits<32> Inst; + + let Inst{31-26} = funct; + let Inst{25-21} = rs; + let Inst{20-0} = offset; +} + +class JMP_IDX_COMPACT_FM<bits<6> funct> : MipsR6Inst { + bits<5> rt; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = funct; + let Inst{25-21} = 0b00000; + let Inst{20-16} = rt; + let Inst{15-0} = offset; +} + +class BRANCH_OFF26_FM<bits<6> funct> : MipsR6Inst { + bits<32> Inst; + bits<26> offset; + + let Inst{31-26} = funct; + let Inst{25-0} = offset; +} + +class SPECIAL3_ALIGN_FM<OPCODE6 Operation> : MipsR6Inst { + bits<5> rd; + bits<5> rs; + bits<5> rt; + bits<2> bp; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL3.Value; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-8} = 0b010; + let Inst{7-6} = bp; + let Inst{5-0} = Operation.Value; +} + +class SPECIAL3_DALIGN_FM<OPCODE6 Operation> : MipsR6Inst { + bits<5> rd; + bits<5> rs; + bits<5> rt; + bits<3> bp; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL3.Value; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-9} = 0b01; + let Inst{8-6} = bp; + let Inst{5-0} = Operation.Value; +} + +class SPECIAL3_LL_SC_FM<OPCODE6 Operation> : MipsR6Inst { + bits<5> rt; + bits<21> addr; + bits<5> base = addr{20-16}; + bits<9> offset = addr{8-0}; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL3.Value; + let Inst{25-21} = base; + let Inst{20-16} = rt; + let Inst{15-7} = offset; + let Inst{5-0} = Operation.Value; + + string DecoderMethod = "DecodeSpecial3LlSc"; +} + +class SPECIAL_LSA_FM<OPCODE6 Operation> : MipsR6Inst { + bits<5> rd; + bits<5> rs; + bits<5> rt; + bits<2> imm2; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL.Value; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-8} = 0b000; + let Inst{7-6} = imm2; + let Inst{5-0} = Operation.Value; +} + +class REGIMM_FM<OPCODE5 Operation> : MipsR6Inst { + bits<5> rs; + bits<16> imm; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_REGIMM.Value; + let Inst{25-21} = rs; + let Inst{20-16} = Operation.Value; + let Inst{15-0} = imm; +} + +class COP1_CMP_CONDN_FM<FIELD_CMP_FORMAT Format, + FIELD_CMP_COND Cond> : MipsR6Inst { + bits<5> fd; + bits<5> fs; + bits<5> ft; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_COP1.Value; + let Inst{25-21} = Format.Value; + let Inst{20-16} = ft; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5} = 0; + let Inst{4-0} = Cond.Value; +} + +class JR_HB_R6_FM<OPCODE6 Operation> : MipsR6Inst { + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL.Value; + let Inst{25-21} = rs; + let Inst{20-16} = 0; + let Inst{15-11} = 0; + let Inst{10} = 1; + let Inst{9-6} = 0; + let Inst{5-0} = Operation.Value; +} + +class COP2LDST_FM<OPCODE5 Operation> : MipsR6Inst { + bits<5> rt; + bits<21> addr; + bits<5> base = addr{20-16}; + bits<11> offset = addr{10-0}; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_COP2LDST.Value; + let Inst{25-21} = Operation.Value; + let Inst{20-16} = rt; + let Inst{15-11} = base; + let Inst{10-0} = offset; +} diff --git a/contrib/llvm/lib/Target/Mips/Mips32r6InstrInfo.td b/contrib/llvm/lib/Target/Mips/Mips32r6InstrInfo.td new file mode 100644 index 0000000..82d2c8e --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips32r6InstrInfo.td @@ -0,0 +1,847 @@ +//=- Mips32r6InstrInfo.td - Mips32r6 Instruction Information -*- tablegen -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes Mips32r6 instructions. +// +//===----------------------------------------------------------------------===// + +include "Mips32r6InstrFormats.td" + +// Notes about removals/changes from MIPS32r6: +// Reencoded: jr -> jalr +// Reencoded: jr.hb -> jalr.hb + +def brtarget21 : Operand<OtherVT> { + let EncoderMethod = "getBranchTarget21OpValue"; + let OperandType = "OPERAND_PCREL"; + let DecoderMethod = "DecodeBranchTarget21"; + let ParserMatchClass = MipsJumpTargetAsmOperand; +} + +def brtarget26 : Operand<OtherVT> { + let EncoderMethod = "getBranchTarget26OpValue"; + let OperandType = "OPERAND_PCREL"; + let DecoderMethod = "DecodeBranchTarget26"; + let ParserMatchClass = MipsJumpTargetAsmOperand; +} + +def jmpoffset16 : Operand<OtherVT> { + let EncoderMethod = "getJumpOffset16OpValue"; + let ParserMatchClass = MipsJumpTargetAsmOperand; +} + +def calloffset16 : Operand<iPTR> { + let EncoderMethod = "getJumpOffset16OpValue"; + let ParserMatchClass = MipsJumpTargetAsmOperand; +} + +//===----------------------------------------------------------------------===// +// +// Instruction Encodings +// +//===----------------------------------------------------------------------===// + +class ADDIUPC_ENC : PCREL19_FM<OPCODE2_ADDIUPC>; +class ALIGN_ENC : SPECIAL3_ALIGN_FM<OPCODE6_ALIGN>; +class ALUIPC_ENC : PCREL16_FM<OPCODE5_ALUIPC>; +class AUI_ENC : AUI_FM; +class AUIPC_ENC : PCREL16_FM<OPCODE5_AUIPC>; + +class BAL_ENC : BAL_FM; +class BALC_ENC : BRANCH_OFF26_FM<0b111010>; +class BC_ENC : BRANCH_OFF26_FM<0b110010>; +class BEQC_ENC : CMP_BRANCH_2R_OFF16_FM<OPGROUP_ADDI>, + DecodeDisambiguates<"AddiGroupBranch">; +class BEQZALC_ENC : CMP_BRANCH_1R_RT_OFF16_FM<OPGROUP_ADDI>, + DecodeDisambiguatedBy<"DaddiGroupBranch">; +class BNEC_ENC : CMP_BRANCH_2R_OFF16_FM<OPGROUP_DADDI>, + DecodeDisambiguates<"DaddiGroupBranch">; +class BNEZALC_ENC : CMP_BRANCH_1R_RT_OFF16_FM<OPGROUP_DADDI>, + DecodeDisambiguatedBy<"DaddiGroupBranch">; + +class BLTZC_ENC : CMP_BRANCH_1R_BOTH_OFF16_FM<OPGROUP_BGTZL>, + DecodeDisambiguates<"BgtzlGroupBranch">; +class BGEC_ENC : CMP_BRANCH_2R_OFF16_FM<OPGROUP_BLEZL>, + DecodeDisambiguatedBy<"BlezlGroupBranch">; +class BGEUC_ENC : CMP_BRANCH_2R_OFF16_FM<OPGROUP_BLEZ>, + DecodeDisambiguatedBy<"BlezGroupBranch">; +class BGEZC_ENC : CMP_BRANCH_1R_BOTH_OFF16_FM<OPGROUP_BLEZL>, + DecodeDisambiguates<"BlezlGroupBranch">; +class BGTZALC_ENC : CMP_BRANCH_1R_RT_OFF16_FM<OPGROUP_BGTZ>, + DecodeDisambiguatedBy<"BgtzGroupBranch">; + +class BLTC_ENC : CMP_BRANCH_2R_OFF16_FM<OPGROUP_BGTZL>, + DecodeDisambiguatedBy<"BgtzlGroupBranch">; +class BLTUC_ENC : CMP_BRANCH_2R_OFF16_FM<OPGROUP_BGTZ>, + DecodeDisambiguatedBy<"BgtzGroupBranch">; + +class BLEZC_ENC : CMP_BRANCH_1R_RT_OFF16_FM<OPGROUP_BLEZL>, + DecodeDisambiguatedBy<"BlezlGroupBranch">; +class BLTZALC_ENC : CMP_BRANCH_1R_BOTH_OFF16_FM<OPGROUP_BGTZ>, + DecodeDisambiguates<"BgtzGroupBranch">; +class BGTZC_ENC : CMP_BRANCH_1R_RT_OFF16_FM<OPGROUP_BGTZL>, + DecodeDisambiguatedBy<"BgtzlGroupBranch">; + +class BEQZC_ENC : CMP_BRANCH_OFF21_FM<0b110110>; +class BGEZALC_ENC : CMP_BRANCH_1R_BOTH_OFF16_FM<OPGROUP_BLEZ>, + DecodeDisambiguates<"BlezGroupBranch">; +class BNEZC_ENC : CMP_BRANCH_OFF21_FM<0b111110>; + +class BC1EQZ_ENC : COP1_BCCZ_FM<OPCODE5_BC1EQZ>; +class BC1NEZ_ENC : COP1_BCCZ_FM<OPCODE5_BC1NEZ>; +class BC2EQZ_ENC : COP2_BCCZ_FM<OPCODE5_BC2EQZ>; +class BC2NEZ_ENC : COP2_BCCZ_FM<OPCODE5_BC2NEZ>; + +class JIALC_ENC : JMP_IDX_COMPACT_FM<0b111110>; +class JIC_ENC : JMP_IDX_COMPACT_FM<0b110110>; +class JR_HB_R6_ENC : JR_HB_R6_FM<OPCODE6_JALR>; +class BITSWAP_ENC : SPECIAL3_2R_FM<OPCODE6_BITSWAP>; +class BLEZALC_ENC : CMP_BRANCH_1R_RT_OFF16_FM<OPGROUP_BLEZ>, + DecodeDisambiguatedBy<"BlezGroupBranch">; +class BNVC_ENC : CMP_BRANCH_2R_OFF16_FM<OPGROUP_DADDI>, + DecodeDisambiguatedBy<"DaddiGroupBranch">; +class BOVC_ENC : CMP_BRANCH_2R_OFF16_FM<OPGROUP_ADDI>, + DecodeDisambiguatedBy<"AddiGroupBranch">; +class DIV_ENC : SPECIAL_3R_FM<0b00010, 0b011010>; +class DIVU_ENC : SPECIAL_3R_FM<0b00010, 0b011011>; +class MOD_ENC : SPECIAL_3R_FM<0b00011, 0b011010>; +class MODU_ENC : SPECIAL_3R_FM<0b00011, 0b011011>; +class MUH_ENC : SPECIAL_3R_FM<0b00011, 0b011000>; +class MUHU_ENC : SPECIAL_3R_FM<0b00011, 0b011001>; +class MUL_R6_ENC : SPECIAL_3R_FM<0b00010, 0b011000>; +class MULU_ENC : SPECIAL_3R_FM<0b00010, 0b011001>; + +class MADDF_S_ENC : COP1_3R_FM<0b011000, FIELD_FMT_S>; +class MADDF_D_ENC : COP1_3R_FM<0b011000, FIELD_FMT_D>; +class MSUBF_S_ENC : COP1_3R_FM<0b011001, FIELD_FMT_S>; +class MSUBF_D_ENC : COP1_3R_FM<0b011001, FIELD_FMT_D>; + +class SEL_D_ENC : COP1_3R_FM<0b010000, FIELD_FMT_D>; +class SEL_S_ENC : COP1_3R_FM<0b010000, FIELD_FMT_S>; + +class SELEQZ_ENC : SPECIAL_3R_FM<0b00000, 0b110101>; +class SELNEZ_ENC : SPECIAL_3R_FM<0b00000, 0b110111>; + +class LWPC_ENC : PCREL19_FM<OPCODE2_LWPC>; +class LWUPC_ENC : PCREL19_FM<OPCODE2_LWUPC>; + +class MAX_S_ENC : COP1_3R_FM<0b011101, FIELD_FMT_S>; +class MAX_D_ENC : COP1_3R_FM<0b011101, FIELD_FMT_D>; +class MIN_S_ENC : COP1_3R_FM<0b011100, FIELD_FMT_S>; +class MIN_D_ENC : COP1_3R_FM<0b011100, FIELD_FMT_D>; + +class MAXA_S_ENC : COP1_3R_FM<0b011111, FIELD_FMT_S>; +class MAXA_D_ENC : COP1_3R_FM<0b011111, FIELD_FMT_D>; +class MINA_S_ENC : COP1_3R_FM<0b011110, FIELD_FMT_S>; +class MINA_D_ENC : COP1_3R_FM<0b011110, FIELD_FMT_D>; + +class SELEQZ_S_ENC : COP1_3R_FM<0b010100, FIELD_FMT_S>; +class SELEQZ_D_ENC : COP1_3R_FM<0b010100, FIELD_FMT_D>; +class SELNEZ_S_ENC : COP1_3R_FM<0b010111, FIELD_FMT_S>; +class SELNEZ_D_ENC : COP1_3R_FM<0b010111, FIELD_FMT_D>; + +class RINT_S_ENC : COP1_2R_FM<0b011010, FIELD_FMT_S>; +class RINT_D_ENC : COP1_2R_FM<0b011010, FIELD_FMT_D>; +class CLASS_S_ENC : COP1_2R_FM<0b011011, FIELD_FMT_S>; +class CLASS_D_ENC : COP1_2R_FM<0b011011, FIELD_FMT_D>; + +class CACHE_ENC : SPECIAL3_MEM_FM<OPCODE6_CACHE>; +class PREF_ENC : SPECIAL3_MEM_FM<OPCODE6_PREF>; + +class LDC2_R6_ENC : COP2LDST_FM<OPCODE5_LDC2>; +class LWC2_R6_ENC : COP2LDST_FM<OPCODE5_LWC2>; +class SDC2_R6_ENC : COP2LDST_FM<OPCODE5_SDC2>; +class SWC2_R6_ENC : COP2LDST_FM<OPCODE5_SWC2>; + +class LSA_R6_ENC : SPECIAL_LSA_FM<OPCODE6_LSA>; + +class LL_R6_ENC : SPECIAL3_LL_SC_FM<OPCODE6_LL>; +class SC_R6_ENC : SPECIAL3_LL_SC_FM<OPCODE6_SC>; + +class CLO_R6_ENC : SPECIAL_2R_FM<OPCODE6_CLO>; +class CLZ_R6_ENC : SPECIAL_2R_FM<OPCODE6_CLZ>; + +class SDBBP_R6_ENC : SPECIAL_SDBBP_FM; + +//===----------------------------------------------------------------------===// +// +// Instruction Multiclasses +// +//===----------------------------------------------------------------------===// + +class CMP_CONDN_DESC_BASE<string CondStr, string Typestr, + RegisterOperand FGROpnd, + SDPatternOperator Op = null_frag> { + dag OutOperandList = (outs FGRCCOpnd:$fd); + dag InOperandList = (ins FGROpnd:$fs, FGROpnd:$ft); + string AsmString = !strconcat("cmp.", CondStr, ".", Typestr, "\t$fd, $fs, $ft"); + list<dag> Pattern = [(set FGRCCOpnd:$fd, (Op FGROpnd:$fs, FGROpnd:$ft))]; +} + +multiclass CMP_CC_M <FIELD_CMP_FORMAT Format, string Typestr, + RegisterOperand FGROpnd>{ + let AdditionalPredicates = [NotInMicroMips] in { + def CMP_F_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_AF>, + CMP_CONDN_DESC_BASE<"af", Typestr, FGROpnd>, + ISA_MIPS32R6, HARDFLOAT; + def CMP_UN_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_UN>, + CMP_CONDN_DESC_BASE<"un", Typestr, FGROpnd, setuo>, + ISA_MIPS32R6, HARDFLOAT; + def CMP_EQ_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_EQ>, + CMP_CONDN_DESC_BASE<"eq", Typestr, FGROpnd, setoeq>, + ISA_MIPS32R6, HARDFLOAT; + def CMP_UEQ_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_UEQ>, + CMP_CONDN_DESC_BASE<"ueq", Typestr, FGROpnd, setueq>, + ISA_MIPS32R6, HARDFLOAT; + def CMP_LT_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_LT>, + CMP_CONDN_DESC_BASE<"lt", Typestr, FGROpnd, setolt>, + ISA_MIPS32R6, HARDFLOAT; + def CMP_ULT_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_ULT>, + CMP_CONDN_DESC_BASE<"ult", Typestr, FGROpnd, setult>, + ISA_MIPS32R6, HARDFLOAT; + def CMP_LE_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_LE>, + CMP_CONDN_DESC_BASE<"le", Typestr, FGROpnd, setole>, + ISA_MIPS32R6, HARDFLOAT; + def CMP_ULE_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_ULE>, + CMP_CONDN_DESC_BASE<"ule", Typestr, FGROpnd, setule>, + ISA_MIPS32R6, HARDFLOAT; + def CMP_SAF_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SAF>, + CMP_CONDN_DESC_BASE<"saf", Typestr, FGROpnd>, + ISA_MIPS32R6, HARDFLOAT; + def CMP_SUN_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SUN>, + CMP_CONDN_DESC_BASE<"sun", Typestr, FGROpnd>, + ISA_MIPS32R6, HARDFLOAT; + def CMP_SEQ_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SEQ>, + CMP_CONDN_DESC_BASE<"seq", Typestr, FGROpnd>, + ISA_MIPS32R6, HARDFLOAT; + def CMP_SUEQ_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SUEQ>, + CMP_CONDN_DESC_BASE<"sueq", Typestr, FGROpnd>, + ISA_MIPS32R6, HARDFLOAT; + def CMP_SLT_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SLT>, + CMP_CONDN_DESC_BASE<"slt", Typestr, FGROpnd>, + ISA_MIPS32R6, HARDFLOAT; + def CMP_SULT_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SULT>, + CMP_CONDN_DESC_BASE<"sult", Typestr, FGROpnd>, + ISA_MIPS32R6, HARDFLOAT; + def CMP_SLE_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SLE>, + CMP_CONDN_DESC_BASE<"sle", Typestr, FGROpnd>, + ISA_MIPS32R6, HARDFLOAT; + def CMP_SULE_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SULE>, + CMP_CONDN_DESC_BASE<"sule", Typestr, FGROpnd>, + ISA_MIPS32R6, HARDFLOAT; + } +} + +//===----------------------------------------------------------------------===// +// +// Instruction Descriptions +// +//===----------------------------------------------------------------------===// + +class PCREL_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + Operand ImmOpnd> : MipsR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rs); + dag InOperandList = (ins ImmOpnd:$imm); + string AsmString = !strconcat(instr_asm, "\t$rs, $imm"); + list<dag> Pattern = []; +} + +class ADDIUPC_DESC : PCREL_DESC_BASE<"addiupc", GPR32Opnd, simm19_lsl2>; +class LWPC_DESC: PCREL_DESC_BASE<"lwpc", GPR32Opnd, simm19_lsl2>; +class LWUPC_DESC: PCREL_DESC_BASE<"lwupc", GPR32Opnd, simm19_lsl2>; + +class ALIGN_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + Operand ImmOpnd> : MipsR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, ImmOpnd:$bp); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt, $bp"); + list<dag> Pattern = []; +} + +class ALIGN_DESC : ALIGN_DESC_BASE<"align", GPR32Opnd, uimm2>; + +class ALUIPC_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> + : MipsR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rs); + dag InOperandList = (ins simm16:$imm); + string AsmString = !strconcat(instr_asm, "\t$rs, $imm"); + list<dag> Pattern = []; +} + +class ALUIPC_DESC : ALUIPC_DESC_BASE<"aluipc", GPR32Opnd>; +class AUIPC_DESC : ALUIPC_DESC_BASE<"auipc", GPR32Opnd>; + +class AUI_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> + : MipsR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rs); + dag InOperandList = (ins GPROpnd:$rt, simm16:$imm); + string AsmString = !strconcat(instr_asm, "\t$rs, $rt, $imm"); + list<dag> Pattern = []; +} + +class AUI_DESC : AUI_DESC_BASE<"aui", GPR32Opnd>; + +class BRANCH_DESC_BASE { + bit isBranch = 1; + bit isTerminator = 1; + bit hasDelaySlot = 0; +} + +class BC_DESC_BASE<string instr_asm, DAGOperand opnd> : BRANCH_DESC_BASE, + MipsR6Arch<instr_asm> { + dag InOperandList = (ins opnd:$offset); + dag OutOperandList = (outs); + string AsmString = !strconcat(instr_asm, "\t$offset"); + bit isBarrier = 1; +} + +class CMP_BC_DESC_BASE<string instr_asm, DAGOperand opnd, + RegisterOperand GPROpnd> : BRANCH_DESC_BASE { + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, opnd:$offset); + dag OutOperandList = (outs); + string AsmString = !strconcat(instr_asm, "\t$rs, $rt, $offset"); + list<Register> Defs = [AT]; +} + +class CMP_CBR_EQNE_Z_DESC_BASE<string instr_asm, DAGOperand opnd, + RegisterOperand GPROpnd> : BRANCH_DESC_BASE { + dag InOperandList = (ins GPROpnd:$rs, opnd:$offset); + dag OutOperandList = (outs); + string AsmString = !strconcat(instr_asm, "\t$rs, $offset"); + list<Register> Defs = [AT]; +} + +class CMP_CBR_RT_Z_DESC_BASE<string instr_asm, DAGOperand opnd, + RegisterOperand GPROpnd> + : BRANCH_DESC_BASE, MipsR6Arch<instr_asm> { + dag InOperandList = (ins GPROpnd:$rt, opnd:$offset); + dag OutOperandList = (outs); + string AsmString = !strconcat(instr_asm, "\t$rt, $offset"); + list<Register> Defs = [AT]; +} + +class BAL_DESC : BC_DESC_BASE<"bal", brtarget> { + bit isCall = 1; + bit hasDelaySlot = 1; + list<Register> Defs = [RA]; +} + +class BALC_DESC : BC_DESC_BASE<"balc", brtarget26> { + bit isCall = 1; + list<Register> Defs = [RA]; +} + +class BC_DESC : BC_DESC_BASE<"bc", brtarget26>; +class BGEC_DESC : CMP_BC_DESC_BASE<"bgec", brtarget, GPR32Opnd>; +class BGEUC_DESC : CMP_BC_DESC_BASE<"bgeuc", brtarget, GPR32Opnd>; +class BEQC_DESC : CMP_BC_DESC_BASE<"beqc", brtarget, GPR32Opnd>; +class BNEC_DESC : CMP_BC_DESC_BASE<"bnec", brtarget, GPR32Opnd>; + +class BLTC_DESC : CMP_BC_DESC_BASE<"bltc", brtarget, GPR32Opnd>; +class BLTUC_DESC : CMP_BC_DESC_BASE<"bltuc", brtarget, GPR32Opnd>; + +class BLTZC_DESC : CMP_CBR_RT_Z_DESC_BASE<"bltzc", brtarget, GPR32Opnd>; +class BGEZC_DESC : CMP_CBR_RT_Z_DESC_BASE<"bgezc", brtarget, GPR32Opnd>; + +class BLEZC_DESC : CMP_CBR_RT_Z_DESC_BASE<"blezc", brtarget, GPR32Opnd>; +class BGTZC_DESC : CMP_CBR_RT_Z_DESC_BASE<"bgtzc", brtarget, GPR32Opnd>; + +class BEQZC_DESC : CMP_CBR_EQNE_Z_DESC_BASE<"beqzc", brtarget21, GPR32Opnd>; +class BNEZC_DESC : CMP_CBR_EQNE_Z_DESC_BASE<"bnezc", brtarget21, GPR32Opnd>; + +class COP1_BCCZ_DESC_BASE<string instr_asm> : BRANCH_DESC_BASE { + dag InOperandList = (ins FGR64Opnd:$ft, brtarget:$offset); + dag OutOperandList = (outs); + string AsmString = instr_asm; + bit hasDelaySlot = 1; +} + +class BC1EQZ_DESC : COP1_BCCZ_DESC_BASE<"bc1eqz $ft, $offset">; +class BC1NEZ_DESC : COP1_BCCZ_DESC_BASE<"bc1nez $ft, $offset">; + +class COP2_BCCZ_DESC_BASE<string instr_asm> : BRANCH_DESC_BASE { + dag InOperandList = (ins COP2Opnd:$ct, brtarget:$offset); + dag OutOperandList = (outs); + string AsmString = instr_asm; + bit hasDelaySlot = 1; +} + +class BC2EQZ_DESC : COP2_BCCZ_DESC_BASE<"bc2eqz $ct, $offset">; +class BC2NEZ_DESC : COP2_BCCZ_DESC_BASE<"bc2nez $ct, $offset">; + +class BOVC_DESC : CMP_BC_DESC_BASE<"bovc", brtarget, GPR32Opnd>; +class BNVC_DESC : CMP_BC_DESC_BASE<"bnvc", brtarget, GPR32Opnd>; + +class JMP_IDX_COMPACT_DESC_BASE<string opstr, DAGOperand opnd, + RegisterOperand GPROpnd> + : MipsR6Arch<opstr> { + dag InOperandList = (ins GPROpnd:$rt, opnd:$offset); + string AsmString = !strconcat(opstr, "\t$rt, $offset"); + list<dag> Pattern = []; + bit isTerminator = 1; + bit hasDelaySlot = 0; +} + +class JIALC_DESC : JMP_IDX_COMPACT_DESC_BASE<"jialc", calloffset16, + GPR32Opnd> { + bit isCall = 1; + list<Register> Defs = [RA]; +} + +class JIC_DESC : JMP_IDX_COMPACT_DESC_BASE<"jic", jmpoffset16, GPR32Opnd> { + bit isBarrier = 1; + list<Register> Defs = [AT]; +} + +class JR_HB_R6_DESC : JR_HB_DESC_BASE<"jr.hb", GPR32Opnd> { + bit isBranch = 1; + bit isIndirectBranch = 1; + bit hasDelaySlot = 1; + bit isTerminator=1; + bit isBarrier=1; +} + +class BITSWAP_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> + : MipsR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rt"); + list<dag> Pattern = []; +} + +class BITSWAP_DESC : BITSWAP_DESC_BASE<"bitswap", GPR32Opnd>; + +class DIVMOD_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + SDPatternOperator Op=null_frag> + : MipsR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt"); + list<dag> Pattern = [(set GPROpnd:$rd, (Op GPROpnd:$rs, GPROpnd:$rt))]; + + // This instruction doesn't trap division by zero itself. We must insert + // teq instructions as well. + bit usesCustomInserter = 1; +} + +class DIV_DESC : DIVMOD_DESC_BASE<"div", GPR32Opnd, sdiv>; +class DIVU_DESC : DIVMOD_DESC_BASE<"divu", GPR32Opnd, udiv>; +class MOD_DESC : DIVMOD_DESC_BASE<"mod", GPR32Opnd, srem>; +class MODU_DESC : DIVMOD_DESC_BASE<"modu", GPR32Opnd, urem>; + +class BEQZALC_DESC : CMP_CBR_RT_Z_DESC_BASE<"beqzalc", brtarget, GPR32Opnd> { + list<Register> Defs = [RA]; +} + +class BGEZALC_DESC : CMP_CBR_RT_Z_DESC_BASE<"bgezalc", brtarget, GPR32Opnd> { + list<Register> Defs = [RA]; +} + +class BGTZALC_DESC : CMP_CBR_RT_Z_DESC_BASE<"bgtzalc", brtarget, GPR32Opnd> { + list<Register> Defs = [RA]; +} + +class BLEZALC_DESC : CMP_CBR_RT_Z_DESC_BASE<"blezalc", brtarget, GPR32Opnd> { + list<Register> Defs = [RA]; +} + +class BLTZALC_DESC : CMP_CBR_RT_Z_DESC_BASE<"bltzalc", brtarget, GPR32Opnd> { + list<Register> Defs = [RA]; +} + +class BNEZALC_DESC : CMP_CBR_RT_Z_DESC_BASE<"bnezalc", brtarget, GPR32Opnd> { + list<Register> Defs = [RA]; +} + +class MUL_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + SDPatternOperator Op=null_frag> : MipsR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt"); + list<dag> Pattern = [(set GPROpnd:$rd, (Op GPROpnd:$rs, GPROpnd:$rt))]; +} + +class MUH_DESC : MUL_R6_DESC_BASE<"muh", GPR32Opnd, mulhs>; +class MUHU_DESC : MUL_R6_DESC_BASE<"muhu", GPR32Opnd, mulhu>; +class MUL_R6_DESC : MUL_R6_DESC_BASE<"mul", GPR32Opnd, mul>; +class MULU_DESC : MUL_R6_DESC_BASE<"mulu", GPR32Opnd>; + +class COP1_SEL_DESC_BASE<string instr_asm, RegisterOperand FGROpnd> { + dag OutOperandList = (outs FGROpnd:$fd); + dag InOperandList = (ins FGRCCOpnd:$fd_in, FGROpnd:$fs, FGROpnd:$ft); + string AsmString = !strconcat(instr_asm, "\t$fd, $fs, $ft"); + list<dag> Pattern = [(set FGROpnd:$fd, (select FGRCCOpnd:$fd_in, + FGROpnd:$ft, + FGROpnd:$fs))]; + string Constraints = "$fd_in = $fd"; +} + +class SEL_D_DESC : COP1_SEL_DESC_BASE<"sel.d", FGR64Opnd> { + // We must insert a SUBREG_TO_REG around $fd_in + bit usesCustomInserter = 1; +} +class SEL_S_DESC : COP1_SEL_DESC_BASE<"sel.s", FGR32Opnd>; + +class SELEQNE_Z_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> + : MipsR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt"); + list<dag> Pattern = []; +} + +class SELEQZ_DESC : SELEQNE_Z_DESC_BASE<"seleqz", GPR32Opnd>; +class SELNEZ_DESC : SELEQNE_Z_DESC_BASE<"selnez", GPR32Opnd>; + +class COP1_4R_DESC_BASE<string instr_asm, RegisterOperand FGROpnd> { + dag OutOperandList = (outs FGROpnd:$fd); + dag InOperandList = (ins FGROpnd:$fd_in, FGROpnd:$fs, FGROpnd:$ft); + string AsmString = !strconcat(instr_asm, "\t$fd, $fs, $ft"); + list<dag> Pattern = []; + string Constraints = "$fd_in = $fd"; +} + +class MADDF_S_DESC : COP1_4R_DESC_BASE<"maddf.s", FGR32Opnd>; +class MADDF_D_DESC : COP1_4R_DESC_BASE<"maddf.d", FGR64Opnd>; +class MSUBF_S_DESC : COP1_4R_DESC_BASE<"msubf.s", FGR32Opnd>; +class MSUBF_D_DESC : COP1_4R_DESC_BASE<"msubf.d", FGR64Opnd>; + +class MAX_MIN_DESC_BASE<string instr_asm, RegisterOperand FGROpnd> { + dag OutOperandList = (outs FGROpnd:$fd); + dag InOperandList = (ins FGROpnd:$fs, FGROpnd:$ft); + string AsmString = !strconcat(instr_asm, "\t$fd, $fs, $ft"); + list<dag> Pattern = []; +} + +class MAX_S_DESC : MAX_MIN_DESC_BASE<"max.s", FGR32Opnd>; +class MAX_D_DESC : MAX_MIN_DESC_BASE<"max.d", FGR64Opnd>; +class MIN_S_DESC : MAX_MIN_DESC_BASE<"min.s", FGR32Opnd>; +class MIN_D_DESC : MAX_MIN_DESC_BASE<"min.d", FGR64Opnd>; + +class MAXA_S_DESC : MAX_MIN_DESC_BASE<"maxa.s", FGR32Opnd>; +class MAXA_D_DESC : MAX_MIN_DESC_BASE<"maxa.d", FGR64Opnd>; +class MINA_S_DESC : MAX_MIN_DESC_BASE<"mina.s", FGR32Opnd>; +class MINA_D_DESC : MAX_MIN_DESC_BASE<"mina.d", FGR64Opnd>; + +class SELEQNEZ_DESC_BASE<string instr_asm, RegisterOperand FGROpnd> { + dag OutOperandList = (outs FGROpnd:$fd); + dag InOperandList = (ins FGROpnd:$fs, FGROpnd:$ft); + string AsmString = !strconcat(instr_asm, "\t$fd, $fs, $ft"); + list<dag> Pattern = []; +} + +class SELEQZ_S_DESC : SELEQNEZ_DESC_BASE<"seleqz.s", FGR32Opnd>; +class SELEQZ_D_DESC : SELEQNEZ_DESC_BASE<"seleqz.d", FGR64Opnd>; +class SELNEZ_S_DESC : SELEQNEZ_DESC_BASE<"selnez.s", FGR32Opnd>; +class SELNEZ_D_DESC : SELEQNEZ_DESC_BASE<"selnez.d", FGR64Opnd>; + +class CLASS_RINT_DESC_BASE<string instr_asm, RegisterOperand FGROpnd> { + dag OutOperandList = (outs FGROpnd:$fd); + dag InOperandList = (ins FGROpnd:$fs); + string AsmString = !strconcat(instr_asm, "\t$fd, $fs"); + list<dag> Pattern = []; +} + +class RINT_S_DESC : CLASS_RINT_DESC_BASE<"rint.s", FGR32Opnd>; +class RINT_D_DESC : CLASS_RINT_DESC_BASE<"rint.d", FGR64Opnd>; +class CLASS_S_DESC : CLASS_RINT_DESC_BASE<"class.s", FGR32Opnd>; +class CLASS_D_DESC : CLASS_RINT_DESC_BASE<"class.d", FGR64Opnd>; + +class CACHE_HINT_DESC<string instr_asm, Operand MemOpnd, + RegisterOperand GPROpnd> : MipsR6Arch<instr_asm> { + dag OutOperandList = (outs); + dag InOperandList = (ins MemOpnd:$addr, uimm5:$hint); + string AsmString = !strconcat(instr_asm, "\t$hint, $addr"); + list<dag> Pattern = []; + string DecoderMethod = "DecodeCacheeOp_CacheOpR6"; +} + +class CACHE_DESC : CACHE_HINT_DESC<"cache", mem_simm9, GPR32Opnd>; +class PREF_DESC : CACHE_HINT_DESC<"pref", mem_simm9, GPR32Opnd>; + +class COP2LD_DESC_BASE<string instr_asm, RegisterOperand COPOpnd> { + dag OutOperandList = (outs COPOpnd:$rt); + dag InOperandList = (ins mem_simm11:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + bit mayLoad = 1; + string DecoderMethod = "DecodeFMemCop2R6"; +} + +class LDC2_R6_DESC : COP2LD_DESC_BASE<"ldc2", COP2Opnd>; +class LWC2_R6_DESC : COP2LD_DESC_BASE<"lwc2", COP2Opnd>; + +class COP2ST_DESC_BASE<string instr_asm, RegisterOperand COPOpnd> { + dag OutOperandList = (outs); + dag InOperandList = (ins COPOpnd:$rt, mem_simm11:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + bit mayStore = 1; + string DecoderMethod = "DecodeFMemCop2R6"; +} + +class SDC2_R6_DESC : COP2ST_DESC_BASE<"sdc2", COP2Opnd>; +class SWC2_R6_DESC : COP2ST_DESC_BASE<"swc2", COP2Opnd>; + +class LSA_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + Operand ImmOpnd> : MipsR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, ImmOpnd:$imm2); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt, $imm2"); + list<dag> Pattern = []; +} + +class LSA_R6_DESC : LSA_R6_DESC_BASE<"lsa", GPR32Opnd, uimm2_plus1>; + +class LL_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$rt); + dag InOperandList = (ins mem_simm9:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + bit mayLoad = 1; +} + +class LL_R6_DESC : LL_R6_DESC_BASE<"ll", GPR32Opnd>; + +class SC_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$dst); + dag InOperandList = (ins GPROpnd:$rt, mem_simm9:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + bit mayStore = 1; + string Constraints = "$rt = $dst"; +} + +class SC_R6_DESC : SC_R6_DESC_BASE<"sc", GPR32Opnd>; + +class CLO_CLZ_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> + : MipsR6Arch<instr_asm> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs"); +} + +class CLO_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> : + CLO_CLZ_R6_DESC_BASE<instr_asm, GPROpnd> { + list<dag> Pattern = [(set GPROpnd:$rd, (ctlz (not GPROpnd:$rs)))]; +} + +class CLZ_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> : + CLO_CLZ_R6_DESC_BASE<instr_asm, GPROpnd> { + list<dag> Pattern = [(set GPROpnd:$rd, (ctlz GPROpnd:$rs))]; +} + +class CLO_R6_DESC : CLO_R6_DESC_BASE<"clo", GPR32Opnd>; +class CLZ_R6_DESC : CLZ_R6_DESC_BASE<"clz", GPR32Opnd>; + +class SDBBP_R6_DESC { + dag OutOperandList = (outs); + dag InOperandList = (ins uimm20:$code_); + string AsmString = "sdbbp\t$code_"; + list<dag> Pattern = []; +} + +//===----------------------------------------------------------------------===// +// +// Instruction Definitions +// +//===----------------------------------------------------------------------===// + +def ADDIUPC : R6MMR6Rel, ADDIUPC_ENC, ADDIUPC_DESC, ISA_MIPS32R6; +def ALIGN : R6MMR6Rel, ALIGN_ENC, ALIGN_DESC, ISA_MIPS32R6; +def ALUIPC : R6MMR6Rel, ALUIPC_ENC, ALUIPC_DESC, ISA_MIPS32R6; +def AUI : R6MMR6Rel, AUI_ENC, AUI_DESC, ISA_MIPS32R6; +def AUIPC : R6MMR6Rel, AUIPC_ENC, AUIPC_DESC, ISA_MIPS32R6; +def BAL : BAL_ENC, BAL_DESC, ISA_MIPS32R6; +def BALC : R6MMR6Rel, BALC_ENC, BALC_DESC, ISA_MIPS32R6; +def BC1EQZ : BC1EQZ_ENC, BC1EQZ_DESC, ISA_MIPS32R6, HARDFLOAT; +def BC1NEZ : BC1NEZ_ENC, BC1NEZ_DESC, ISA_MIPS32R6, HARDFLOAT; +def BC2EQZ : BC2EQZ_ENC, BC2EQZ_DESC, ISA_MIPS32R6; +def BC2NEZ : BC2NEZ_ENC, BC2NEZ_DESC, ISA_MIPS32R6; +def BC : R6MMR6Rel, BC_ENC, BC_DESC, ISA_MIPS32R6; +def BEQC : BEQC_ENC, BEQC_DESC, ISA_MIPS32R6; +def BEQZALC : R6MMR6Rel, BEQZALC_ENC, BEQZALC_DESC, ISA_MIPS32R6; +def BEQZC : BEQZC_ENC, BEQZC_DESC, ISA_MIPS32R6; +def BGEC : BGEC_ENC, BGEC_DESC, ISA_MIPS32R6; +def BGEUC : BGEUC_ENC, BGEUC_DESC, ISA_MIPS32R6; +def BGEZALC : R6MMR6Rel, BGEZALC_ENC, BGEZALC_DESC, ISA_MIPS32R6; +def BGEZC : BGEZC_ENC, BGEZC_DESC, ISA_MIPS32R6; +def BGTZALC : R6MMR6Rel, BGTZALC_ENC, BGTZALC_DESC, ISA_MIPS32R6; +def BGTZC : BGTZC_ENC, BGTZC_DESC, ISA_MIPS32R6; +def BITSWAP : R6MMR6Rel, BITSWAP_ENC, BITSWAP_DESC, ISA_MIPS32R6; +def BLEZALC : R6MMR6Rel, BLEZALC_ENC, BLEZALC_DESC, ISA_MIPS32R6; +def BLEZC : BLEZC_ENC, BLEZC_DESC, ISA_MIPS32R6; +def BLTC : BLTC_ENC, BLTC_DESC, ISA_MIPS32R6; +def BLTUC : BLTUC_ENC, BLTUC_DESC, ISA_MIPS32R6; +def BLTZALC : R6MMR6Rel, BLTZALC_ENC, BLTZALC_DESC, ISA_MIPS32R6; +def BLTZC : BLTZC_ENC, BLTZC_DESC, ISA_MIPS32R6; +def BNEC : BNEC_ENC, BNEC_DESC, ISA_MIPS32R6; +def BNEZALC : R6MMR6Rel, BNEZALC_ENC, BNEZALC_DESC, ISA_MIPS32R6; +def BNEZC : BNEZC_ENC, BNEZC_DESC, ISA_MIPS32R6; +def BNVC : BNVC_ENC, BNVC_DESC, ISA_MIPS32R6; +def BOVC : BOVC_ENC, BOVC_DESC, ISA_MIPS32R6; +def CACHE_R6 : R6MMR6Rel, CACHE_ENC, CACHE_DESC, ISA_MIPS32R6; +let AdditionalPredicates = [NotInMicroMips] in { + def CLASS_D : CLASS_D_ENC, CLASS_D_DESC, ISA_MIPS32R6, HARDFLOAT; + def CLASS_S : CLASS_S_ENC, CLASS_S_DESC, ISA_MIPS32R6, HARDFLOAT; +} +def CLO_R6 : R6MMR6Rel, CLO_R6_ENC, CLO_R6_DESC, ISA_MIPS32R6; +def CLZ_R6 : R6MMR6Rel, CLZ_R6_ENC, CLZ_R6_DESC, ISA_MIPS32R6; +defm S : CMP_CC_M<FIELD_CMP_FORMAT_S, "s", FGR32Opnd>; +defm D : CMP_CC_M<FIELD_CMP_FORMAT_D, "d", FGR64Opnd>; +def DIV : R6MMR6Rel, DIV_ENC, DIV_DESC, ISA_MIPS32R6; +def DIVU : R6MMR6Rel, DIVU_ENC, DIVU_DESC, ISA_MIPS32R6; +def JIALC : R6MMR6Rel, JIALC_ENC, JIALC_DESC, ISA_MIPS32R6; +def JIC : R6MMR6Rel, JIC_ENC, JIC_DESC, ISA_MIPS32R6; +def JR_HB_R6 : JR_HB_R6_ENC, JR_HB_R6_DESC, ISA_MIPS32R6; +def LDC2_R6 : LDC2_R6_ENC, LDC2_R6_DESC, ISA_MIPS32R6; +def LL_R6 : LL_R6_ENC, LL_R6_DESC, ISA_MIPS32R6; +def LSA_R6 : R6MMR6Rel, LSA_R6_ENC, LSA_R6_DESC, ISA_MIPS32R6; +def LWC2_R6 : LWC2_R6_ENC, LWC2_R6_DESC, ISA_MIPS32R6; +def LWPC : R6MMR6Rel, LWPC_ENC, LWPC_DESC, ISA_MIPS32R6; +def LWUPC : LWUPC_ENC, LWUPC_DESC, ISA_MIPS32R6; +let AdditionalPredicates = [NotInMicroMips] in { + def MADDF_S : MADDF_S_ENC, MADDF_S_DESC, ISA_MIPS32R6, HARDFLOAT; + def MADDF_D : MADDF_D_ENC, MADDF_D_DESC, ISA_MIPS32R6, HARDFLOAT; + def MAXA_D : MAXA_D_ENC, MAXA_D_DESC, ISA_MIPS32R6, HARDFLOAT; + def MAXA_S : MAXA_S_ENC, MAXA_S_DESC, ISA_MIPS32R6, HARDFLOAT; + def MAX_D : MAX_D_ENC, MAX_D_DESC, ISA_MIPS32R6, HARDFLOAT; + def MAX_S : MAX_S_ENC, MAX_S_DESC, ISA_MIPS32R6, HARDFLOAT; + def MINA_D : MINA_D_ENC, MINA_D_DESC, ISA_MIPS32R6, HARDFLOAT; + def MINA_S : MINA_S_ENC, MINA_S_DESC, ISA_MIPS32R6, HARDFLOAT; + def MIN_D : MIN_D_ENC, MIN_D_DESC, ISA_MIPS32R6, HARDFLOAT; + def MIN_S : MIN_S_ENC, MIN_S_DESC, ISA_MIPS32R6, HARDFLOAT; +} +def MOD : R6MMR6Rel, MOD_ENC, MOD_DESC, ISA_MIPS32R6; +def MODU : R6MMR6Rel, MODU_ENC, MODU_DESC, ISA_MIPS32R6; +let AdditionalPredicates = [NotInMicroMips] in { + def MSUBF_S : MSUBF_S_ENC, MSUBF_S_DESC, ISA_MIPS32R6, HARDFLOAT; + def MSUBF_D : MSUBF_D_ENC, MSUBF_D_DESC, ISA_MIPS32R6, HARDFLOAT; +} +def MUH : R6MMR6Rel, MUH_ENC, MUH_DESC, ISA_MIPS32R6; +def MUHU : R6MMR6Rel, MUHU_ENC, MUHU_DESC, ISA_MIPS32R6; +def MUL_R6 : R6MMR6Rel, MUL_R6_ENC, MUL_R6_DESC, ISA_MIPS32R6; +def MULU : R6MMR6Rel, MULU_ENC, MULU_DESC, ISA_MIPS32R6; +def NAL; // BAL with rd=0 +def PREF_R6 : R6MMR6Rel, PREF_ENC, PREF_DESC, ISA_MIPS32R6; +let AdditionalPredicates = [NotInMicroMips] in { + def RINT_D : RINT_D_ENC, RINT_D_DESC, ISA_MIPS32R6, HARDFLOAT; + def RINT_S : RINT_S_ENC, RINT_S_DESC, ISA_MIPS32R6, HARDFLOAT; +} +def SC_R6 : SC_R6_ENC, SC_R6_DESC, ISA_MIPS32R6; +let AdditionalPredicates = [NotInMicroMips] in { +def SDBBP_R6 : SDBBP_R6_ENC, SDBBP_R6_DESC, ISA_MIPS32R6; +} +def SDC2_R6 : SDC2_R6_ENC, SDC2_R6_DESC, ISA_MIPS32R6; +def SELEQZ : R6MMR6Rel, SELEQZ_ENC, SELEQZ_DESC, ISA_MIPS32R6, GPR_32; +let AdditionalPredicates = [NotInMicroMips] in { + def SELEQZ_D : SELEQZ_D_ENC, SELEQZ_D_DESC, ISA_MIPS32R6, HARDFLOAT; + def SELEQZ_S : SELEQZ_S_ENC, SELEQZ_S_DESC, ISA_MIPS32R6, HARDFLOAT; +} +def SELNEZ : R6MMR6Rel, SELNEZ_ENC, SELNEZ_DESC, ISA_MIPS32R6, GPR_32; +let AdditionalPredicates = [NotInMicroMips] in { + def SELNEZ_D : SELNEZ_D_ENC, SELNEZ_D_DESC, ISA_MIPS32R6, HARDFLOAT; + def SELNEZ_S : SELNEZ_S_ENC, SELNEZ_S_DESC, ISA_MIPS32R6, HARDFLOAT; + def SEL_D : SEL_D_ENC, SEL_D_DESC, ISA_MIPS32R6, HARDFLOAT; + def SEL_S : SEL_S_ENC, SEL_S_DESC, ISA_MIPS32R6, HARDFLOAT; +} +def SWC2_R6 : SWC2_R6_ENC, SWC2_R6_DESC, ISA_MIPS32R6; + +//===----------------------------------------------------------------------===// +// +// Instruction Aliases +// +//===----------------------------------------------------------------------===// + +let AdditionalPredicates = [NotInMicroMips] in { +def : MipsInstAlias<"sdbbp", (SDBBP_R6 0)>, ISA_MIPS32R6; +} +def : MipsInstAlias<"jr $rs", (JALR ZERO, GPR32Opnd:$rs), 1>, ISA_MIPS32R6; + +//===----------------------------------------------------------------------===// +// +// Patterns and Pseudo Instructions +// +//===----------------------------------------------------------------------===// + +// comparisons supported via another comparison +multiclass Cmp_Pats<ValueType VT, Instruction NOROp, Register ZEROReg> { +def : MipsPat<(setone VT:$lhs, VT:$rhs), + (NOROp (!cast<Instruction>("CMP_UEQ_"#NAME) VT:$lhs, VT:$rhs), ZEROReg)>; +def : MipsPat<(seto VT:$lhs, VT:$rhs), + (NOROp (!cast<Instruction>("CMP_UN_"#NAME) VT:$lhs, VT:$rhs), ZEROReg)>; +def : MipsPat<(setune VT:$lhs, VT:$rhs), + (NOROp (!cast<Instruction>("CMP_EQ_"#NAME) VT:$lhs, VT:$rhs), ZEROReg)>; +def : MipsPat<(seteq VT:$lhs, VT:$rhs), + (!cast<Instruction>("CMP_EQ_"#NAME) VT:$lhs, VT:$rhs)>; +def : MipsPat<(setgt VT:$lhs, VT:$rhs), + (!cast<Instruction>("CMP_LE_"#NAME) VT:$rhs, VT:$lhs)>; +def : MipsPat<(setge VT:$lhs, VT:$rhs), + (!cast<Instruction>("CMP_LT_"#NAME) VT:$rhs, VT:$lhs)>; +def : MipsPat<(setlt VT:$lhs, VT:$rhs), + (!cast<Instruction>("CMP_LT_"#NAME) VT:$lhs, VT:$rhs)>; +def : MipsPat<(setle VT:$lhs, VT:$rhs), + (!cast<Instruction>("CMP_LE_"#NAME) VT:$lhs, VT:$rhs)>; +def : MipsPat<(setne VT:$lhs, VT:$rhs), + (NOROp (!cast<Instruction>("CMP_EQ_"#NAME) VT:$lhs, VT:$rhs), ZEROReg)>; +} + +defm S : Cmp_Pats<f32, NOR, ZERO>, ISA_MIPS32R6; +defm D : Cmp_Pats<f64, NOR, ZERO>, ISA_MIPS32R6; + +// i32 selects +multiclass SelectInt_Pats<ValueType RC, Instruction OROp, Instruction XORiOp, + Instruction SLTiOp, Instruction SLTiuOp, + Instruction SELEQZOp, Instruction SELNEZOp, + SDPatternOperator imm_type, ValueType Opg> { +// reg, immz +def : MipsPat<(select (Opg (seteq RC:$cond, immz)), RC:$t, RC:$f), + (OROp (SELEQZOp RC:$t, RC:$cond), (SELNEZOp RC:$f, RC:$cond))>; +def : MipsPat<(select (Opg (setne RC:$cond, immz)), RC:$t, RC:$f), + (OROp (SELNEZOp RC:$t, RC:$cond), (SELEQZOp RC:$f, RC:$cond))>; + +// reg, immZExt16[_64] +def : MipsPat<(select (Opg (seteq RC:$cond, imm_type:$imm)), RC:$t, RC:$f), + (OROp (SELEQZOp RC:$t, (XORiOp RC:$cond, imm_type:$imm)), + (SELNEZOp RC:$f, (XORiOp RC:$cond, imm_type:$imm)))>; +def : MipsPat<(select (Opg (setne RC:$cond, imm_type:$imm)), RC:$t, RC:$f), + (OROp (SELNEZOp RC:$t, (XORiOp RC:$cond, imm_type:$imm)), + (SELEQZOp RC:$f, (XORiOp RC:$cond, imm_type:$imm)))>; + +// reg, immSExt16Plus1 +def : MipsPat<(select (Opg (setgt RC:$cond, immSExt16Plus1:$imm)), RC:$t, RC:$f), + (OROp (SELEQZOp RC:$t, (SLTiOp RC:$cond, (Plus1 imm:$imm))), + (SELNEZOp RC:$f, (SLTiOp RC:$cond, (Plus1 imm:$imm))))>; +def : MipsPat<(select (Opg (setugt RC:$cond, immSExt16Plus1:$imm)), RC:$t, RC:$f), + (OROp (SELEQZOp RC:$t, (SLTiuOp RC:$cond, (Plus1 imm:$imm))), + (SELNEZOp RC:$f, (SLTiuOp RC:$cond, (Plus1 imm:$imm))))>; + +def : MipsPat<(select (Opg (seteq RC:$cond, immz)), RC:$t, immz), + (SELEQZOp RC:$t, RC:$cond)>; +def : MipsPat<(select (Opg (setne RC:$cond, immz)), RC:$t, immz), + (SELNEZOp RC:$t, RC:$cond)>; +def : MipsPat<(select (Opg (seteq RC:$cond, immz)), immz, RC:$f), + (SELNEZOp RC:$f, RC:$cond)>; +def : MipsPat<(select (Opg (setne RC:$cond, immz)), immz, RC:$f), + (SELEQZOp RC:$f, RC:$cond)>; +} + +defm : SelectInt_Pats<i32, OR, XORi, SLTi, SLTiu, SELEQZ, SELNEZ, + immZExt16, i32>, ISA_MIPS32R6; + +def : MipsPat<(select i32:$cond, i32:$t, i32:$f), + (OR (SELNEZ i32:$t, i32:$cond), + (SELEQZ i32:$f, i32:$cond))>, + ISA_MIPS32R6; +def : MipsPat<(select i32:$cond, i32:$t, immz), + (SELNEZ i32:$t, i32:$cond)>, + ISA_MIPS32R6; +def : MipsPat<(select i32:$cond, immz, i32:$f), + (SELEQZ i32:$f, i32:$cond)>, + ISA_MIPS32R6; diff --git a/contrib/llvm/lib/Target/Mips/Mips64InstrInfo.td b/contrib/llvm/lib/Target/Mips/Mips64InstrInfo.td new file mode 100644 index 0000000..cbdcdd7 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips64InstrInfo.td @@ -0,0 +1,686 @@ +//===- Mips64InstrInfo.td - Mips64 Instruction Information -*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes Mips64 instructions. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Mips Operand, Complex Patterns and Transformations Definitions. +//===----------------------------------------------------------------------===// + +// Unsigned Operand +def uimm16_64 : Operand<i64> { + let PrintMethod = "printUnsignedImm"; +} + +// Signed Operand +def simm10_64 : Operand<i64>; + +// Transformation Function - get Imm - 32. +def Subtract32 : SDNodeXForm<imm, [{ + return getImm(N, (unsigned)N->getZExtValue() - 32); +}]>; + +// shamt must fit in 6 bits. +def immZExt6 : ImmLeaf<i32, [{return Imm == (Imm & 0x3f);}]>; + +// Node immediate fits as 10-bit sign extended on target immediate. +// e.g. seqi, snei +def immSExt10_64 : PatLeaf<(i64 imm), + [{ return isInt<10>(N->getSExtValue()); }]>; + +def immZExt16_64 : PatLeaf<(i64 imm), + [{ return isInt<16>(N->getZExtValue()); }]>; + +def immZExt5_64 : ImmLeaf<i64, [{ return Imm == (Imm & 0x1f); }]>; + +// Transformation function: get log2 of low 32 bits of immediate +def Log2LO : SDNodeXForm<imm, [{ + return getImm(N, Log2_64((unsigned) N->getZExtValue())); +}]>; + +// Transformation function: get log2 of high 32 bits of immediate +def Log2HI : SDNodeXForm<imm, [{ + return getImm(N, Log2_64((unsigned) (N->getZExtValue() >> 32))); +}]>; + +// Predicate: True if immediate is a power of 2 and fits 32 bits +def PowerOf2LO : PatLeaf<(imm), [{ + if (N->getValueType(0) == MVT::i64) { + uint64_t Imm = N->getZExtValue(); + return isPowerOf2_64(Imm) && (Imm & 0xffffffff) == Imm; + } + else + return false; +}]>; + +// Predicate: True if immediate is a power of 2 and exceeds 32 bits +def PowerOf2HI : PatLeaf<(imm), [{ + if (N->getValueType(0) == MVT::i64) { + uint64_t Imm = N->getZExtValue(); + return isPowerOf2_64(Imm) && (Imm & 0xffffffff00000000) == Imm; + } + else + return false; +}]>; + +//===----------------------------------------------------------------------===// +// Instructions specific format +//===----------------------------------------------------------------------===// +let usesCustomInserter = 1 in { + def ATOMIC_LOAD_ADD_I64 : Atomic2Ops<atomic_load_add_64, GPR64>; + def ATOMIC_LOAD_SUB_I64 : Atomic2Ops<atomic_load_sub_64, GPR64>; + def ATOMIC_LOAD_AND_I64 : Atomic2Ops<atomic_load_and_64, GPR64>; + def ATOMIC_LOAD_OR_I64 : Atomic2Ops<atomic_load_or_64, GPR64>; + def ATOMIC_LOAD_XOR_I64 : Atomic2Ops<atomic_load_xor_64, GPR64>; + def ATOMIC_LOAD_NAND_I64 : Atomic2Ops<atomic_load_nand_64, GPR64>; + def ATOMIC_SWAP_I64 : Atomic2Ops<atomic_swap_64, GPR64>; + def ATOMIC_CMP_SWAP_I64 : AtomicCmpSwap<atomic_cmp_swap_64, GPR64>; +} + +/// Pseudo instructions for loading and storing accumulator registers. +let isPseudo = 1, isCodeGenOnly = 1 in { + def LOAD_ACC128 : Load<"", ACC128>; + def STORE_ACC128 : Store<"", ACC128>; +} + +//===----------------------------------------------------------------------===// +// Instruction definition +//===----------------------------------------------------------------------===// +let DecoderNamespace = "Mips64" in { +/// Arithmetic Instructions (ALU Immediate) +def DADDi : ArithLogicI<"daddi", simm16_64, GPR64Opnd>, ADDI_FM<0x18>, + ISA_MIPS3_NOT_32R6_64R6; +def DADDiu : ArithLogicI<"daddiu", simm16_64, GPR64Opnd, II_DADDIU, + immSExt16, add>, + ADDI_FM<0x19>, IsAsCheapAsAMove, ISA_MIPS3; + +let isCodeGenOnly = 1 in { +def SLTi64 : SetCC_I<"slti", setlt, simm16_64, immSExt16, GPR64Opnd>, + SLTI_FM<0xa>; +def SLTiu64 : SetCC_I<"sltiu", setult, simm16_64, immSExt16, GPR64Opnd>, + SLTI_FM<0xb>; +def ANDi64 : ArithLogicI<"andi", uimm16_64, GPR64Opnd, II_AND, immZExt16, and>, + ADDI_FM<0xc>; +def ORi64 : ArithLogicI<"ori", uimm16_64, GPR64Opnd, II_OR, immZExt16, or>, + ADDI_FM<0xd>; +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, 1, II_DADD>, ADD_FM<0, 0x2c>, + ISA_MIPS3; +def DADDu : ArithLogicR<"daddu", GPR64Opnd, 1, II_DADDU, add>, ADD_FM<0, 0x2d>, + ISA_MIPS3; +def DSUBu : ArithLogicR<"dsubu", GPR64Opnd, 0, II_DSUBU, sub>, ADD_FM<0, 0x2f>, + ISA_MIPS3; +def DSUB : ArithLogicR<"dsub", GPR64Opnd, 0, II_DSUB>, ADD_FM<0, 0x2e>, + ISA_MIPS3; + +let isCodeGenOnly = 1 in { +def SLT64 : SetCC_R<"slt", setlt, GPR64Opnd>, ADD_FM<0, 0x2a>; +def SLTu64 : SetCC_R<"sltu", setult, GPR64Opnd>, ADD_FM<0, 0x2b>; +def AND64 : ArithLogicR<"and", GPR64Opnd, 1, 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, II_DSLL, shl, immZExt6>, + SRA_FM<0x38, 0>, ISA_MIPS3; +def DSRL : shift_rotate_imm<"dsrl", uimm6, GPR64Opnd, II_DSRL, srl, immZExt6>, + SRA_FM<0x3a, 0>, ISA_MIPS3; +def DSRA : shift_rotate_imm<"dsra", uimm6, GPR64Opnd, II_DSRA, sra, immZExt6>, + SRA_FM<0x3b, 0>, ISA_MIPS3; +def DSLLV : shift_rotate_reg<"dsllv", GPR64Opnd, II_DSLLV, shl>, + SRLV_FM<0x14, 0>, ISA_MIPS3; +def DSRLV : shift_rotate_reg<"dsrlv", GPR64Opnd, II_DSRLV, srl>, + SRLV_FM<0x16, 0>, ISA_MIPS3; +def DSRAV : shift_rotate_reg<"dsrav", GPR64Opnd, II_DSRAV, sra>, + SRLV_FM<0x17, 0>, ISA_MIPS3; +def DSLL32 : shift_rotate_imm<"dsll32", uimm5, GPR64Opnd, II_DSLL32>, + SRA_FM<0x3c, 0>, ISA_MIPS3; +def DSRL32 : shift_rotate_imm<"dsrl32", uimm5, GPR64Opnd, II_DSRL32>, + SRA_FM<0x3e, 0>, ISA_MIPS3; +def DSRA32 : shift_rotate_imm<"dsra32", uimm5, GPR64Opnd, II_DSRA32>, + SRA_FM<0x3f, 0>, ISA_MIPS3; + +// Rotate Instructions +def DROTR : shift_rotate_imm<"drotr", uimm6, GPR64Opnd, II_DROTR, rotr, + immZExt6>, + SRA_FM<0x3a, 1>, ISA_MIPS64R2; +def DROTRV : shift_rotate_reg<"drotrv", GPR64Opnd, II_DROTRV, rotr>, + SRLV_FM<0x16, 1>, ISA_MIPS64R2; +def DROTR32 : shift_rotate_imm<"drotr32", uimm5, GPR64Opnd, II_DROTR32>, + SRA_FM<0x3e, 1>, ISA_MIPS64R2; + +/// Load and Store Instructions +/// aligned +let isCodeGenOnly = 1 in { +def LB64 : Load<"lb", GPR64Opnd, sextloadi8, 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, II_LWU>, LW_FM<0x27>, ISA_MIPS3; +def LD : Load<"ld", GPR64Opnd, load, II_LD>, LW_FM<0x37>, ISA_MIPS3; +def SD : Store<"sd", GPR64Opnd, store, II_SD>, LW_FM<0x3f>, ISA_MIPS3; + +/// load/store left/right +let isCodeGenOnly = 1 in { +def LWL64 : LoadLeftRight<"lwl", MipsLWL, GPR64Opnd, 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, II_LDL>, LW_FM<0x1a>, + ISA_MIPS3_NOT_32R6_64R6; +def LDR : LoadLeftRight<"ldr", MipsLDR, GPR64Opnd, II_LDR>, LW_FM<0x1b>, + ISA_MIPS3_NOT_32R6_64R6; +def SDL : StoreLeftRight<"sdl", MipsSDL, GPR64Opnd, II_SDL>, LW_FM<0x2c>, + ISA_MIPS3_NOT_32R6_64R6; +def SDR : StoreLeftRight<"sdr", MipsSDR, GPR64Opnd, II_SDR>, LW_FM<0x2d>, + ISA_MIPS3_NOT_32R6_64R6; + +/// Load-linked, Store-conditional +def LLD : LLBase<"lld", GPR64Opnd>, LW_FM<0x34>, ISA_MIPS3_NOT_32R6_64R6; +def SCD : SCBase<"scd", GPR64Opnd>, LW_FM<0x3c>, ISA_MIPS3_NOT_32R6_64R6; + +/// Jump and Branch Instructions +let isCodeGenOnly = 1 in { + def JR64 : IndirectBranch<"jr", GPR64Opnd>, MTLO_FM<8>; + def BEQ64 : CBranch<"beq", brtarget, seteq, GPR64Opnd>, BEQ_FM<4>; + def BNE64 : CBranch<"bne", brtarget, setne, GPR64Opnd>, BEQ_FM<5>; + def BGEZ64 : CBranchZero<"bgez", brtarget, setge, GPR64Opnd>, BGEZ_FM<1, 1>; + def BGTZ64 : CBranchZero<"bgtz", brtarget, setgt, GPR64Opnd>, BGEZ_FM<7, 0>; + def BLEZ64 : CBranchZero<"blez", brtarget, setle, GPR64Opnd>, BGEZ_FM<6, 0>; + def BLTZ64 : CBranchZero<"bltz", brtarget, setlt, GPR64Opnd>, BGEZ_FM<1, 0>; + def JALR64 : JumpLinkReg<"jalr", GPR64Opnd>, JALR_FM; + def JALR64Pseudo : JumpLinkRegPseudo<GPR64Opnd, JALR, RA, GPR32Opnd>; + def TAILCALL64_R : TailCallReg<GPR64Opnd, JR, GPR32Opnd>; +} + +def PseudoReturn64 : PseudoReturnBase<GPR64Opnd>; +def PseudoIndirectBranch64 : PseudoIndirectBranchBase<GPR64Opnd>; + +/// Multiply and Divide Instructions. +def DMULT : Mult<"dmult", II_DMULT, GPR64Opnd, [HI0_64, LO0_64]>, + MULT_FM<0, 0x1c>, ISA_MIPS3_NOT_32R6_64R6; +def DMULTu : Mult<"dmultu", II_DMULTU, GPR64Opnd, [HI0_64, LO0_64]>, + MULT_FM<0, 0x1d>, ISA_MIPS3_NOT_32R6_64R6; +def PseudoDMULT : MultDivPseudo<DMULT, ACC128, GPR64Opnd, MipsMult, + II_DMULT>, ISA_MIPS3_NOT_32R6_64R6; +def PseudoDMULTu : MultDivPseudo<DMULTu, ACC128, GPR64Opnd, MipsMultu, + II_DMULTU>, ISA_MIPS3_NOT_32R6_64R6; +def DSDIV : Div<"ddiv", II_DDIV, GPR64Opnd, [HI0_64, LO0_64]>, + MULT_FM<0, 0x1e>, ISA_MIPS3_NOT_32R6_64R6; +def DUDIV : Div<"ddivu", II_DDIVU, GPR64Opnd, [HI0_64, LO0_64]>, + MULT_FM<0, 0x1f>, ISA_MIPS3_NOT_32R6_64R6; +def PseudoDSDIV : MultDivPseudo<DSDIV, ACC128, GPR64Opnd, MipsDivRem, + II_DDIV, 0, 1, 1>, ISA_MIPS3_NOT_32R6_64R6; +def PseudoDUDIV : MultDivPseudo<DUDIV, ACC128, GPR64Opnd, MipsDivRemU, + II_DDIVU, 0, 1, 1>, ISA_MIPS3_NOT_32R6_64R6; + +let isCodeGenOnly = 1 in { +def MTHI64 : MoveToLOHI<"mthi", GPR64Opnd, [HI0_64]>, MTLO_FM<0x11>, + ISA_MIPS3_NOT_32R6_64R6; +def MTLO64 : MoveToLOHI<"mtlo", GPR64Opnd, [LO0_64]>, MTLO_FM<0x13>, + ISA_MIPS3_NOT_32R6_64R6; +def MFHI64 : MoveFromLOHI<"mfhi", GPR64Opnd, AC0_64>, MFLO_FM<0x10>, + ISA_MIPS3_NOT_32R6_64R6; +def MFLO64 : MoveFromLOHI<"mflo", GPR64Opnd, AC0_64>, MFLO_FM<0x12>, + ISA_MIPS3_NOT_32R6_64R6; +def PseudoMFHI64 : PseudoMFLOHI<GPR64, ACC128, MipsMFHI>, + ISA_MIPS3_NOT_32R6_64R6; +def PseudoMFLO64 : PseudoMFLOHI<GPR64, ACC128, MipsMFLO>, + ISA_MIPS3_NOT_32R6_64R6; +def PseudoMTLOHI64 : PseudoMTLOHI<ACC128, GPR64>, ISA_MIPS3_NOT_32R6_64R6; + +/// Sign Ext In Register Instructions. +def SEB64 : SignExtInReg<"seb", i8, GPR64Opnd, II_SEB>, SEB_FM<0x10, 0x20>, + ISA_MIPS32R2; +def SEH64 : SignExtInReg<"seh", i16, GPR64Opnd, II_SEH>, SEB_FM<0x18, 0x20>, + ISA_MIPS32R2; +} + +/// Count Leading +def DCLZ : CountLeading0<"dclz", GPR64Opnd>, CLO_FM<0x24>, ISA_MIPS64_NOT_64R6; +def DCLO : CountLeading1<"dclo", GPR64Opnd>, CLO_FM<0x25>, ISA_MIPS64_NOT_64R6; + +/// Double Word Swap Bytes/HalfWords +def DSBH : SubwordSwap<"dsbh", GPR64Opnd>, SEB_FM<2, 0x24>, ISA_MIPS64R2; +def DSHD : SubwordSwap<"dshd", GPR64Opnd>, SEB_FM<5, 0x24>, ISA_MIPS64R2; + +def LEA_ADDiu64 : EffectiveAddress<"daddiu", GPR64Opnd>, LW_FM<0x19>; + +let isCodeGenOnly = 1 in +def RDHWR64 : ReadHardware<GPR64Opnd, HWRegsOpnd>, RDHWR_FM; + +let AdditionalPredicates = [NotInMicroMips] in { + // TODO: Add 'pos + size' constraint check to dext* instructions + // DEXT: 0 < pos + size <= 63 + // DEXTM, DEXTU: 32 < pos + size <= 64 + def DEXT : ExtBase<"dext", GPR64Opnd, uimm5, uimm5_plus1, MipsExt>, + EXT_FM<3>; + def DEXTM : ExtBase<"dextm", GPR64Opnd, uimm5, uimm5_plus33, MipsExt>, + EXT_FM<1>; + def DEXTU : ExtBase<"dextu", GPR64Opnd, uimm5_plus32, uimm5_plus1, + MipsExt>, EXT_FM<2>; +} + +def DINS : InsBase<"dins", GPR64Opnd, uimm6, MipsIns>, EXT_FM<7>; +def DINSU : InsBase<"dinsu", GPR64Opnd, uimm5_plus32>, EXT_FM<6>; +def DINSM : InsBase<"dinsm", GPR64Opnd, uimm5>, EXT_FM<5>; + +let isCodeGenOnly = 1, rs = 0, shamt = 0 in { + def DSLL64_32 : FR<0x00, 0x3c, (outs GPR64:$rd), (ins GPR32:$rt), + "dsll\t$rd, $rt, 32", [], II_DSLL>; + def SLL64_32 : FR<0x0, 0x00, (outs GPR64:$rd), (ins GPR32:$rt), + "sll\t$rd, $rt, 0", [], II_SLL>; + def SLL64_64 : FR<0x0, 0x00, (outs GPR64:$rd), (ins GPR64:$rt), + "sll\t$rd, $rt, 0", [], II_SLL>; +} + +// We need the following pseudo instruction to avoid offset calculation for +// long branches. See the comment in file MipsLongBranch.cpp for detailed +// explanation. + +// Expands to: daddiu $dst, $src, %PART($tgt - $baltgt) +// where %PART may be %hi or %lo, depending on the relocation kind +// that $tgt is annotated with. +def LONG_BRANCH_DADDiu : PseudoSE<(outs GPR64Opnd:$dst), + (ins GPR64Opnd:$src, brtarget:$tgt, brtarget:$baltgt), []>; + +// Cavium Octeon cnMIPS instructions +let DecoderNamespace = "CnMips", + EncodingPredicates = []<Predicate>, // FIXME: The lack of HasStdEnc is probably a bug + AdditionalPredicates = [HasCnMips] in { + +class Count1s<string opstr, RegisterOperand RO>: + InstSE<(outs RO:$rd), (ins RO:$rs), !strconcat(opstr, "\t$rd, $rs"), + [(set RO:$rd, (ctpop RO:$rs))], II_POP, FrmR, opstr> { + let TwoOperandAliasConstraint = "$rd = $rs"; +} + +class ExtsCins<string opstr, SDPatternOperator Op = null_frag>: + InstSE<(outs GPR64Opnd:$rt), (ins GPR64Opnd:$rs, uimm5:$pos, uimm5:$lenm1), + !strconcat(opstr, " $rt, $rs, $pos, $lenm1"), + [(set GPR64Opnd:$rt, (Op GPR64Opnd:$rs, imm:$pos, imm:$lenm1))], + NoItinerary, FrmR, opstr> { + let TwoOperandAliasConstraint = "$rt = $rs"; +} + +class SetCC64_R<string opstr, PatFrag cond_op> : + InstSE<(outs GPR64Opnd:$rd), (ins GPR64Opnd:$rs, GPR64Opnd:$rt), + !strconcat(opstr, "\t$rd, $rs, $rt"), + [(set GPR64Opnd:$rd, (zext (cond_op GPR64Opnd:$rs, + GPR64Opnd:$rt)))], + II_SEQ_SNE, FrmR, opstr> { + let TwoOperandAliasConstraint = "$rd = $rs"; +} + +class SetCC64_I<string opstr, PatFrag cond_op>: + InstSE<(outs GPR64Opnd:$rt), (ins GPR64Opnd:$rs, simm10_64:$imm10), + !strconcat(opstr, "\t$rt, $rs, $imm10"), + [(set GPR64Opnd:$rt, (zext (cond_op GPR64Opnd:$rs, + immSExt10_64:$imm10)))], + II_SEQI_SNEI, FrmI, opstr> { + let TwoOperandAliasConstraint = "$rt = $rs"; +} + +class CBranchBitNum<string opstr, DAGOperand opnd, PatFrag cond_op, + RegisterOperand RO, Operand ImmOp, bits<64> shift = 1> : + InstSE<(outs), (ins RO:$rs, ImmOp:$p, opnd:$offset), + !strconcat(opstr, "\t$rs, $p, $offset"), + [(brcond (i32 (cond_op (and RO:$rs, (shl shift, immZExt5_64:$p)), 0)), + bb:$offset)], II_BBIT, FrmI, opstr> { + let isBranch = 1; + let isTerminator = 1; + let hasDelaySlot = 1; + let Defs = [AT]; +} + +class MFC2OP<string asmstr, RegisterOperand RO> : + InstSE<(outs RO:$rt, uimm16:$imm16), (ins), + !strconcat(asmstr, "\t$rt, $imm16"), [], NoItinerary, FrmFR>; + +// 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>; + +// Branch on Bit Clear /+32 +def BBIT0 : CBranchBitNum<"bbit0", brtarget, seteq, GPR64Opnd, + uimm5_64_report_uimm6>, BBIT_FM<0x32>; +def BBIT032: CBranchBitNum<"bbit032", brtarget, seteq, GPR64Opnd, uimm5_64, + 0x100000000>, + BBIT_FM<0x36>; + +// Branch on Bit Set /+32 +def BBIT1 : CBranchBitNum<"bbit1", brtarget, setne, GPR64Opnd, + uimm5_64_report_uimm6>, BBIT_FM<0x3a>; +def BBIT132: CBranchBitNum<"bbit132", brtarget, setne, GPR64Opnd, uimm5_64, + 0x100000000>, BBIT_FM<0x3e>; + +// Multiply Doubleword to GPR +let Defs = [HI0, LO0, P0, P1, P2] in +def DMUL : ArithLogicR<"dmul", GPR64Opnd, 1, II_DMUL, mul>, + ADD_FM<0x1c, 0x03>; + +// Extract a signed bit field /+32 +def EXTS : ExtsCins<"exts">, EXTS_FM<0x3a>; +def EXTS32: ExtsCins<"exts32">, EXTS_FM<0x3b>; + +// Clear and insert a bit field /+32 +def CINS : ExtsCins<"cins">, EXTS_FM<0x32>; +def CINS32: ExtsCins<"cins32">, EXTS_FM<0x33>; + +// Move to multiplier/product register +def MTM0 : MoveToLOHI<"mtm0", GPR64Opnd, [MPL0, P0, P1, P2]>, MTMR_FM<0x08>; +def MTM1 : MoveToLOHI<"mtm1", GPR64Opnd, [MPL1, P0, P1, P2]>, MTMR_FM<0x0c>; +def MTM2 : MoveToLOHI<"mtm2", GPR64Opnd, [MPL2, P0, P1, P2]>, MTMR_FM<0x0d>; +def MTP0 : MoveToLOHI<"mtp0", GPR64Opnd, [P0]>, MTMR_FM<0x09>; +def MTP1 : MoveToLOHI<"mtp1", GPR64Opnd, [P1]>, MTMR_FM<0x0a>; +def MTP2 : MoveToLOHI<"mtp2", GPR64Opnd, [P2]>, MTMR_FM<0x0b>; + +// Count Ones in a Word/Doubleword +def POP : Count1s<"pop", GPR32Opnd>, POP_FM<0x2c>; +def DPOP : Count1s<"dpop", GPR64Opnd>, POP_FM<0x2d>; + +// Set on equal/not equal +def SEQ : SetCC64_R<"seq", seteq>, SEQ_FM<0x2a>; +def SEQi : SetCC64_I<"seqi", seteq>, SEQI_FM<0x2e>; +def SNE : SetCC64_R<"sne", setne>, SEQ_FM<0x2b>; +def SNEi : SetCC64_I<"snei", setne>, SEQI_FM<0x2f>; + +// 192-bit x 64-bit Unsigned Multiply and Add +let Defs = [P0, P1, P2] in +def V3MULU: ArithLogicR<"v3mulu", GPR64Opnd, 0, II_DMUL>, + ADD_FM<0x1c, 0x11>; + +// 64-bit Unsigned Multiply and Add Move +let Defs = [MPL0, P0, P1, P2] in +def VMM0 : ArithLogicR<"vmm0", GPR64Opnd, 0, II_DMUL>, + ADD_FM<0x1c, 0x10>; + +// 64-bit Unsigned Multiply and Add +let Defs = [MPL1, MPL2, P0, P1, P2] in +def VMULU : ArithLogicR<"vmulu", GPR64Opnd, 0, II_DMUL>, + ADD_FM<0x1c, 0x0f>; + +// Move between CPU and coprocessor registers +def DMFC2_OCTEON : MFC2OP<"dmfc2", GPR64Opnd>, MFC2OP_FM<0x12, 1>; +def DMTC2_OCTEON : MFC2OP<"dmtc2", GPR64Opnd>, MFC2OP_FM<0x12, 5>; +} + +} + +/// Move between CPU and coprocessor registers +let DecoderNamespace = "Mips64", Predicates = [HasMips64] in { +def DMFC0 : MFC3OP<"dmfc0", GPR64Opnd, COP0Opnd>, MFC3OP_FM<0x10, 1>, ISA_MIPS3; +def DMTC0 : MTC3OP<"dmtc0", COP0Opnd, GPR64Opnd>, MFC3OP_FM<0x10, 5>, ISA_MIPS3; +def DMFC2 : MFC3OP<"dmfc2", GPR64Opnd, COP2Opnd>, MFC3OP_FM<0x12, 1>, ISA_MIPS3; +def DMTC2 : MTC3OP<"dmtc2", COP2Opnd, GPR64Opnd>, MFC3OP_FM<0x12, 5>, ISA_MIPS3; +} + +//===----------------------------------------------------------------------===// +// Arbitrary patterns that map to one or more instructions +//===----------------------------------------------------------------------===// + +// extended loads +def : MipsPat<(i64 (extloadi1 addr:$src)), (LB64 addr:$src)>; +def : MipsPat<(i64 (extloadi8 addr:$src)), (LB64 addr:$src)>; +def : MipsPat<(i64 (extloadi16 addr:$src)), (LH64 addr:$src)>; +def : MipsPat<(i64 (extloadi32 addr:$src)), (LW64 addr:$src)>; + +// hi/lo relocs +def : MipsPat<(MipsHi tglobaladdr:$in), (LUi64 tglobaladdr:$in)>; +def : MipsPat<(MipsHi tblockaddress:$in), (LUi64 tblockaddress:$in)>; +def : MipsPat<(MipsHi tjumptable:$in), (LUi64 tjumptable:$in)>; +def : MipsPat<(MipsHi tconstpool:$in), (LUi64 tconstpool:$in)>; +def : MipsPat<(MipsHi tglobaltlsaddr:$in), (LUi64 tglobaltlsaddr:$in)>; +def : MipsPat<(MipsHi texternalsym:$in), (LUi64 texternalsym:$in)>; + +def : MipsPat<(MipsLo tglobaladdr:$in), (DADDiu ZERO_64, tglobaladdr:$in)>; +def : MipsPat<(MipsLo tblockaddress:$in), (DADDiu ZERO_64, tblockaddress:$in)>; +def : MipsPat<(MipsLo tjumptable:$in), (DADDiu ZERO_64, tjumptable:$in)>; +def : MipsPat<(MipsLo tconstpool:$in), (DADDiu ZERO_64, tconstpool:$in)>; +def : MipsPat<(MipsLo tglobaltlsaddr:$in), + (DADDiu ZERO_64, tglobaltlsaddr:$in)>; +def : MipsPat<(MipsLo texternalsym:$in), (DADDiu ZERO_64, texternalsym:$in)>; + +def : MipsPat<(add GPR64:$hi, (MipsLo tglobaladdr:$lo)), + (DADDiu GPR64:$hi, tglobaladdr:$lo)>; +def : MipsPat<(add GPR64:$hi, (MipsLo tblockaddress:$lo)), + (DADDiu GPR64:$hi, tblockaddress:$lo)>; +def : MipsPat<(add GPR64:$hi, (MipsLo tjumptable:$lo)), + (DADDiu GPR64:$hi, tjumptable:$lo)>; +def : MipsPat<(add GPR64:$hi, (MipsLo tconstpool:$lo)), + (DADDiu GPR64:$hi, tconstpool:$lo)>; +def : MipsPat<(add GPR64:$hi, (MipsLo tglobaltlsaddr:$lo)), + (DADDiu GPR64:$hi, tglobaltlsaddr:$lo)>; + +def : WrapperPat<tglobaladdr, DADDiu, GPR64>; +def : WrapperPat<tconstpool, DADDiu, GPR64>; +def : WrapperPat<texternalsym, DADDiu, GPR64>; +def : WrapperPat<tblockaddress, DADDiu, GPR64>; +def : WrapperPat<tjumptable, DADDiu, GPR64>; +def : WrapperPat<tglobaltlsaddr, DADDiu, GPR64>; + +defm : BrcondPats<GPR64, BEQ64, BNE64, SLT64, SLTu64, SLTi64, SLTiu64, + ZERO_64>; + +def : MipsPat<(brcond (i32 (setlt i64:$lhs, 1)), bb:$dst), + (BLEZ64 i64:$lhs, bb:$dst)>; +def : MipsPat<(brcond (i32 (setgt i64:$lhs, -1)), bb:$dst), + (BGEZ64 i64:$lhs, bb:$dst)>; + +// setcc patterns +defm : SeteqPats<GPR64, SLTiu64, XOR64, SLTu64, ZERO_64>; +defm : SetlePats<GPR64, SLT64, SLTu64>; +defm : SetgtPats<GPR64, SLT64, SLTu64>; +defm : SetgePats<GPR64, SLT64, SLTu64>; +defm : SetgeImmPats<GPR64, SLTi64, SLTiu64>; + +// truncate +def : MipsPat<(trunc (assertsext GPR64:$src)), + (EXTRACT_SUBREG GPR64:$src, sub_32)>; +def : MipsPat<(trunc (assertzext GPR64:$src)), + (EXTRACT_SUBREG GPR64:$src, sub_32)>; +def : MipsPat<(i32 (trunc GPR64:$src)), + (SLL (EXTRACT_SUBREG GPR64:$src, sub_32), 0)>; + +// variable shift instructions patterns +def : MipsPat<(shl GPR64:$rt, (i32 (trunc GPR64:$rs))), + (DSLLV GPR64:$rt, (EXTRACT_SUBREG GPR64:$rs, sub_32))>; +def : MipsPat<(srl GPR64:$rt, (i32 (trunc GPR64:$rs))), + (DSRLV GPR64:$rt, (EXTRACT_SUBREG GPR64:$rs, sub_32))>; +def : MipsPat<(sra GPR64:$rt, (i32 (trunc GPR64:$rs))), + (DSRAV GPR64:$rt, (EXTRACT_SUBREG GPR64:$rs, sub_32))>; +def : MipsPat<(rotr GPR64:$rt, (i32 (trunc GPR64:$rs))), + (DROTRV GPR64:$rt, (EXTRACT_SUBREG GPR64:$rs, sub_32))>; + +// 32-to-64-bit extension +def : MipsPat<(i64 (anyext GPR32:$src)), (SLL64_32 GPR32:$src)>; +def : MipsPat<(i64 (zext GPR32:$src)), (DSRL (DSLL64_32 GPR32:$src), 32)>; +def : MipsPat<(i64 (sext GPR32:$src)), (SLL64_32 GPR32:$src)>; + +// Sign extend in register +def : MipsPat<(i64 (sext_inreg GPR64:$src, i32)), + (SLL64_64 GPR64:$src)>; + +// bswap MipsPattern +def : MipsPat<(bswap GPR64:$rt), (DSHD (DSBH GPR64:$rt))>; + +// Carry pattern +def : MipsPat<(subc GPR64:$lhs, GPR64:$rhs), + (DSUBu GPR64:$lhs, GPR64:$rhs)>; +let AdditionalPredicates = [NotDSP] in { + def : MipsPat<(addc GPR64:$lhs, GPR64:$rhs), + (DADDu GPR64:$lhs, GPR64:$rhs)>; + def : MipsPat<(addc GPR64:$lhs, immSExt16:$imm), + (DADDiu GPR64:$lhs, imm:$imm)>; +} + +// Octeon bbit0/bbit1 MipsPattern +let Predicates = [HasMips64, HasCnMips] in { +def : MipsPat<(brcond (i32 (seteq (and i64:$lhs, PowerOf2LO:$mask), 0)), bb:$dst), + (BBIT0 i64:$lhs, (Log2LO PowerOf2LO:$mask), bb:$dst)>; +def : MipsPat<(brcond (i32 (seteq (and i64:$lhs, PowerOf2HI:$mask), 0)), bb:$dst), + (BBIT032 i64:$lhs, (Log2HI PowerOf2HI:$mask), bb:$dst)>; +def : MipsPat<(brcond (i32 (setne (and i64:$lhs, PowerOf2LO:$mask), 0)), bb:$dst), + (BBIT1 i64:$lhs, (Log2LO PowerOf2LO:$mask), bb:$dst)>; +def : MipsPat<(brcond (i32 (setne (and i64:$lhs, PowerOf2HI:$mask), 0)), bb:$dst), + (BBIT132 i64:$lhs, (Log2HI PowerOf2HI:$mask), bb:$dst)>; +} + +// Atomic load patterns. +def : MipsPat<(atomic_load_8 addr:$a), (LB64 addr:$a)>; +def : MipsPat<(atomic_load_16 addr:$a), (LH64 addr:$a)>; +def : MipsPat<(atomic_load_32 addr:$a), (LW64 addr:$a)>; +def : MipsPat<(atomic_load_64 addr:$a), (LD addr:$a)>; + +// Atomic store patterns. +def : MipsPat<(atomic_store_8 addr:$a, GPR64:$v), (SB64 GPR64:$v, addr:$a)>; +def : MipsPat<(atomic_store_16 addr:$a, GPR64:$v), (SH64 GPR64:$v, addr:$a)>; +def : MipsPat<(atomic_store_32 addr:$a, GPR64:$v), (SW64 GPR64:$v, addr:$a)>; +def : MipsPat<(atomic_store_64 addr:$a, GPR64:$v), (SD GPR64:$v, addr:$a)>; + +//===----------------------------------------------------------------------===// +// Instruction aliases +//===----------------------------------------------------------------------===// +def : MipsInstAlias<"move $dst, $src", + (OR64 GPR64Opnd:$dst, GPR64Opnd:$src, ZERO_64), 1>, + GPR_64; +def : MipsInstAlias<"move $dst, $src", + (DADDu GPR64Opnd:$dst, GPR64Opnd:$src, ZERO_64), 1>, + GPR_64; +def : MipsInstAlias<"daddu $rs, $rt, $imm", + (DADDiu GPR64Opnd:$rs, GPR64Opnd:$rt, simm16_64:$imm), + 0>, ISA_MIPS3; +def : MipsInstAlias<"dadd $rs, $rt, $imm", + (DADDi GPR64Opnd:$rs, GPR64Opnd:$rt, simm16_64:$imm), + 0>, ISA_MIPS3_NOT_32R6_64R6; +def : MipsInstAlias<"daddu $rs, $imm", + (DADDiu GPR64Opnd:$rs, GPR64Opnd:$rs, simm16_64:$imm), + 0>, ISA_MIPS3; +def : MipsInstAlias<"dadd $rs, $imm", + (DADDi GPR64Opnd:$rs, GPR64Opnd:$rs, simm16_64:$imm), + 0>, ISA_MIPS3_NOT_32R6_64R6; +def : MipsInstAlias<"dsll $rd, $rt, $rs", + (DSLLV GPR64Opnd:$rd, GPR64Opnd:$rt, GPR32Opnd:$rs), 0>, + ISA_MIPS3; +def : MipsInstAlias<"dneg $rt, $rs", + (DSUB GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rs), 1>, + ISA_MIPS3; +def : MipsInstAlias<"dneg $rt", + (DSUB GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rt), 0>, + ISA_MIPS3; +def : MipsInstAlias<"dnegu $rt, $rs", + (DSUBu GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rs), 1>, + ISA_MIPS3; +def : MipsInstAlias<"dsubu $rt, $rs, $imm", + (DADDiu GPR64Opnd:$rt, GPR64Opnd:$rs, + InvertedImOperand64:$imm), 0>, ISA_MIPS3; +def : MipsInstAlias<"dsubi $rs, $rt, $imm", + (DADDi GPR64Opnd:$rs, GPR64Opnd:$rt, + InvertedImOperand64:$imm), + 0>, ISA_MIPS3_NOT_32R6_64R6; +def : MipsInstAlias<"dsubi $rs, $imm", + (DADDi GPR64Opnd:$rs, GPR64Opnd:$rs, + InvertedImOperand64:$imm), + 0>, ISA_MIPS3_NOT_32R6_64R6; +def : MipsInstAlias<"dsub $rs, $rt, $imm", + (DADDi GPR64Opnd:$rs, GPR64Opnd:$rt, + InvertedImOperand64:$imm), + 0>, ISA_MIPS3_NOT_32R6_64R6; +def : MipsInstAlias<"dsub $rs, $imm", + (DADDi GPR64Opnd:$rs, GPR64Opnd:$rs, + InvertedImOperand64:$imm), + 0>, ISA_MIPS3_NOT_32R6_64R6; +def : MipsInstAlias<"dsubu $rs, $imm", + (DADDiu GPR64Opnd:$rs, GPR64Opnd:$rs, + InvertedImOperand64:$imm), + 0>, ISA_MIPS3; +def : MipsInstAlias<"dsra $rd, $rt, $rs", + (DSRAV GPR64Opnd:$rd, GPR64Opnd:$rt, GPR32Opnd:$rs), 0>, + ISA_MIPS3; +def : MipsInstAlias<"dsrl $rd, $rt, $rs", + (DSRLV GPR64Opnd:$rd, GPR64Opnd:$rt, GPR32Opnd:$rs), 0>, + ISA_MIPS3; + +// Two operand (implicit 0 selector) versions: +def : MipsInstAlias<"dmfc0 $rt, $rd", (DMFC0 GPR64Opnd:$rt, COP0Opnd:$rd, 0), 0>; +def : MipsInstAlias<"dmtc0 $rt, $rd", (DMTC0 COP0Opnd:$rd, GPR64Opnd:$rt, 0), 0>; +def : MipsInstAlias<"dmfc2 $rt, $rd", (DMFC2 GPR64Opnd:$rt, COP2Opnd:$rd, 0), 0>; +def : MipsInstAlias<"dmtc2 $rt, $rd", (DMTC2 COP2Opnd:$rd, GPR64Opnd:$rt, 0), 0>; + +let Predicates = [HasMips64, HasCnMips] in { +def : MipsInstAlias<"synciobdma", (SYNC 0x2), 0>; +def : MipsInstAlias<"syncs", (SYNC 0x6), 0>; +def : MipsInstAlias<"syncw", (SYNC 0x4), 0>; +def : MipsInstAlias<"syncws", (SYNC 0x5), 0>; +} + +// cnMIPS Aliases. + +// bbit* with $p 32-63 converted to bbit*32 with $p 0-31 +def : MipsInstAlias<"bbit0 $rs, $p, $offset", + (BBIT032 GPR64Opnd:$rs, uimm5_plus32_normalize_64:$p, + brtarget:$offset), 0>, + ASE_CNMIPS; +def : MipsInstAlias<"bbit1 $rs, $p, $offset", + (BBIT132 GPR64Opnd:$rs, uimm5_plus32_normalize_64:$p, + brtarget:$offset), 0>, + ASE_CNMIPS; + +// exts with $pos 32-63 in converted to exts32 with $pos 0-31 +def : MipsInstAlias<"exts $rt, $rs, $pos, $lenm1", + (EXTS32 GPR64Opnd:$rt, GPR64Opnd:$rs, + uimm5_plus32_normalize:$pos, uimm5:$lenm1), 0>, + ASE_CNMIPS; +def : MipsInstAlias<"exts $rt, $pos, $lenm1", + (EXTS32 GPR64Opnd:$rt, GPR64Opnd:$rt, + uimm5_plus32_normalize:$pos, uimm5:$lenm1), 0>, + ASE_CNMIPS; + +// cins with $pos 32-63 in converted to cins32 with $pos 0-31 +def : MipsInstAlias<"cins $rt, $rs, $pos, $lenm1", + (CINS32 GPR64Opnd:$rt, GPR64Opnd:$rs, + uimm5_plus32_normalize:$pos, uimm5:$lenm1), 0>, + ASE_CNMIPS; +def : MipsInstAlias<"cins $rt, $pos, $lenm1", + (CINS32 GPR64Opnd:$rt, GPR64Opnd:$rt, + uimm5_plus32_normalize:$pos, uimm5:$lenm1), 0>, + ASE_CNMIPS; + +//===----------------------------------------------------------------------===// +// Assembler Pseudo Instructions +//===----------------------------------------------------------------------===// + +class LoadImmediate64<string instr_asm, Operand Od, RegisterOperand RO> : + MipsAsmPseudoInst<(outs RO:$rt), (ins Od:$imm64), + !strconcat(instr_asm, "\t$rt, $imm64")> ; +def LoadImm64 : LoadImmediate64<"dli", imm64, GPR64Opnd>; + +def LoadAddrReg64 : MipsAsmPseudoInst<(outs GPR64Opnd:$rt), (ins mem:$addr), + "dla\t$rt, $addr">; +def LoadAddrImm64 : MipsAsmPseudoInst<(outs GPR64Opnd:$rt), (ins imm64:$imm64), + "dla\t$rt, $imm64">; diff --git a/contrib/llvm/lib/Target/Mips/Mips64r6InstrInfo.td b/contrib/llvm/lib/Target/Mips/Mips64r6InstrInfo.td new file mode 100644 index 0000000..6f34dbe --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips64r6InstrInfo.td @@ -0,0 +1,219 @@ +//=- Mips64r6InstrInfo.td - Mips64r6 Instruction Information -*- tablegen -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes Mips64r6 instructions. +// +//===----------------------------------------------------------------------===// + +// Notes about removals/changes from MIPS32r6: +// Reencoded: dclo, dclz + +//===----------------------------------------------------------------------===// +// +// Instruction Encodings +// +//===----------------------------------------------------------------------===// + +class DALIGN_ENC : SPECIAL3_DALIGN_FM<OPCODE6_DALIGN>; +class DAUI_ENC : DAUI_FM; +class DAHI_ENC : REGIMM_FM<OPCODE5_DAHI>; +class DATI_ENC : REGIMM_FM<OPCODE5_DATI>; +class DBITSWAP_ENC : SPECIAL3_2R_FM<OPCODE6_DBITSWAP>; +class DCLO_R6_ENC : SPECIAL_2R_FM<OPCODE6_DCLO>; +class DCLZ_R6_ENC : SPECIAL_2R_FM<OPCODE6_DCLZ>; +class DDIV_ENC : SPECIAL_3R_FM<0b00010, 0b011110>; +class DDIVU_ENC : SPECIAL_3R_FM<0b00010, 0b011111>; +class DLSA_R6_ENC : SPECIAL_LSA_FM<OPCODE6_DLSA>; +class DMOD_ENC : SPECIAL_3R_FM<0b00011, 0b011110>; +class DMODU_ENC : SPECIAL_3R_FM<0b00011, 0b011111>; +class DMUH_ENC : SPECIAL_3R_FM<0b00011, 0b011100>; +class DMUHU_ENC : SPECIAL_3R_FM<0b00011, 0b011101>; +class DMUL_R6_ENC : SPECIAL_3R_FM<0b00010, 0b011100>; +class DMULU_ENC : SPECIAL_3R_FM<0b00010, 0b011101>; +class LDPC_ENC : PCREL18_FM<OPCODE3_LDPC>; +class LLD_R6_ENC : SPECIAL3_LL_SC_FM<OPCODE6_LLD>; +class SCD_R6_ENC : SPECIAL3_LL_SC_FM<OPCODE6_SCD>; + +//===----------------------------------------------------------------------===// +// +// Instruction Descriptions +// +//===----------------------------------------------------------------------===// + +class AHI_ATI_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$rs); + dag InOperandList = (ins GPROpnd:$rt, simm16:$imm); + string AsmString = !strconcat(instr_asm, "\t$rt, $imm"); + string Constraints = "$rs = $rt"; +} + +class DALIGN_DESC : ALIGN_DESC_BASE<"dalign", GPR64Opnd, uimm3>; +class DAHI_DESC : AHI_ATI_DESC_BASE<"dahi", GPR64Opnd>; +class DATI_DESC : AHI_ATI_DESC_BASE<"dati", GPR64Opnd>; +class DAUI_DESC : AUI_DESC_BASE<"daui", GPR64Opnd>; +class DBITSWAP_DESC : BITSWAP_DESC_BASE<"dbitswap", GPR64Opnd>; +class DCLO_R6_DESC : CLO_R6_DESC_BASE<"dclo", GPR64Opnd>; +class DCLZ_R6_DESC : CLZ_R6_DESC_BASE<"dclz", GPR64Opnd>; +class DDIV_DESC : DIVMOD_DESC_BASE<"ddiv", GPR64Opnd, sdiv>; +class DDIVU_DESC : DIVMOD_DESC_BASE<"ddivu", GPR64Opnd, udiv>; +class DLSA_R6_DESC : LSA_R6_DESC_BASE<"dlsa", GPR64Opnd, uimm2_plus1>; +class DMOD_DESC : DIVMOD_DESC_BASE<"dmod", GPR64Opnd, srem>; +class DMODU_DESC : DIVMOD_DESC_BASE<"dmodu", GPR64Opnd, urem>; +class DMUH_DESC : MUL_R6_DESC_BASE<"dmuh", GPR64Opnd, mulhs>; +class DMUHU_DESC : MUL_R6_DESC_BASE<"dmuhu", GPR64Opnd, mulhu>; +class DMUL_R6_DESC : MUL_R6_DESC_BASE<"dmul", GPR64Opnd, mul>; +class DMULU_DESC : MUL_R6_DESC_BASE<"dmulu", GPR64Opnd>; +class LDPC_DESC : PCREL_DESC_BASE<"ldpc", GPR64Opnd, simm18_lsl3>; +class LLD_R6_DESC : LL_R6_DESC_BASE<"lld", GPR64Opnd>; +class SCD_R6_DESC : SC_R6_DESC_BASE<"scd", GPR64Opnd>; +class SELEQZ64_DESC : SELEQNE_Z_DESC_BASE<"seleqz", GPR64Opnd>; +class SELNEZ64_DESC : SELEQNE_Z_DESC_BASE<"selnez", GPR64Opnd>; + +//===----------------------------------------------------------------------===// +// +// Instruction Definitions +// +//===----------------------------------------------------------------------===// + +let AdditionalPredicates = [NotInMicroMips] in { + def DATI : DATI_ENC, DATI_DESC, ISA_MIPS64R6; + def DAHI : DAHI_ENC, DAHI_DESC, ISA_MIPS64R6; + def DAUI : DAUI_ENC, DAUI_DESC, ISA_MIPS64R6; + def DALIGN : DALIGN_ENC, DALIGN_DESC, ISA_MIPS64R6; +} +def DBITSWAP : DBITSWAP_ENC, DBITSWAP_DESC, ISA_MIPS64R6; +def DCLO_R6 : DCLO_R6_ENC, DCLO_R6_DESC, ISA_MIPS64R6; +def DCLZ_R6 : DCLZ_R6_ENC, DCLZ_R6_DESC, ISA_MIPS64R6; +def DDIV : DDIV_ENC, DDIV_DESC, ISA_MIPS64R6; +def DDIVU : DDIVU_ENC, DDIVU_DESC, ISA_MIPS64R6; +def DLSA_R6 : DLSA_R6_ENC, DLSA_R6_DESC, ISA_MIPS64R6; +def DMOD : DMOD_ENC, DMOD_DESC, ISA_MIPS64R6; +def DMODU : DMODU_ENC, DMODU_DESC, ISA_MIPS64R6; +def DMUH: DMUH_ENC, DMUH_DESC, ISA_MIPS64R6; +def DMUHU: DMUHU_ENC, DMUHU_DESC, ISA_MIPS64R6; +def DMUL_R6: DMUL_R6_ENC, DMUL_R6_DESC, ISA_MIPS64R6; +def DMULU: DMULU_ENC, DMULU_DESC, ISA_MIPS64R6; +def LDPC: LDPC_ENC, LDPC_DESC, ISA_MIPS64R6; +def LLD_R6 : LLD_R6_ENC, LLD_R6_DESC, ISA_MIPS32R6; +def SCD_R6 : SCD_R6_ENC, SCD_R6_DESC, ISA_MIPS32R6; +let DecoderNamespace = "Mips32r6_64r6_GP64" in { + def SELEQZ64 : SELEQZ_ENC, SELEQZ64_DESC, ISA_MIPS32R6, GPR_64; + def SELNEZ64 : SELNEZ_ENC, SELNEZ64_DESC, ISA_MIPS32R6, GPR_64; +} + +//===----------------------------------------------------------------------===// +// +// Instruction Aliases +// +//===----------------------------------------------------------------------===// + +def : MipsInstAlias<"jr $rs", (JALR64 ZERO_64, GPR64Opnd:$rs), 1>, ISA_MIPS64R6; + +//===----------------------------------------------------------------------===// +// +// Patterns and Pseudo Instructions +// +//===----------------------------------------------------------------------===// + +// i64 selects +def : MipsPat<(select i64:$cond, i64:$t, i64:$f), + (OR64 (SELNEZ64 i64:$t, i64:$cond), + (SELEQZ64 i64:$f, i64:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i64:$cond, immz)), i64:$t, i64:$f), + (OR64 (SELEQZ64 i64:$t, i64:$cond), + (SELNEZ64 i64:$f, i64:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (setne i64:$cond, immz)), i64:$t, i64:$f), + (OR64 (SELNEZ64 i64:$t, i64:$cond), + (SELEQZ64 i64:$f, i64:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i64:$cond, immZExt16_64:$imm)), i64:$t, i64:$f), + (OR64 (SELEQZ64 i64:$t, (XORi64 i64:$cond, immZExt16_64:$imm)), + (SELNEZ64 i64:$f, (XORi64 i64:$cond, immZExt16_64:$imm)))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (setne i64:$cond, immZExt16_64:$imm)), i64:$t, i64:$f), + (OR64 (SELNEZ64 i64:$t, (XORi64 i64:$cond, immZExt16_64:$imm)), + (SELEQZ64 i64:$f, (XORi64 i64:$cond, immZExt16_64:$imm)))>, + ISA_MIPS64R6; +def : MipsPat< + (select (i32 (setgt i64:$cond, immSExt16Plus1:$imm)), i64:$t, i64:$f), + (OR64 (SELEQZ64 i64:$t, + (SUBREG_TO_REG (i64 0), (SLTi64 i64:$cond, (Plus1 imm:$imm)), + sub_32)), + (SELNEZ64 i64:$f, + (SUBREG_TO_REG (i64 0), (SLTi64 i64:$cond, (Plus1 imm:$imm)), + sub_32)))>, + ISA_MIPS64R6; +def : MipsPat< + (select (i32 (setugt i64:$cond, immSExt16Plus1:$imm)), i64:$t, i64:$f), + (OR64 (SELEQZ64 i64:$t, + (SUBREG_TO_REG (i64 0), (SLTiu64 i64:$cond, (Plus1 imm:$imm)), + sub_32)), + (SELNEZ64 i64:$f, + (SUBREG_TO_REG (i64 0), (SLTiu64 i64:$cond, (Plus1 imm:$imm)), + sub_32)))>, + ISA_MIPS64R6; + +def : MipsPat<(select (i32 (setne i64:$cond, immz)), i64:$t, immz), + (SELNEZ64 i64:$t, i64:$cond)>, ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i64:$cond, immz)), i64:$t, immz), + (SELEQZ64 i64:$t, i64:$cond)>, ISA_MIPS64R6; +def : MipsPat<(select (i32 (setne i64:$cond, immz)), immz, i64:$f), + (SELEQZ64 i64:$f, i64:$cond)>, ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i64:$cond, immz)), immz, i64:$f), + (SELNEZ64 i64:$f, i64:$cond)>, ISA_MIPS64R6; + +// i64 selects from an i32 comparison +// One complicating factor here is that bits 32-63 of an i32 are undefined. +// FIXME: Ideally, setcc would always produce an i64 on MIPS64 targets. +// This would allow us to remove the sign-extensions here. +def : MipsPat<(select i32:$cond, i64:$t, i64:$f), + (OR64 (SELNEZ64 i64:$t, (SLL64_32 i32:$cond)), + (SELEQZ64 i64:$f, (SLL64_32 i32:$cond)))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immz)), i64:$t, i64:$f), + (OR64 (SELEQZ64 i64:$t, (SLL64_32 i32:$cond)), + (SELNEZ64 i64:$f, (SLL64_32 i32:$cond)))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (setne i32:$cond, immz)), i64:$t, i64:$f), + (OR64 (SELNEZ64 i64:$t, (SLL64_32 i32:$cond)), + (SELEQZ64 i64:$f, (SLL64_32 i32:$cond)))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immZExt16:$imm)), i64:$t, i64:$f), + (OR64 (SELEQZ64 i64:$t, (SLL64_32 (XORi i32:$cond, + immZExt16:$imm))), + (SELNEZ64 i64:$f, (SLL64_32 (XORi i32:$cond, + immZExt16:$imm))))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (setne i32:$cond, immZExt16:$imm)), i64:$t, i64:$f), + (OR64 (SELNEZ64 i64:$t, (SLL64_32 (XORi i32:$cond, + immZExt16:$imm))), + (SELEQZ64 i64:$f, (SLL64_32 (XORi i32:$cond, + immZExt16:$imm))))>, + ISA_MIPS64R6; + +def : MipsPat<(select i32:$cond, i64:$t, immz), + (SELNEZ64 i64:$t, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (setne i32:$cond, immz)), i64:$t, immz), + (SELNEZ64 i64:$t, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immz)), i64:$t, immz), + (SELEQZ64 i64:$t, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select i32:$cond, immz, i64:$f), + (SELEQZ64 i64:$f, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (setne i32:$cond, immz)), immz, i64:$f), + (SELEQZ64 i64:$f, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immz)), immz, i64:$f), + (SELNEZ64 i64:$f, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; diff --git a/contrib/llvm/lib/Target/Mips/MipsAnalyzeImmediate.cpp b/contrib/llvm/lib/Target/Mips/MipsAnalyzeImmediate.cpp new file mode 100644 index 0000000..161345d --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsAnalyzeImmediate.cpp @@ -0,0 +1,154 @@ +//===-- MipsAnalyzeImmediate.cpp - Analyze Immediates ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "MipsAnalyzeImmediate.h" +#include "Mips.h" +#include "llvm/Support/MathExtras.h" + +using namespace llvm; + +MipsAnalyzeImmediate::Inst::Inst(unsigned O, unsigned I) : Opc(O), ImmOpnd(I) {} + +// Add I to the instruction sequences. +void MipsAnalyzeImmediate::AddInstr(InstSeqLs &SeqLs, const Inst &I) { + // Add an instruction seqeunce consisting of just I. + if (SeqLs.empty()) { + SeqLs.push_back(InstSeq(1, I)); + return; + } + + for (InstSeqLs::iterator Iter = SeqLs.begin(); Iter != SeqLs.end(); ++Iter) + Iter->push_back(I); +} + +void MipsAnalyzeImmediate::GetInstSeqLsADDiu(uint64_t Imm, unsigned RemSize, + InstSeqLs &SeqLs) { + GetInstSeqLs((Imm + 0x8000ULL) & 0xffffffffffff0000ULL, RemSize, SeqLs); + AddInstr(SeqLs, Inst(ADDiu, Imm & 0xffffULL)); +} + +void MipsAnalyzeImmediate::GetInstSeqLsORi(uint64_t Imm, unsigned RemSize, + InstSeqLs &SeqLs) { + GetInstSeqLs(Imm & 0xffffffffffff0000ULL, RemSize, SeqLs); + AddInstr(SeqLs, Inst(ORi, Imm & 0xffffULL)); +} + +void MipsAnalyzeImmediate::GetInstSeqLsSLL(uint64_t Imm, unsigned RemSize, + InstSeqLs &SeqLs) { + unsigned Shamt = countTrailingZeros(Imm); + GetInstSeqLs(Imm >> Shamt, RemSize - Shamt, SeqLs); + AddInstr(SeqLs, Inst(SLL, Shamt)); +} + +void MipsAnalyzeImmediate::GetInstSeqLs(uint64_t Imm, unsigned RemSize, + InstSeqLs &SeqLs) { + uint64_t MaskedImm = Imm & (0xffffffffffffffffULL >> (64 - Size)); + + // Do nothing if Imm is 0. + if (!MaskedImm) + return; + + // A single ADDiu will do if RemSize <= 16. + if (RemSize <= 16) { + AddInstr(SeqLs, Inst(ADDiu, MaskedImm)); + return; + } + + // Shift if the lower 16-bit is cleared. + if (!(Imm & 0xffff)) { + GetInstSeqLsSLL(Imm, RemSize, SeqLs); + return; + } + + GetInstSeqLsADDiu(Imm, RemSize, SeqLs); + + // If bit 15 is cleared, it doesn't make a difference whether the last + // instruction is an ADDiu or ORi. In that case, do not call GetInstSeqLsORi. + if (Imm & 0x8000) { + InstSeqLs SeqLsORi; + GetInstSeqLsORi(Imm, RemSize, SeqLsORi); + SeqLs.append(std::make_move_iterator(SeqLsORi.begin()), + std::make_move_iterator(SeqLsORi.end())); + } +} + +// Replace a ADDiu & SLL pair with a LUi. +// e.g. the following two instructions +// ADDiu 0x0111 +// SLL 18 +// are replaced with +// LUi 0x444 +void MipsAnalyzeImmediate::ReplaceADDiuSLLWithLUi(InstSeq &Seq) { + // Check if the first two instructions are ADDiu and SLL and the shift amount + // is at least 16. + if ((Seq.size() < 2) || (Seq[0].Opc != ADDiu) || + (Seq[1].Opc != SLL) || (Seq[1].ImmOpnd < 16)) + return; + + // Sign-extend and shift operand of ADDiu and see if it still fits in 16-bit. + int64_t Imm = SignExtend64<16>(Seq[0].ImmOpnd); + int64_t ShiftedImm = (uint64_t)Imm << (Seq[1].ImmOpnd - 16); + + if (!isInt<16>(ShiftedImm)) + return; + + // Replace the first instruction and erase the second. + Seq[0].Opc = LUi; + Seq[0].ImmOpnd = (unsigned)(ShiftedImm & 0xffff); + Seq.erase(Seq.begin() + 1); +} + +void MipsAnalyzeImmediate::GetShortestSeq(InstSeqLs &SeqLs, InstSeq &Insts) { + InstSeqLs::iterator ShortestSeq = SeqLs.end(); + // The length of an instruction sequence is at most 7. + unsigned ShortestLength = 8; + + for (InstSeqLs::iterator S = SeqLs.begin(); S != SeqLs.end(); ++S) { + ReplaceADDiuSLLWithLUi(*S); + assert(S->size() <= 7); + + if (S->size() < ShortestLength) { + ShortestSeq = S; + ShortestLength = S->size(); + } + } + + Insts.clear(); + Insts.append(ShortestSeq->begin(), ShortestSeq->end()); +} + +const MipsAnalyzeImmediate::InstSeq +&MipsAnalyzeImmediate::Analyze(uint64_t Imm, unsigned Size, + bool LastInstrIsADDiu) { + this->Size = Size; + + if (Size == 32) { + ADDiu = Mips::ADDiu; + ORi = Mips::ORi; + SLL = Mips::SLL; + LUi = Mips::LUi; + } else { + ADDiu = Mips::DADDiu; + ORi = Mips::ORi64; + SLL = Mips::DSLL; + LUi = Mips::LUi64; + } + + InstSeqLs SeqLs; + + // Get the list of instruction sequences. + if (LastInstrIsADDiu | !Imm) + GetInstSeqLsADDiu(Imm, Size, SeqLs); + else + GetInstSeqLs(Imm, Size, SeqLs); + + // Set Insts to the shortest instruction sequence. + GetShortestSeq(SeqLs, Insts); + + return Insts; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsAnalyzeImmediate.h b/contrib/llvm/lib/Target/Mips/MipsAnalyzeImmediate.h new file mode 100644 index 0000000..ae3c38c --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsAnalyzeImmediate.h @@ -0,0 +1,63 @@ +//===-- MipsAnalyzeImmediate.h - Analyze Immediates ------------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_LIB_TARGET_MIPS_MIPSANALYZEIMMEDIATE_H +#define LLVM_LIB_TARGET_MIPS_MIPSANALYZEIMMEDIATE_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataTypes.h" + +namespace llvm { + + class MipsAnalyzeImmediate { + public: + struct Inst { + unsigned Opc, ImmOpnd; + Inst(unsigned Opc, unsigned ImmOpnd); + }; + typedef SmallVector<Inst, 7 > InstSeq; + + /// Analyze - Get an instruction sequence to load immediate Imm. The last + /// instruction in the sequence must be an ADDiu if LastInstrIsADDiu is + /// true; + const InstSeq &Analyze(uint64_t Imm, unsigned Size, bool LastInstrIsADDiu); + private: + typedef SmallVector<InstSeq, 5> InstSeqLs; + + /// AddInstr - Add I to all instruction sequences in SeqLs. + void AddInstr(InstSeqLs &SeqLs, const Inst &I); + + /// GetInstSeqLsADDiu - Get instruction sequences which end with an ADDiu to + /// load immediate Imm + void GetInstSeqLsADDiu(uint64_t Imm, unsigned RemSize, InstSeqLs &SeqLs); + + /// GetInstSeqLsORi - Get instrutcion sequences which end with an ORi to + /// load immediate Imm + void GetInstSeqLsORi(uint64_t Imm, unsigned RemSize, InstSeqLs &SeqLs); + + /// GetInstSeqLsSLL - Get instruction sequences which end with a SLL to + /// load immediate Imm + void GetInstSeqLsSLL(uint64_t Imm, unsigned RemSize, InstSeqLs &SeqLs); + + /// GetInstSeqLs - Get instruction sequences to load immediate Imm. + void GetInstSeqLs(uint64_t Imm, unsigned RemSize, InstSeqLs &SeqLs); + + /// ReplaceADDiuSLLWithLUi - Replace an ADDiu & SLL pair with a LUi. + void ReplaceADDiuSLLWithLUi(InstSeq &Seq); + + /// GetShortestSeq - Find the shortest instruction sequence in SeqLs and + /// return it in Insts. + void GetShortestSeq(InstSeqLs &SeqLs, InstSeq &Insts); + + unsigned Size; + unsigned ADDiu, ORi, SLL, LUi; + InstSeq Insts; + }; +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.cpp b/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.cpp new file mode 100644 index 0000000..9575293 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.cpp @@ -0,0 +1,1093 @@ +//===-- MipsAsmPrinter.cpp - Mips LLVM Assembly Printer -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to GAS-format MIPS assembly language. +// +//===----------------------------------------------------------------------===// + +#include "InstPrinter/MipsInstPrinter.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MCTargetDesc/MipsMCNaCl.h" +#include "Mips.h" +#include "MipsAsmPrinter.h" +#include "MipsInstrInfo.h" +#include "MipsMCInstLower.h" +#include "MipsTargetMachine.h" +#include "MipsTargetStreamer.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/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/MCSymbolELF.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/Target/TargetOptions.h" +#include <string> + +using namespace llvm; + +#define DEBUG_TYPE "mips-asm-printer" + +MipsTargetStreamer &MipsAsmPrinter::getTargetStreamer() const { + return static_cast<MipsTargetStreamer &>(*OutStreamer->getTargetStreamer()); +} + +bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &MF.getSubtarget<MipsSubtarget>(); + + // Initialize TargetLoweringObjectFile. + 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; +} + +bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) { + MCOp = MCInstLowering.LowerOperand(MO); + return MCOp.isValid(); +} + +#include "MipsGenMCPseudoLowering.inc" + +// Lower PseudoReturn/PseudoIndirectBranch/PseudoIndirectBranch64 to JR, JR_MM, +// JALR, or JALR64 as appropriate for the target +void MipsAsmPrinter::emitPseudoIndirectBranch(MCStreamer &OutStreamer, + const MachineInstr *MI) { + bool HasLinkReg = false; + MCInst TmpInst0; + + if (Subtarget->hasMips64r6()) { + // MIPS64r6 should use (JALR64 ZERO_64, $rs) + TmpInst0.setOpcode(Mips::JALR64); + HasLinkReg = true; + } else if (Subtarget->hasMips32r6()) { + // MIPS32r6 should use (JALR ZERO, $rs) + TmpInst0.setOpcode(Mips::JALR); + HasLinkReg = true; + } else if (Subtarget->inMicroMipsMode()) + // microMIPS should use (JR_MM $rs) + TmpInst0.setOpcode(Mips::JR_MM); + else { + // Everything else should use (JR $rs) + TmpInst0.setOpcode(Mips::JR); + } + + MCOperand MCOp; + + if (HasLinkReg) { + unsigned ZeroReg = Subtarget->isGP64bit() ? Mips::ZERO_64 : Mips::ZERO; + TmpInst0.addOperand(MCOperand::createReg(ZeroReg)); + } + + lowerOperand(MI->getOperand(0), MCOp); + TmpInst0.addOperand(MCOp); + + EmitToStreamer(OutStreamer, TmpInst0); +} + +void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { + MipsTargetStreamer &TS = getTargetStreamer(); + TS.forbidModuleDirective(); + + if (MI->isDebugValue()) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + + PrintDebugValueComment(MI, OS); + return; + } + + // If we just ended a constant pool, mark it as such. + if (InConstantPool && MI->getOpcode() != Mips::CONSTPOOL_ENTRY) { + OutStreamer->EmitDataRegion(MCDR_DataRegionEnd); + InConstantPool = false; + } + if (MI->getOpcode() == Mips::CONSTPOOL_ENTRY) { + // CONSTPOOL_ENTRY - This instruction represents a floating + //constant pool in the function. The first operand is the ID# + // for this instruction, the second is the index into the + // MachineConstantPool that this is, the third is the size in + // bytes of this constant pool entry. + // The required alignment is specified on the basic block holding this MI. + // + unsigned LabelId = (unsigned)MI->getOperand(0).getImm(); + unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex(); + + // If this is the first entry of the pool, mark it. + if (!InConstantPool) { + OutStreamer->EmitDataRegion(MCDR_DataRegion); + InConstantPool = true; + } + + OutStreamer->EmitLabel(GetCPISymbol(LabelId)); + + const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; + if (MCPE.isMachineConstantPoolEntry()) + EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); + else + EmitGlobalConstant(MF->getDataLayout(), MCPE.Val.ConstVal); + return; + } + + + MachineBasicBlock::const_instr_iterator I = MI->getIterator(); + MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end(); + + do { + // Do any auto-generated pseudo lowerings. + if (emitPseudoExpansionLowering(*OutStreamer, &*I)) + continue; + + if (I->getOpcode() == Mips::PseudoReturn || + I->getOpcode() == Mips::PseudoReturn64 || + I->getOpcode() == Mips::PseudoIndirectBranch || + I->getOpcode() == Mips::PseudoIndirectBranch64) { + emitPseudoIndirectBranch(*OutStreamer, &*I); + continue; + } + + // The inMips16Mode() test is not permanent. + // Some instructions are marked as pseudo right now which + // would make the test fail for the wrong reason but + // that will be fixed soon. We need this here because we are + // removing another test for this situation downstream in the + // callchain. + // + if (I->isPseudo() && !Subtarget->inMips16Mode() + && !isLongBranchPseudo(I->getOpcode())) + llvm_unreachable("Pseudo opcode found in EmitInstruction()"); + + MCInst TmpInst0; + MCInstLowering.Lower(&*I, TmpInst0); + EmitToStreamer(*OutStreamer, TmpInst0); + } while ((++I != E) && I->isInsideBundle()); // Delay slot check +} + +//===----------------------------------------------------------------------===// +// +// Mips Asm Directives +// +// -- Frame directive "frame Stackpointer, Stacksize, RARegister" +// Describe the stack frame. +// +// -- Mask directives "(f)mask bitmask, offset" +// Tells the assembler which registers are saved and where. +// bitmask - contain a little endian bitset indicating which registers are +// saved on function prologue (e.g. with a 0x80000000 mask, the +// assembler knows the register 31 (RA) is saved at prologue. +// offset - the position before stack pointer subtraction indicating where +// the first saved register on prologue is located. (e.g. with a +// +// Consider the following function prologue: +// +// .frame $fp,48,$ra +// .mask 0xc0000000,-8 +// addiu $sp, $sp, -48 +// sw $ra, 40($sp) +// sw $fp, 36($sp) +// +// With a 0xc0000000 mask, the assembler knows the register 31 (RA) and +// 30 (FP) are saved at prologue. As the save order on prologue is from +// left to right, RA is saved first. A -8 offset means that after the +// stack pointer subtration, the first register in the mask (RA) will be +// saved at address 48-8=40. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Mask directives +//===----------------------------------------------------------------------===// + +// Create a bitmask with all callee saved registers for CPU or Floating Point +// registers. For CPU registers consider RA, GP and FP for saving if necessary. +void MipsAsmPrinter::printSavedRegsBitmask() { + // CPU and FPU Saved Registers Bitmasks + unsigned CPUBitmask = 0, FPUBitmask = 0; + int CPUTopSavedRegOff, FPUTopSavedRegOff; + + // Set the CPU and FPU Bitmasks + const MachineFrameInfo *MFI = MF->getFrameInfo(); + const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); + const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); + // size of stack area to which FP callee-saved regs are saved. + unsigned CPURegSize = Mips::GPR32RegClass.getSize(); + unsigned FGR32RegSize = Mips::FGR32RegClass.getSize(); + unsigned AFGR64RegSize = Mips::AFGR64RegClass.getSize(); + bool HasAFGR64Reg = false; + unsigned CSFPRegsSize = 0; + + for (const auto &I : CSI) { + unsigned Reg = I.getReg(); + unsigned RegNum = TRI->getEncodingValue(Reg); + + // If it's a floating point register, set the FPU Bitmask. + // If it's a general purpose register, set the CPU Bitmask. + if (Mips::FGR32RegClass.contains(Reg)) { + FPUBitmask |= (1 << RegNum); + CSFPRegsSize += FGR32RegSize; + } else if (Mips::AFGR64RegClass.contains(Reg)) { + FPUBitmask |= (3 << RegNum); + CSFPRegsSize += AFGR64RegSize; + HasAFGR64Reg = true; + } else if (Mips::GPR32RegClass.contains(Reg)) + CPUBitmask |= (1 << RegNum); + } + + // FP Regs are saved right below where the virtual frame pointer points to. + FPUTopSavedRegOff = FPUBitmask ? + (HasAFGR64Reg ? -AFGR64RegSize : -FGR32RegSize) : 0; + + // CPU Regs are saved below FP Regs. + CPUTopSavedRegOff = CPUBitmask ? -CSFPRegsSize - CPURegSize : 0; + + MipsTargetStreamer &TS = getTargetStreamer(); + // Print CPUBitmask + TS.emitMask(CPUBitmask, CPUTopSavedRegOff); + + // Print FPUBitmask + TS.emitFMask(FPUBitmask, FPUTopSavedRegOff); +} + +//===----------------------------------------------------------------------===// +// Frame and Set directives +//===----------------------------------------------------------------------===// + +/// Frame Directive +void MipsAsmPrinter::emitFrameDirective() { + const TargetRegisterInfo &RI = *MF->getSubtarget().getRegisterInfo(); + + unsigned stackReg = RI.getFrameRegister(*MF); + unsigned returnReg = RI.getRARegister(); + unsigned stackSize = MF->getFrameInfo()->getStackSize(); + + getTargetStreamer().emitFrame(stackReg, stackSize, returnReg); +} + +/// Emit Set directives. +const char *MipsAsmPrinter::getCurrentABIString() const { + switch (static_cast<MipsTargetMachine &>(TM).getABI().GetEnumValue()) { + case MipsABIInfo::ABI::O32: return "abi32"; + case MipsABIInfo::ABI::N32: return "abiN32"; + case MipsABIInfo::ABI::N64: return "abi64"; + case MipsABIInfo::ABI::EABI: return "eabi32"; // TODO: handle eabi64 + default: llvm_unreachable("Unknown Mips ABI"); + } +} + +void MipsAsmPrinter::EmitFunctionEntryLabel() { + 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()) + TS.emitDirectiveSetMicroMips(); + else + TS.emitDirectiveSetNoMicroMips(); + + if (Subtarget->inMips16Mode()) + TS.emitDirectiveSetMips16(); + else + TS.emitDirectiveSetNoMips16(); + + TS.emitDirectiveEnt(*CurrentFnSym); + OutStreamer->EmitLabel(CurrentFnSym); +} + +/// EmitFunctionBodyStart - Targets can override this to emit stuff before +/// the first basic block in the function. +void MipsAsmPrinter::EmitFunctionBodyStart() { + MipsTargetStreamer &TS = getTargetStreamer(); + + MCInstLowering.Initialize(&MF->getContext()); + + bool IsNakedFunction = MF->getFunction()->hasFnAttribute(Attribute::Naked); + if (!IsNakedFunction) + emitFrameDirective(); + + 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 (!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) + return; + InConstantPool = false; + OutStreamer->EmitDataRegion(MCDR_DataRegionEnd); +} + +void MipsAsmPrinter::EmitBasicBlockEnd(const MachineBasicBlock &MBB) { + MipsTargetStreamer &TS = getTargetStreamer(); + if (MBB.size() == 0) + TS.emitDirectiveInsn(); +} + +/// isBlockOnlyReachableByFallthough - Return true if the basic block has +/// exactly one predecessor and the control transfer mechanism between +/// the predecessor and this block is a fall-through. +bool MipsAsmPrinter::isBlockOnlyReachableByFallthrough(const MachineBasicBlock* + MBB) const { + // The predecessor has to be immediately before this block. + const MachineBasicBlock *Pred = *MBB->pred_begin(); + + // If the predecessor is a switch statement, assume a jump table + // implementation, so it is not a fall through. + if (const BasicBlock *bb = Pred->getBasicBlock()) + if (isa<SwitchInst>(bb->getTerminator())) + return false; + + // If this is a landing pad, it isn't a fall through. If it has no preds, + // then nothing falls through to it. + if (MBB->isEHPad() || MBB->pred_empty()) + return false; + + // If there isn't exactly one predecessor, it can't be a fall through. + MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PI2 = PI; + ++PI2; + + if (PI2 != MBB->pred_end()) + return false; + + // The predecessor has to be immediately before this block. + if (!Pred->isLayoutSuccessor(MBB)) + return false; + + // If the block is completely empty, then it definitely does fall through. + if (Pred->empty()) + return true; + + // Otherwise, check the last instruction. + // Check if the last terminator is an unconditional branch. + MachineBasicBlock::const_iterator I = Pred->end(); + while (I != Pred->begin() && !(--I)->isTerminator()) ; + + return !I->isBarrier(); +} + +// Print out an operand for an inline asm expression. +bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O) { + // Does this asm operand have a single letter operand modifier? + if (ExtraCode && ExtraCode[0]) { + if (ExtraCode[1] != 0) return true; // Unknown modifier. + + const MachineOperand &MO = MI->getOperand(OpNum); + switch (ExtraCode[0]) { + default: + // See if this is a generic print operand + return AsmPrinter::PrintAsmOperand(MI,OpNum,AsmVariant,ExtraCode,O); + case 'X': // hex const int + if ((MO.getType()) != MachineOperand::MO_Immediate) + return true; + O << "0x" << Twine::utohexstr(MO.getImm()); + return false; + case 'x': // hex const int (low 16 bits) + if ((MO.getType()) != MachineOperand::MO_Immediate) + return true; + O << "0x" << Twine::utohexstr(MO.getImm() & 0xffff); + return false; + case 'd': // decimal const int + if ((MO.getType()) != MachineOperand::MO_Immediate) + return true; + O << MO.getImm(); + return false; + case 'm': // decimal const int minus 1 + if ((MO.getType()) != MachineOperand::MO_Immediate) + return true; + O << MO.getImm() - 1; + return false; + case 'z': { + // $0 if zero, regular printing otherwise + if (MO.getType() == MachineOperand::MO_Immediate && MO.getImm() == 0) { + O << "$0"; + return false; + } + // If not, call printOperand as normal. + break; + } + case 'D': // Second part of a double word register operand + case 'L': // Low order register of a double word register operand + case 'M': // High order register of a double word register operand + { + if (OpNum == 0) + return true; + const MachineOperand &FlagsOP = MI->getOperand(OpNum - 1); + if (!FlagsOP.isImm()) + return true; + unsigned Flags = FlagsOP.getImm(); + unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags); + // Number of registers represented by this operand. We are looking + // for 2 for 32 bit mode and 1 for 64 bit mode. + if (NumVals != 2) { + if (Subtarget->isGP64bit() && NumVals == 1 && MO.isReg()) { + unsigned Reg = MO.getReg(); + O << '$' << MipsInstPrinter::getRegisterName(Reg); + return false; + } + return true; + } + + unsigned RegOp = OpNum; + if (!Subtarget->isGP64bit()){ + // Endianess reverses which register holds the high or low value + // between M and L. + switch(ExtraCode[0]) { + case 'M': + RegOp = (Subtarget->isLittle()) ? OpNum + 1 : OpNum; + break; + case 'L': + RegOp = (Subtarget->isLittle()) ? OpNum : OpNum + 1; + break; + case 'D': // Always the second part + RegOp = OpNum + 1; + } + if (RegOp >= MI->getNumOperands()) + return true; + const MachineOperand &MO = MI->getOperand(RegOp); + if (!MO.isReg()) + return true; + unsigned Reg = MO.getReg(); + O << '$' << MipsInstPrinter::getRegisterName(Reg); + return false; + } + } + case 'w': + // Print MSA registers for the 'f' constraint + // In LLVM, the 'w' modifier doesn't need to do anything. + // We can just call printOperand as normal. + break; + } + } + + printOperand(MI, OpNum, O); + return false; +} + +bool MipsAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNum, unsigned AsmVariant, + const char *ExtraCode, + raw_ostream &O) { + assert(OpNum + 1 < MI->getNumOperands() && "Insufficient operands"); + const MachineOperand &BaseMO = MI->getOperand(OpNum); + const MachineOperand &OffsetMO = MI->getOperand(OpNum + 1); + assert(BaseMO.isReg() && "Unexpected base pointer for inline asm memory operand."); + assert(OffsetMO.isImm() && "Unexpected offset for inline asm memory operand."); + int Offset = OffsetMO.getImm(); + + // Currently we are expecting either no ExtraCode or 'D' + if (ExtraCode) { + if (ExtraCode[0] == 'D') + Offset += 4; + else + return true; // Unknown modifier. + // FIXME: M = high order bits + // FIXME: L = low order bits + } + + O << Offset << "($" << MipsInstPrinter::getRegisterName(BaseMO.getReg()) << ")"; + + return false; +} + +void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(opNum); + bool closeP = false; + + if (MO.getTargetFlags()) + closeP = true; + + switch(MO.getTargetFlags()) { + case MipsII::MO_GPREL: O << "%gp_rel("; break; + case MipsII::MO_GOT_CALL: O << "%call16("; break; + case MipsII::MO_GOT: O << "%got("; break; + case MipsII::MO_ABS_HI: O << "%hi("; break; + case MipsII::MO_ABS_LO: O << "%lo("; break; + case MipsII::MO_TLSGD: O << "%tlsgd("; break; + case MipsII::MO_GOTTPREL: O << "%gottprel("; break; + case MipsII::MO_TPREL_HI: O << "%tprel_hi("; break; + case MipsII::MO_TPREL_LO: O << "%tprel_lo("; break; + case MipsII::MO_GPOFF_HI: O << "%hi(%neg(%gp_rel("; break; + case MipsII::MO_GPOFF_LO: O << "%lo(%neg(%gp_rel("; break; + case MipsII::MO_GOT_DISP: O << "%got_disp("; break; + case MipsII::MO_GOT_PAGE: O << "%got_page("; break; + case MipsII::MO_GOT_OFST: O << "%got_ofst("; break; + } + + switch (MO.getType()) { + case MachineOperand::MO_Register: + O << '$' + << StringRef(MipsInstPrinter::getRegisterName(MO.getReg())).lower(); + break; + + case MachineOperand::MO_Immediate: + O << MO.getImm(); + break; + + case MachineOperand::MO_MachineBasicBlock: + MO.getMBB()->getSymbol()->print(O, MAI); + return; + + case MachineOperand::MO_GlobalAddress: + getSymbol(MO.getGlobal())->print(O, MAI); + break; + + case MachineOperand::MO_BlockAddress: { + MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress()); + O << BA->getName(); + break; + } + + case MachineOperand::MO_ConstantPoolIndex: + O << getDataLayout().getPrivateGlobalPrefix() << "CPI" + << getFunctionNumber() << "_" << MO.getIndex(); + if (MO.getOffset()) + O << "+" << MO.getOffset(); + break; + + default: + llvm_unreachable("<unknown operand type>"); + } + + if (closeP) O << ")"; +} + +void MipsAsmPrinter::printUnsignedImm(const MachineInstr *MI, int opNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(opNum); + if (MO.isImm()) + O << (unsigned short int)MO.getImm(); + else + printOperand(MI, opNum, O); +} + +void MipsAsmPrinter::printUnsignedImm8(const MachineInstr *MI, int opNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(opNum); + if (MO.isImm()) + O << (unsigned short int)(unsigned char)MO.getImm(); + else + printOperand(MI, opNum, O); +} + +void MipsAsmPrinter:: +printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O) { + // Load/Store memory operands -- imm($reg) + // If PIC target the target is loaded as the + // pattern lw $25,%call16($28) + + // opNum can be invalid if instruction has reglist as operand. + // MemOperand is always last operand of instruction (base + offset). + switch (MI->getOpcode()) { + default: + break; + case Mips::SWM32_MM: + case Mips::LWM32_MM: + opNum = MI->getNumOperands() - 2; + break; + } + + printOperand(MI, opNum+1, O); + O << "("; + printOperand(MI, opNum, O); + O << ")"; +} + +void MipsAsmPrinter:: +printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O) { + // when using stack locations for not load/store instructions + // print the same way as all normal 3 operand instructions. + printOperand(MI, opNum, O); + O << ", "; + printOperand(MI, opNum+1, O); + return; +} + +void MipsAsmPrinter:: +printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, + const char *Modifier) { + const MachineOperand &MO = MI->getOperand(opNum); + O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm()); +} + +void MipsAsmPrinter:: +printRegisterList(const MachineInstr *MI, int opNum, raw_ostream &O) { + for (int i = opNum, e = MI->getNumOperands(); i != e; ++i) { + if (i != opNum) O << ", "; + printOperand(MI, i, O); + } +} + +void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) { + + // Compute MIPS architecture attributes based on the default subtarget + // that we'd have constructed. Module level directives aren't LTO + // clean anyhow. + // FIXME: For ifunc related functions we could iterate over and look + // for a feature string that doesn't match the default one. + const Triple &TT = TM.getTargetTriple(); + StringRef CPU = MIPS_MC::selectMipsCPU(TT, TM.getTargetCPU()); + StringRef FS = TM.getTargetFeatureString(); + const MipsTargetMachine &MTM = static_cast<const MipsTargetMachine &>(TM); + const MipsSubtarget STI(TT, CPU, FS, MTM.isLittleEndian(), MTM); + + bool IsABICalls = STI.isABICalls(); + const MipsABIInfo &ABI = MTM.getABI(); + if (IsABICalls) { + getTargetStreamer().emitDirectiveAbiCalls(); + Reloc::Model RM = TM.getRelocationModel(); + // FIXME: This condition should be a lot more complicated that it is here. + // Ideally it should test for properties of the ABI and not the ABI + // itself. + // For the moment, I'm only correcting enough to make MIPS-IV work. + if (RM == Reloc::Static && !ABI.IsN64()) + getTargetStreamer().emitDirectiveOptionPic0(); + } + + // Tell the assembler which ABI we are using + std::string SectionName = std::string(".mdebug.") + getCurrentABIString(); + OutStreamer->SwitchSection( + OutContext.getELFSection(SectionName, ELF::SHT_PROGBITS, 0)); + + // NaN: At the moment we only support: + // 1. .nan legacy (default) + // 2. .nan 2008 + STI.isNaN2008() ? getTargetStreamer().emitDirectiveNaN2008() + : getTargetStreamer().emitDirectiveNaNLegacy(); + + // TODO: handle O64 ABI + + if (ABI.IsEABI()) { + if (STI.isGP32bit()) + OutStreamer->SwitchSection(OutContext.getELFSection(".gcc_compiled_long32", + ELF::SHT_PROGBITS, 0)); + else + OutStreamer->SwitchSection(OutContext.getELFSection(".gcc_compiled_long64", + ELF::SHT_PROGBITS, 0)); + } + + getTargetStreamer().updateABIInfo(STI); + + // We should always emit a '.module fp=...' but binutils 2.24 does not accept + // it. We therefore emit it when it contradicts the ABI defaults (-mfpxx or + // -mfp64) and omit it otherwise. + if (ABI.IsO32() && (STI.isABI_FPXX() || STI.isFP64bit())) + getTargetStreamer().emitDirectiveModuleFP(); + + // We should always emit a '.module [no]oddspreg' but binutils 2.24 does not + // accept it. We therefore emit it when it contradicts the default or an + // option has changed the default (i.e. FPXX) and omit it otherwise. + if (ABI.IsO32() && (!STI.useOddSPReg() || STI.isABI_FPXX())) + getTargetStreamer().emitDirectiveModuleOddSPReg(); +} + +void MipsAsmPrinter::emitInlineAsmStart() const { + MipsTargetStreamer &TS = getTargetStreamer(); + + // GCC's choice of assembler options for inline assembly code ('at', 'macro' + // and 'reorder') is different from LLVM's choice for generated code ('noat', + // 'nomacro' and 'noreorder'). + // In order to maintain compatibility with inline assembly code which depends + // on GCC's assembler options being used, we have to switch to those options + // for the duration of the inline assembly block and then switch back. + TS.emitDirectiveSetPush(); + TS.emitDirectiveSetAt(); + TS.emitDirectiveSetMacro(); + TS.emitDirectiveSetReorder(); + OutStreamer->AddBlankLine(); +} + +void MipsAsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, + const MCSubtargetInfo *EndInfo) const { + OutStreamer->AddBlankLine(); + getTargetStreamer().emitDirectiveSetPop(); +} + +void MipsAsmPrinter::EmitJal(const MCSubtargetInfo &STI, MCSymbol *Symbol) { + MCInst I; + I.setOpcode(Mips::JAL); + I.addOperand( + MCOperand::createExpr(MCSymbolRefExpr::create(Symbol, OutContext))); + OutStreamer->EmitInstruction(I, STI); +} + +void MipsAsmPrinter::EmitInstrReg(const MCSubtargetInfo &STI, unsigned Opcode, + unsigned Reg) { + MCInst I; + I.setOpcode(Opcode); + I.addOperand(MCOperand::createReg(Reg)); + OutStreamer->EmitInstruction(I, STI); +} + +void MipsAsmPrinter::EmitInstrRegReg(const MCSubtargetInfo &STI, + 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, STI); +} + +void MipsAsmPrinter::EmitInstrRegRegReg(const MCSubtargetInfo &STI, + 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, STI); +} + +void MipsAsmPrinter::EmitMovFPIntPair(const MCSubtargetInfo &STI, + unsigned MovOpc, unsigned Reg1, + unsigned Reg2, unsigned FPReg1, + unsigned FPReg2, bool LE) { + if (!LE) { + unsigned temp = Reg1; + Reg1 = Reg2; + Reg2 = temp; + } + EmitInstrRegReg(STI, MovOpc, Reg1, FPReg1); + EmitInstrRegReg(STI, MovOpc, Reg2, FPReg2); +} + +void MipsAsmPrinter::EmitSwapFPIntParams(const MCSubtargetInfo &STI, + Mips16HardFloatInfo::FPParamVariant PV, + bool LE, bool ToFP) { + using namespace Mips16HardFloatInfo; + unsigned MovOpc = ToFP ? Mips::MTC1 : Mips::MFC1; + switch (PV) { + case FSig: + EmitInstrRegReg(STI, MovOpc, Mips::A0, Mips::F12); + break; + case FFSig: + EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F14, LE); + break; + case FDSig: + EmitInstrRegReg(STI, MovOpc, Mips::A0, Mips::F12); + EmitMovFPIntPair(STI, MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE); + break; + case DSig: + EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); + break; + case DDSig: + EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); + EmitMovFPIntPair(STI, MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE); + break; + case DFSig: + EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); + EmitInstrRegReg(STI, MovOpc, Mips::A2, Mips::F14); + break; + case NoSig: + return; + } +} + +void MipsAsmPrinter::EmitSwapFPIntRetval( + const MCSubtargetInfo &STI, Mips16HardFloatInfo::FPReturnVariant RV, + bool LE) { + using namespace Mips16HardFloatInfo; + unsigned MovOpc = Mips::MFC1; + switch (RV) { + case FRet: + EmitInstrRegReg(STI, MovOpc, Mips::V0, Mips::F0); + break; + case DRet: + EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); + break; + case CFRet: + EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); + break; + case CDRet: + EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); + EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F2, Mips::F3, LE); + break; + case NoFPRet: + break; + } +} + +void MipsAsmPrinter::EmitFPCallStub( + const char *Symbol, const Mips16HardFloatInfo::FuncSignature *Signature) { + MCSymbol *MSymbol = OutContext.getOrCreateSymbol(StringRef(Symbol)); + using namespace Mips16HardFloatInfo; + bool LE = getDataLayout().isLittleEndian(); + // Construct a local MCSubtargetInfo here. + // This is because the MachineFunction won't exist (but have not yet been + // freed) and since we're at the global level we can use the default + // constructed subtarget. + std::unique_ptr<MCSubtargetInfo> STI(TM.getTarget().createMCSubtargetInfo( + TM.getTargetTriple().str(), TM.getTargetCPU(), + TM.getTargetFeatureString())); + + // + // .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 + // + MCSectionELF *M = OutContext.getELFSection( + ".mips16.call.fp." + std::string(Symbol), ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_EXECINSTR); + OutStreamer->SwitchSection(M, nullptr); + // + // .align 2 + // + OutStreamer->EmitValueToAlignment(4); + MipsTargetStreamer &TS = getTargetStreamer(); + // + // .set nomips16 + // .set nomicromips + // + TS.emitDirectiveSetNoMips16(); + TS.emitDirectiveSetNoMicroMips(); + // + // .ent __call_stub_fp_xxxx + // .type __call_stub_fp_xxxx,@function + // __call_stub_fp_xxxx: + // + std::string x = "__call_stub_fp_" + std::string(Symbol); + MCSymbolELF *Stub = + cast<MCSymbolELF>(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); + + // Only handle non-pic for now. + assert(TM.getRelocationModel() != Reloc::PIC_ && + "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(*STI, Mips::OR, Mips::S2, Mips::RA, Mips::ZERO); + + EmitSwapFPIntParams(*STI, Signature->ParamSig, LE, true); + + // Jal xxxx + // + EmitJal(*STI, MSymbol); + + // fix return values + EmitSwapFPIntRetval(*STI, Signature->RetSig, LE); + // + // do the return + // if (Signature->RetSig == NoFPRet) + // llvm_unreachable("should not be any stubs here with no return value"); + // else + EmitInstrReg(*STI, 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 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, + raw_ostream &OS) { + // TODO: implement +} + +// Align all targets of indirect branches on bundle size. Used only if target +// is NaCl. +void MipsAsmPrinter::NaClAlignIndirectJumpTargets(MachineFunction &MF) { + // Align all blocks that are jumped to through jump table. + if (MachineJumpTableInfo *JtInfo = MF.getJumpTableInfo()) { + const std::vector<MachineJumpTableEntry> &JT = JtInfo->getJumpTables(); + for (unsigned I = 0; I < JT.size(); ++I) { + const std::vector<MachineBasicBlock*> &MBBs = JT[I].MBBs; + + for (unsigned J = 0; J < MBBs.size(); ++J) + MBBs[J]->setAlignment(MIPS_NACL_BUNDLE_ALIGN); + } + } + + // If basic block address is taken, block can be target of indirect branch. + for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); + MBB != E; ++MBB) { + if (MBB->hasAddressTaken()) + MBB->setAlignment(MIPS_NACL_BUNDLE_ALIGN); + } +} + +bool MipsAsmPrinter::isLongBranchPseudo(int Opcode) const { + return (Opcode == Mips::LONG_BRANCH_LUi + || Opcode == Mips::LONG_BRANCH_ADDiu + || Opcode == Mips::LONG_BRANCH_DADDiu); +} + +// Force static initialization. +extern "C" void LLVMInitializeMipsAsmPrinter() { + RegisterAsmPrinter<MipsAsmPrinter> X(TheMipsTarget); + RegisterAsmPrinter<MipsAsmPrinter> Y(TheMipselTarget); + RegisterAsmPrinter<MipsAsmPrinter> A(TheMips64Target); + RegisterAsmPrinter<MipsAsmPrinter> B(TheMips64elTarget); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.h b/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.h new file mode 100644 index 0000000..a7f3304 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.h @@ -0,0 +1,151 @@ +//===-- MipsAsmPrinter.h - Mips LLVM Assembly Printer ----------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Mips Assembly printer class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSASMPRINTER_H +#define LLVM_LIB_TARGET_MIPS_MIPSASMPRINTER_H + +#include "Mips16HardFloatInfo.h" +#include "MipsMCInstLower.h" +#include "MipsMachineFunction.h" +#include "MipsSubtarget.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { +class MCStreamer; +class MachineInstr; +class MachineBasicBlock; +class MipsTargetStreamer; +class Module; +class raw_ostream; + +class LLVM_LIBRARY_VISIBILITY MipsAsmPrinter : public AsmPrinter { + MipsTargetStreamer &getTargetStreamer() const; + + void EmitInstrWithMacroNoAT(const MachineInstr *MI); + +private: + // tblgen'erated function. + bool emitPseudoExpansionLowering(MCStreamer &OutStreamer, + const MachineInstr *MI); + + // Emit PseudoReturn, PseudoReturn64, PseudoIndirectBranch, + // and PseudoIndirectBranch64 as a JR, JR_MM, JALR, or JALR64 as appropriate + // for the target. + void emitPseudoIndirectBranch(MCStreamer &OutStreamer, + const MachineInstr *MI); + + // lowerOperand - Convert a MachineOperand into the equivalent MCOperand. + bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp); + + /// MCP - Keep a pointer to constantpool entries of the current + /// MachineFunction. + const MachineConstantPool *MCP; + + /// InConstantPool - Maintain state when emitting a sequence of constant + /// pool entries so we can properly mark them as data regions. + bool InConstantPool; + + std::map<const char *, const llvm::Mips16HardFloatInfo::FuncSignature *> + StubsNeeded; + + void emitInlineAsmStart() const override; + + void emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, + const MCSubtargetInfo *EndInfo) const override; + + void EmitJal(const MCSubtargetInfo &STI, MCSymbol *Symbol); + + void EmitInstrReg(const MCSubtargetInfo &STI, unsigned Opcode, unsigned Reg); + + void EmitInstrRegReg(const MCSubtargetInfo &STI, unsigned Opcode, + unsigned Reg1, unsigned Reg2); + + void EmitInstrRegRegReg(const MCSubtargetInfo &STI, unsigned Opcode, + unsigned Reg1, unsigned Reg2, unsigned Reg3); + + void EmitMovFPIntPair(const MCSubtargetInfo &STI, unsigned MovOpc, + unsigned Reg1, unsigned Reg2, unsigned FPReg1, + unsigned FPReg2, bool LE); + + void EmitSwapFPIntParams(const MCSubtargetInfo &STI, + Mips16HardFloatInfo::FPParamVariant, bool LE, + bool ToFP); + + void EmitSwapFPIntRetval(const MCSubtargetInfo &STI, + Mips16HardFloatInfo::FPReturnVariant, bool LE); + + void EmitFPCallStub(const char *, const Mips16HardFloatInfo::FuncSignature *); + + void NaClAlignIndirectJumpTargets(MachineFunction &MF); + + bool isLongBranchPseudo(int Opcode) const; + +public: + + const MipsSubtarget *Subtarget; + const MipsFunctionInfo *MipsFI; + MipsMCInstLower MCInstLowering; + + explicit MipsAsmPrinter(TargetMachine &TM, + std::unique_ptr<MCStreamer> Streamer) + : AsmPrinter(TM, std::move(Streamer)), MCP(nullptr), + InConstantPool(false), MCInstLowering(*this) {} + + const char *getPassName() const override { + return "Mips Assembly Printer"; + } + + bool runOnMachineFunction(MachineFunction &MF) override; + + void EmitConstantPool() override { + bool UsingConstantPools = + (Subtarget->inMips16Mode() && Subtarget->useConstantIslands()); + if (!UsingConstantPools) + AsmPrinter::EmitConstantPool(); + // we emit constant pools customly! + } + + void EmitInstruction(const MachineInstr *MI) override; + void printSavedRegsBitmask(); + void emitFrameDirective(); + const char *getCurrentABIString() const; + void EmitFunctionEntryLabel() override; + void EmitFunctionBodyStart() override; + void EmitFunctionBodyEnd() override; + void EmitBasicBlockEnd(const MachineBasicBlock &MBB) override; + bool isBlockOnlyReachableByFallthrough( + const MachineBasicBlock* MBB) const override; + bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O) override; + bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O) override; + void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O); + void printUnsignedImm(const MachineInstr *MI, int opNum, raw_ostream &O); + void printUnsignedImm8(const MachineInstr *MI, int opNum, raw_ostream &O); + void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O); + void printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O); + void printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, + const char *Modifier = nullptr); + void printRegisterList(const MachineInstr *MI, int opNum, raw_ostream &O); + void EmitStartOfAsmFile(Module &M) override; + void EmitEndOfAsmFile(Module &M) override; + void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS); +}; +} + +#endif + diff --git a/contrib/llvm/lib/Target/Mips/MipsCCState.cpp b/contrib/llvm/lib/Target/Mips/MipsCCState.cpp new file mode 100644 index 0000000..d82063e --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsCCState.cpp @@ -0,0 +1,136 @@ +//===---- MipsCCState.cpp - CCState with Mips specific extensions ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsCCState.h" +#include "MipsSubtarget.h" +#include "llvm/IR/Module.h" + +using namespace llvm; + +/// This function returns true if CallSym is a long double emulation routine. +static bool isF128SoftLibCall(const char *CallSym) { + const char *const LibCalls[] = { + "__addtf3", "__divtf3", "__eqtf2", "__extenddftf2", + "__extendsftf2", "__fixtfdi", "__fixtfsi", "__fixtfti", + "__fixunstfdi", "__fixunstfsi", "__fixunstfti", "__floatditf", + "__floatsitf", "__floattitf", "__floatunditf", "__floatunsitf", + "__floatuntitf", "__getf2", "__gttf2", "__letf2", + "__lttf2", "__multf3", "__netf2", "__powitf2", + "__subtf3", "__trunctfdf2", "__trunctfsf2", "__unordtf2", + "ceill", "copysignl", "cosl", "exp2l", + "expl", "floorl", "fmal", "fmodl", + "log10l", "log2l", "logl", "nearbyintl", + "powl", "rintl", "sinl", "sqrtl", + "truncl"}; + + // Check that LibCalls is sorted alphabetically. + auto Comp = [](const char *S1, const char *S2) { return strcmp(S1, S2) < 0; }; + assert(std::is_sorted(std::begin(LibCalls), std::end(LibCalls), Comp)); + return std::binary_search(std::begin(LibCalls), std::end(LibCalls), + CallSym, Comp); +} + +/// This function returns true if Ty is fp128, {f128} or i128 which was +/// originally a fp128. +static bool originalTypeIsF128(Type *Ty, const SDNode *CallNode) { + if (Ty->isFP128Ty()) + return true; + + if (Ty->isStructTy() && Ty->getStructNumElements() == 1 && + Ty->getStructElementType(0)->isFP128Ty()) + return true; + + const ExternalSymbolSDNode *ES = + dyn_cast_or_null<const ExternalSymbolSDNode>(CallNode); + + // If the Ty is i128 and the function being called is a long double emulation + // routine, then the original type is f128. + return (ES && Ty->isIntegerTy(128) && isF128SoftLibCall(ES->getSymbol())); +} + +MipsCCState::SpecialCallingConvType +MipsCCState::getSpecialCallingConvForCallee(const SDNode *Callee, + const MipsSubtarget &Subtarget) { + MipsCCState::SpecialCallingConvType SpecialCallingConv = NoSpecialCallingConv; + if (Subtarget.inMips16HardFloat()) { + if (const GlobalAddressSDNode *G = + dyn_cast<const GlobalAddressSDNode>(Callee)) { + llvm::StringRef Sym = G->getGlobal()->getName(); + Function *F = G->getGlobal()->getParent()->getFunction(Sym); + if (F && F->hasFnAttribute("__Mips16RetHelper")) { + SpecialCallingConv = Mips16RetHelperConv; + } + } + } + return SpecialCallingConv; +} + +void MipsCCState::PreAnalyzeCallResultForF128( + const SmallVectorImpl<ISD::InputArg> &Ins, + const TargetLowering::CallLoweringInfo &CLI) { + for (unsigned i = 0; i < Ins.size(); ++i) { + OriginalArgWasF128.push_back( + originalTypeIsF128(CLI.RetTy, CLI.Callee.getNode())); + OriginalArgWasFloat.push_back(CLI.RetTy->isFloatingPointTy()); + } +} + +/// Identify lowered values that originated from f128 arguments and record +/// this for use by RetCC_MipsN. +void MipsCCState::PreAnalyzeReturnForF128( + const SmallVectorImpl<ISD::OutputArg> &Outs) { + const MachineFunction &MF = getMachineFunction(); + for (unsigned i = 0; i < Outs.size(); ++i) { + OriginalArgWasF128.push_back( + originalTypeIsF128(MF.getFunction()->getReturnType(), nullptr)); + OriginalArgWasFloat.push_back( + MF.getFunction()->getReturnType()->isFloatingPointTy()); + } +} + +/// Identify lowered values that originated from f128 arguments and record +/// this. +void MipsCCState::PreAnalyzeCallOperands( + const SmallVectorImpl<ISD::OutputArg> &Outs, + std::vector<TargetLowering::ArgListEntry> &FuncArgs, + const SDNode *CallNode) { + for (unsigned i = 0; i < Outs.size(); ++i) { + OriginalArgWasF128.push_back( + originalTypeIsF128(FuncArgs[Outs[i].OrigArgIndex].Ty, CallNode)); + OriginalArgWasFloat.push_back( + FuncArgs[Outs[i].OrigArgIndex].Ty->isFloatingPointTy()); + CallOperandIsFixed.push_back(Outs[i].IsFixed); + } +} + +/// Identify lowered values that originated from f128 arguments and record +/// this. +void MipsCCState::PreAnalyzeFormalArgumentsForF128( + const SmallVectorImpl<ISD::InputArg> &Ins) { + const MachineFunction &MF = getMachineFunction(); + for (unsigned i = 0; i < Ins.size(); ++i) { + Function::const_arg_iterator FuncArg = MF.getFunction()->arg_begin(); + + // SRet arguments cannot originate from f128 or {f128} returns so we just + // push false. We have to handle this specially since SRet arguments + // aren't mapped to an original argument. + if (Ins[i].Flags.isSRet()) { + OriginalArgWasF128.push_back(false); + OriginalArgWasFloat.push_back(false); + continue; + } + + assert(Ins[i].getOrigArgIndex() < MF.getFunction()->arg_size()); + std::advance(FuncArg, Ins[i].getOrigArgIndex()); + + OriginalArgWasF128.push_back( + originalTypeIsF128(FuncArg->getType(), nullptr)); + OriginalArgWasFloat.push_back(FuncArg->getType()->isFloatingPointTy()); + } +} diff --git a/contrib/llvm/lib/Target/Mips/MipsCCState.h b/contrib/llvm/lib/Target/Mips/MipsCCState.h new file mode 100644 index 0000000..081c393 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsCCState.h @@ -0,0 +1,136 @@ +//===---- MipsCCState.h - CCState with Mips specific extensions -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSCCSTATE_H +#define MIPSCCSTATE_H + +#include "MipsISelLowering.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/CallingConvLower.h" + +namespace llvm { +class SDNode; +class MipsSubtarget; + +class MipsCCState : public CCState { +public: + enum SpecialCallingConvType { Mips16RetHelperConv, NoSpecialCallingConv }; + + /// Determine the SpecialCallingConvType for the given callee + static SpecialCallingConvType + getSpecialCallingConvForCallee(const SDNode *Callee, + const MipsSubtarget &Subtarget); + +private: + /// Identify lowered values that originated from f128 arguments and record + /// this for use by RetCC_MipsN. + void PreAnalyzeCallResultForF128(const SmallVectorImpl<ISD::InputArg> &Ins, + const TargetLowering::CallLoweringInfo &CLI); + + /// Identify lowered values that originated from f128 arguments and record + /// this for use by RetCC_MipsN. + void PreAnalyzeReturnForF128(const SmallVectorImpl<ISD::OutputArg> &Outs); + + /// Identify lowered values that originated from f128 arguments and record + /// this. + void + PreAnalyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Outs, + std::vector<TargetLowering::ArgListEntry> &FuncArgs, + const SDNode *CallNode); + + /// Identify lowered values that originated from f128 arguments and record + /// this. + void + PreAnalyzeFormalArgumentsForF128(const SmallVectorImpl<ISD::InputArg> &Ins); + + /// Records whether the value has been lowered from an f128. + SmallVector<bool, 4> OriginalArgWasF128; + + /// Records whether the value has been lowered from float. + SmallVector<bool, 4> OriginalArgWasFloat; + + /// Records whether the value was a fixed argument. + /// See ISD::OutputArg::IsFixed, + SmallVector<bool, 4> CallOperandIsFixed; + + // Used to handle MIPS16-specific calling convention tweaks. + // FIXME: This should probably be a fully fledged calling convention. + SpecialCallingConvType SpecialCallingConv; + +public: + MipsCCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF, + SmallVectorImpl<CCValAssign> &locs, LLVMContext &C, + SpecialCallingConvType SpecialCC = NoSpecialCallingConv) + : CCState(CC, isVarArg, MF, locs, C), SpecialCallingConv(SpecialCC) {} + + void + AnalyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Outs, + CCAssignFn Fn, + std::vector<TargetLowering::ArgListEntry> &FuncArgs, + const SDNode *CallNode) { + PreAnalyzeCallOperands(Outs, FuncArgs, CallNode); + CCState::AnalyzeCallOperands(Outs, Fn); + OriginalArgWasF128.clear(); + OriginalArgWasFloat.clear(); + CallOperandIsFixed.clear(); + } + + // The AnalyzeCallOperands in the base class is not usable since we must + // provide a means of accessing ArgListEntry::IsFixed. Delete them from this + // class. This doesn't stop them being used via the base class though. + void AnalyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Outs, + CCAssignFn Fn) = delete; + void AnalyzeCallOperands(const SmallVectorImpl<MVT> &Outs, + SmallVectorImpl<ISD::ArgFlagsTy> &Flags, + CCAssignFn Fn) = delete; + + void AnalyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Ins, + CCAssignFn Fn) { + PreAnalyzeFormalArgumentsForF128(Ins); + CCState::AnalyzeFormalArguments(Ins, Fn); + OriginalArgWasFloat.clear(); + OriginalArgWasF128.clear(); + } + + void AnalyzeCallResult(const SmallVectorImpl<ISD::InputArg> &Ins, + CCAssignFn Fn, + const TargetLowering::CallLoweringInfo &CLI) { + PreAnalyzeCallResultForF128(Ins, CLI); + CCState::AnalyzeCallResult(Ins, Fn); + OriginalArgWasFloat.clear(); + OriginalArgWasF128.clear(); + } + + void AnalyzeReturn(const SmallVectorImpl<ISD::OutputArg> &Outs, + CCAssignFn Fn) { + PreAnalyzeReturnForF128(Outs); + CCState::AnalyzeReturn(Outs, Fn); + OriginalArgWasFloat.clear(); + OriginalArgWasF128.clear(); + } + + bool CheckReturn(const SmallVectorImpl<ISD::OutputArg> &ArgsFlags, + CCAssignFn Fn) { + PreAnalyzeReturnForF128(ArgsFlags); + bool Return = CCState::CheckReturn(ArgsFlags, Fn); + OriginalArgWasFloat.clear(); + OriginalArgWasF128.clear(); + return Return; + } + + bool WasOriginalArgF128(unsigned ValNo) { return OriginalArgWasF128[ValNo]; } + bool WasOriginalArgFloat(unsigned ValNo) { + return OriginalArgWasFloat[ValNo]; + } + bool IsCallOperandFixed(unsigned ValNo) { return CallOperandIsFixed[ValNo]; } + SpecialCallingConvType getSpecialCallingConv() { return SpecialCallingConv; } +}; +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsCallingConv.td b/contrib/llvm/lib/Target/Mips/MipsCallingConv.td new file mode 100644 index 0000000..0b4b778 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsCallingConv.td @@ -0,0 +1,454 @@ +//===-- MipsCallingConv.td - Calling Conventions for Mips --*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This describes the calling conventions for Mips architecture. +//===----------------------------------------------------------------------===// + +/// CCIfSubtarget - Match if the current subtarget has a feature F. +class CCIfSubtarget<string F, CCAction A, string Invert = ""> + : CCIf<!strconcat(Invert, + "static_cast<const MipsSubtarget&>" + "(State.getMachineFunction().getSubtarget()).", + F), + A>; + +// The inverse of CCIfSubtarget +class CCIfSubtargetNot<string F, CCAction A> : CCIfSubtarget<F, A, "!">; + +/// Match if the original argument (before lowering) was a float. +/// For example, this is true for i32's that were lowered from soft-float. +class CCIfOrigArgWasNotFloat<CCAction A> + : CCIf<"!static_cast<MipsCCState *>(&State)->WasOriginalArgFloat(ValNo)", + A>; + +/// Match if the original argument (before lowering) was a 128-bit float (i.e. +/// long double). +class CCIfOrigArgWasF128<CCAction A> + : CCIf<"static_cast<MipsCCState *>(&State)->WasOriginalArgF128(ValNo)", A>; + +/// Match if this specific argument is a vararg. +/// This is slightly different fro CCIfIsVarArg which matches if any argument is +/// a vararg. +class CCIfArgIsVarArg<CCAction A> + : CCIf<"!static_cast<MipsCCState *>(&State)->IsCallOperandFixed(ValNo)", A>; + + +/// Match if the special calling conv is the specified value. +class CCIfSpecialCallingConv<string CC, CCAction A> + : CCIf<"static_cast<MipsCCState *>(&State)->getSpecialCallingConv() == " + "MipsCCState::" # CC, A>; + +// For soft-float, f128 values are returned in A0_64 rather than V1_64. +def RetCC_F128SoftFloat : CallingConv<[ + CCAssignToReg<[V0_64, A0_64]> +]>; + +// For hard-float, f128 values are returned as a pair of f64's rather than a +// pair of i64's. +def RetCC_F128HardFloat : CallingConv<[ + CCBitConvertToType<f64>, + + // Contrary to the ABI documentation, a struct containing a long double is + // returned in $f0, and $f1 instead of the usual $f0, and $f2. This is to + // match the de facto ABI as implemented by GCC. + CCIfInReg<CCAssignToReg<[D0_64, D1_64]>>, + + CCAssignToReg<[D0_64, D2_64]> +]>; + +// Handle F128 specially since we can't identify the original type during the +// tablegen-erated code. +def RetCC_F128 : CallingConv<[ + CCIfSubtarget<"useSoftFloat()", + CCIfType<[i64], CCDelegateTo<RetCC_F128SoftFloat>>>, + CCIfSubtargetNot<"useSoftFloat()", + CCIfType<[i64], CCDelegateTo<RetCC_F128HardFloat>>> +]>; + +//===----------------------------------------------------------------------===// +// Mips O32 Calling Convention +//===----------------------------------------------------------------------===// + +def CC_MipsO32 : CallingConv<[ + // Promote i8/i16 arguments to i32. + CCIfType<[i1, i8, i16], CCPromoteToType<i32>>, + + // Integer values get stored in stack slots that are 4 bytes in + // size and 4-byte aligned. + CCIfType<[i32, f32], CCAssignToStack<4, 4>>, + + // Integer values get stored in stack slots that are 8 bytes in + // size and 8-byte aligned. + CCIfType<[f64], CCAssignToStack<8, 8>> +]>; + +// Only the return rules are defined here for O32. The rules for argument +// passing are defined in MipsISelLowering.cpp. +def RetCC_MipsO32 : CallingConv<[ + // Promote i1/i8/i16 return values to i32. + CCIfType<[i1, i8, i16], CCPromoteToType<i32>>, + + // i32 are returned in registers V0, V1, A0, A1 + CCIfType<[i32], CCAssignToReg<[V0, V1, A0, A1]>>, + + // f32 are returned in registers F0, F2 + CCIfType<[f32], CCAssignToReg<[F0, F2]>>, + + // f64 arguments are returned in D0_64 and D2_64 in FP64bit mode or + // in D0 and D1 in FP32bit mode. + CCIfType<[f64], CCIfSubtarget<"isFP64bit()", CCAssignToReg<[D0_64, D2_64]>>>, + CCIfType<[f64], CCIfSubtargetNot<"isFP64bit()", CCAssignToReg<[D0, D1]>>> +]>; + +def CC_MipsO32_FP32 : CustomCallingConv; +def CC_MipsO32_FP64 : CustomCallingConv; + +def CC_MipsO32_FP : CallingConv<[ + CCIfSubtargetNot<"isFP64bit()", CCDelegateTo<CC_MipsO32_FP32>>, + CCIfSubtarget<"isFP64bit()", CCDelegateTo<CC_MipsO32_FP64>> +]>; + +//===----------------------------------------------------------------------===// +// Mips N32/64 Calling Convention +//===----------------------------------------------------------------------===// + +def CC_MipsN_SoftFloat : CallingConv<[ + CCAssignToRegWithShadow<[A0, A1, A2, A3, + T0, T1, T2, T3], + [D12_64, D13_64, D14_64, D15_64, + D16_64, D17_64, D18_64, D19_64]>, + CCAssignToStack<4, 8> +]>; + +def CC_MipsN : CallingConv<[ + CCIfType<[i8, i16, i32, i64], + CCIfSubtargetNot<"isLittle()", + CCIfInReg<CCPromoteToUpperBitsInType<i64>>>>, + + // All integers (except soft-float integers) are promoted to 64-bit. + CCIfType<[i8, i16, i32], CCIfOrigArgWasNotFloat<CCPromoteToType<i64>>>, + + // The only i32's we have left are soft-float arguments. + CCIfSubtarget<"useSoftFloat()", CCIfType<[i32], CCDelegateTo<CC_MipsN_SoftFloat>>>, + + // Integer arguments are passed in integer registers. + CCIfType<[i64], CCAssignToRegWithShadow<[A0_64, A1_64, A2_64, A3_64, + T0_64, T1_64, T2_64, T3_64], + [D12_64, D13_64, D14_64, D15_64, + D16_64, D17_64, D18_64, D19_64]>>, + + // f32 arguments are passed in single precision FP registers. + CCIfType<[f32], CCAssignToRegWithShadow<[F12, F13, F14, F15, + F16, F17, F18, F19], + [A0_64, A1_64, A2_64, A3_64, + T0_64, T1_64, T2_64, T3_64]>>, + + // f64 arguments are passed in double precision FP registers. + CCIfType<[f64], CCAssignToRegWithShadow<[D12_64, D13_64, D14_64, D15_64, + D16_64, D17_64, D18_64, D19_64], + [A0_64, A1_64, A2_64, A3_64, + T0_64, T1_64, T2_64, T3_64]>>, + + // All stack parameter slots become 64-bit doublewords and are 8-byte aligned. + CCIfType<[f32], CCAssignToStack<4, 8>>, + CCIfType<[i64, f64], CCAssignToStack<8, 8>> +]>; + +// N32/64 variable arguments. +// All arguments are passed in integer registers. +def CC_MipsN_VarArg : CallingConv<[ + CCIfType<[i8, i16, i32, i64], + CCIfSubtargetNot<"isLittle()", + CCIfInReg<CCPromoteToUpperBitsInType<i64>>>>, + + // All integers are promoted to 64-bit. + CCIfType<[i8, i16, i32], CCPromoteToType<i64>>, + + CCIfType<[f32], CCAssignToReg<[A0, A1, A2, A3, T0, T1, T2, T3]>>, + + CCIfType<[i64, f64], CCAssignToReg<[A0_64, A1_64, A2_64, A3_64, + T0_64, T1_64, T2_64, T3_64]>>, + + // All stack parameter slots become 64-bit doublewords and are 8-byte aligned. + CCIfType<[f32], CCAssignToStack<4, 8>>, + CCIfType<[i64, f64], CCAssignToStack<8, 8>> +]>; + +def RetCC_MipsN : CallingConv<[ + // f128 needs to be handled similarly to f32 and f64. However, f128 is not + // legal and is lowered to i128 which is further lowered to a pair of i64's. + // This presents us with a problem for the calling convention since hard-float + // still needs to pass them in FPU registers, and soft-float needs to use $v0, + // and $a0 instead of the usual $v0, and $v1. We therefore resort to a + // pre-analyze (see PreAnalyzeReturnForF128()) step to pass information on + // whether the result was originally an f128 into the tablegen-erated code. + // + // f128 should only occur for the N64 ABI where long double is 128-bit. On + // N32, long double is equivalent to double. + CCIfType<[i64], CCIfOrigArgWasF128<CCDelegateTo<RetCC_F128>>>, + + // Aggregate returns are positioned at the lowest address in the slot for + // both little and big-endian targets. When passing in registers, this + // requires that big-endian targets shift the value into the upper bits. + CCIfSubtarget<"isLittle()", + CCIfType<[i8, i16, i32, i64], CCIfInReg<CCPromoteToType<i64>>>>, + CCIfSubtargetNot<"isLittle()", + CCIfType<[i8, i16, i32, i64], + CCIfInReg<CCPromoteToUpperBitsInType<i64>>>>, + + // i64 are returned in registers V0_64, V1_64 + CCIfType<[i64], CCAssignToReg<[V0_64, V1_64]>>, + + // f32 are returned in registers F0, F2 + CCIfType<[f32], CCAssignToReg<[F0, F2]>>, + + // f64 are returned in registers D0, D2 + CCIfType<[f64], CCAssignToReg<[D0_64, D2_64]>> +]>; + +//===----------------------------------------------------------------------===// +// Mips EABI Calling Convention +//===----------------------------------------------------------------------===// + +def CC_MipsEABI : CallingConv<[ + // Promote i8/i16 arguments to i32. + CCIfType<[i8, i16], CCPromoteToType<i32>>, + + // Integer arguments are passed in integer registers. + CCIfType<[i32], CCAssignToReg<[A0, A1, A2, A3, T0, T1, T2, T3]>>, + + // Single fp arguments are passed in pairs within 32-bit mode + CCIfType<[f32], CCIfSubtarget<"isSingleFloat()", + CCAssignToReg<[F12, F13, F14, F15, F16, F17, F18, F19]>>>, + + CCIfType<[f32], CCIfSubtargetNot<"isSingleFloat()", + CCAssignToReg<[F12, F14, F16, F18]>>>, + + // The first 4 double fp arguments are passed in single fp registers. + CCIfType<[f64], CCIfSubtargetNot<"isSingleFloat()", + CCAssignToReg<[D6, D7, D8, D9]>>>, + + // Integer values get stored in stack slots that are 4 bytes in + // size and 4-byte aligned. + CCIfType<[i32, f32], CCAssignToStack<4, 4>>, + + // Integer values get stored in stack slots that are 8 bytes in + // size and 8-byte aligned. + CCIfType<[f64], CCIfSubtargetNot<"isSingleFloat()", CCAssignToStack<8, 8>>> +]>; + +def RetCC_MipsEABI : CallingConv<[ + // i32 are returned in registers V0, V1 + CCIfType<[i32], CCAssignToReg<[V0, V1]>>, + + // f32 are returned in registers F0, F1 + CCIfType<[f32], CCAssignToReg<[F0, F1]>>, + + // f64 are returned in register D0 + CCIfType<[f64], CCIfSubtargetNot<"isSingleFloat()", CCAssignToReg<[D0]>>> +]>; + +//===----------------------------------------------------------------------===// +// Mips FastCC Calling Convention +//===----------------------------------------------------------------------===// +def CC_MipsO32_FastCC : CallingConv<[ + // f64 arguments are passed in double-precision floating pointer registers. + CCIfType<[f64], CCIfSubtargetNot<"isFP64bit()", + CCAssignToReg<[D0, D1, D2, D3, D4, D5, D6, + D7, D8, D9]>>>, + CCIfType<[f64], CCIfSubtarget<"isFP64bit()", CCIfSubtarget<"useOddSPReg()", + CCAssignToReg<[D0_64, D1_64, D2_64, D3_64, + D4_64, D5_64, D6_64, D7_64, + D8_64, D9_64, D10_64, D11_64, + D12_64, D13_64, D14_64, D15_64, + D16_64, D17_64, D18_64, + D19_64]>>>>, + CCIfType<[f64], CCIfSubtarget<"isFP64bit()", CCIfSubtarget<"noOddSPReg()", + CCAssignToReg<[D0_64, D2_64, D4_64, D6_64, + D8_64, D10_64, D12_64, D14_64, + D16_64, D18_64]>>>>, + + // Stack parameter slots for f64 are 64-bit doublewords and 8-byte aligned. + CCIfType<[f64], CCAssignToStack<8, 8>> +]>; + +def CC_MipsN_FastCC : CallingConv<[ + // Integer arguments are passed in integer registers. + CCIfType<[i64], CCAssignToReg<[A0_64, A1_64, A2_64, A3_64, T0_64, T1_64, + T2_64, T3_64, T4_64, T5_64, T6_64, T7_64, + T8_64, V1_64]>>, + + // f64 arguments are passed in double-precision floating pointer registers. + CCIfType<[f64], CCAssignToReg<[D0_64, D1_64, D2_64, D3_64, D4_64, D5_64, + D6_64, D7_64, D8_64, D9_64, D10_64, D11_64, + D12_64, D13_64, D14_64, D15_64, D16_64, D17_64, + D18_64, D19_64]>>, + + // Stack parameter slots for i64 and f64 are 64-bit doublewords and + // 8-byte aligned. + CCIfType<[i64, f64], CCAssignToStack<8, 8>> +]>; + +def CC_Mips_FastCC : CallingConv<[ + // Handles byval parameters. + CCIfByVal<CCPassByVal<4, 4>>, + + // Promote i8/i16 arguments to i32. + CCIfType<[i8, i16], CCPromoteToType<i32>>, + + // Integer arguments are passed in integer registers. All scratch registers, + // except for AT, V0 and T9, are available to be used as argument registers. + CCIfType<[i32], CCIfSubtargetNot<"isTargetNaCl()", + 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], CCIfSubtarget<"useOddSPReg()", + CCAssignToReg<[F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, + F14, F15, F16, F17, F18, F19]>>>, + + // Don't use odd numbered single-precision registers for -mno-odd-spreg. + CCIfType<[f32], CCIfSubtarget<"noOddSPReg()", + CCAssignToReg<[F0, F2, F4, F6, F8, F10, F12, F14, F16, F18]>>>, + + // Stack parameter slots for i32 and f32 are 32-bit words and 4-byte aligned. + CCIfType<[i32, f32], CCAssignToStack<4, 4>>, + + CCIfSubtarget<"isABI_EABI()", CCDelegateTo<CC_MipsEABI>>, + CCIfSubtarget<"isABI_O32()", CCDelegateTo<CC_MipsO32_FastCC>>, + CCDelegateTo<CC_MipsN_FastCC> +]>; + +//===----------------------------------------------------------------------===// +// Mips Calling Convention Dispatch +//===----------------------------------------------------------------------===// + +def RetCC_Mips : CallingConv<[ + CCIfSubtarget<"isABI_EABI()", CCDelegateTo<RetCC_MipsEABI>>, + CCIfSubtarget<"isABI_N32()", CCDelegateTo<RetCC_MipsN>>, + CCIfSubtarget<"isABI_N64()", CCDelegateTo<RetCC_MipsN>>, + CCDelegateTo<RetCC_MipsO32> +]>; + +def CC_Mips_ByVal : CallingConv<[ + CCIfSubtarget<"isABI_O32()", CCIfByVal<CCPassByVal<4, 4>>>, + CCIfByVal<CCPassByVal<8, 8>> +]>; + +def CC_Mips16RetHelper : CallingConv<[ + CCIfByVal<CCDelegateTo<CC_Mips_ByVal>>, + + // Integer arguments are passed in integer registers. + CCIfType<[i32], CCAssignToReg<[V0, V1, A0, A1]>> +]>; + +def CC_Mips_FixedArg : CallingConv<[ + // Mips16 needs special handling on some functions. + CCIf<"State.getCallingConv() != CallingConv::Fast", + CCIfSpecialCallingConv<"Mips16RetHelperConv", + CCDelegateTo<CC_Mips16RetHelper>>>, + + CCIfByVal<CCDelegateTo<CC_Mips_ByVal>>, + + // f128 needs to be handled similarly to f32 and f64 on hard-float. However, + // f128 is not legal and is lowered to i128 which is further lowered to a pair + // of i64's. + // This presents us with a problem for the calling convention since hard-float + // still needs to pass them in FPU registers. We therefore resort to a + // pre-analyze (see PreAnalyzeFormalArgsForF128()) step to pass information on + // whether the argument was originally an f128 into the tablegen-erated code. + // + // f128 should only occur for the N64 ABI where long double is 128-bit. On + // N32, long double is equivalent to double. + CCIfType<[i64], + CCIfSubtargetNot<"useSoftFloat()", + CCIfOrigArgWasF128<CCBitConvertToType<f64>>>>, + + CCIfCC<"CallingConv::Fast", CCDelegateTo<CC_Mips_FastCC>>, + + // FIXME: There wasn't an EABI case in the original code and it seems unlikely + // that it's the same as CC_MipsN + CCIfSubtarget<"isABI_O32()", CCDelegateTo<CC_MipsO32_FP>>, + CCDelegateTo<CC_MipsN> +]>; + +def CC_Mips_VarArg : CallingConv<[ + CCIfByVal<CCDelegateTo<CC_Mips_ByVal>>, + + // FIXME: There wasn't an EABI case in the original code and it seems unlikely + // that it's the same as CC_MipsN_VarArg + CCIfSubtarget<"isABI_O32()", CCDelegateTo<CC_MipsO32_FP>>, + CCDelegateTo<CC_MipsN_VarArg> +]>; + +def CC_Mips : CallingConv<[ + CCIfVarArg<CCIfArgIsVarArg<CCDelegateTo<CC_Mips_VarArg>>>, + CCDelegateTo<CC_Mips_FixedArg> +]>; + +//===----------------------------------------------------------------------===// +// Callee-saved register lists. +//===----------------------------------------------------------------------===// + +def CSR_SingleFloatOnly : CalleeSavedRegs<(add (sequence "F%u", 31, 20), RA, FP, + (sequence "S%u", 7, 0))>; + +def CSR_O32_FPXX : CalleeSavedRegs<(add (sequence "D%u", 15, 10), RA, FP, + (sequence "S%u", 7, 0))> { + let OtherPreserved = (add (decimate (sequence "F%u", 30, 20), 2)); +} + +def CSR_O32 : CalleeSavedRegs<(add (sequence "D%u", 15, 10), RA, FP, + (sequence "S%u", 7, 0))>; + +def CSR_O32_FP64 : + CalleeSavedRegs<(add (decimate (sequence "D%u_64", 30, 20), 2), RA, FP, + (sequence "S%u", 7, 0))>; + +def CSR_N32 : CalleeSavedRegs<(add D20_64, D22_64, D24_64, D26_64, D28_64, + D30_64, RA_64, FP_64, GP_64, + (sequence "S%u_64", 7, 0))>; + +def CSR_N64 : CalleeSavedRegs<(add (sequence "D%u_64", 31, 24), RA_64, FP_64, + GP_64, (sequence "S%u_64", 7, 0))>; + +def CSR_Mips16RetHelper : + CalleeSavedRegs<(add V0, V1, FP, + (sequence "A%u", 3, 0), (sequence "S%u", 7, 0), + (sequence "D%u", 15, 10))>; + +def CSR_Interrupt_32R6 : CalleeSavedRegs<(add (sequence "A%u", 3, 0), + (sequence "S%u", 7, 0), + (sequence "V%u", 1, 0), + (sequence "T%u", 9, 0), + RA, FP, GP, AT)>; + +def CSR_Interrupt_32 : CalleeSavedRegs<(add (sequence "A%u", 3, 0), + (sequence "S%u", 7, 0), + (sequence "V%u", 1, 0), + (sequence "T%u", 9, 0), + RA, FP, GP, AT, LO0, HI0)>; + +def CSR_Interrupt_64R6 : CalleeSavedRegs<(add (sequence "A%u_64", 3, 0), + (sequence "V%u_64", 1, 0), + (sequence "S%u_64", 7, 0), + (sequence "T%u_64", 9, 0), + RA_64, FP_64, GP_64, AT_64)>; + +def CSR_Interrupt_64 : CalleeSavedRegs<(add (sequence "A%u_64", 3, 0), + (sequence "S%u_64", 7, 0), + (sequence "T%u_64", 9, 0), + (sequence "V%u_64", 1, 0), + RA_64, FP_64, GP_64, AT_64, + LO0_64, HI0_64)>; diff --git a/contrib/llvm/lib/Target/Mips/MipsCondMov.td b/contrib/llvm/lib/Target/Mips/MipsCondMov.td new file mode 100644 index 0000000..2d96d9b --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsCondMov.td @@ -0,0 +1,303 @@ +//===-- MipsCondMov.td - Describe Mips Conditional Moves --*- tablegen -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is the Conditional Moves implementation. +// +//===----------------------------------------------------------------------===// + +// Conditional moves: +// These instructions are expanded in +// MipsISelLowering::EmitInstrWithCustomInserter if target does not have +// conditional move instructions. +// cond:int, data:int +class CMov_I_I_FT<string opstr, RegisterOperand CRC, RegisterOperand DRC, + InstrItinClass Itin> : + InstSE<(outs DRC:$rd), (ins DRC:$rs, CRC:$rt, DRC:$F), + !strconcat(opstr, "\t$rd, $rs, $rt"), [], Itin, FrmFR, opstr> { + let Constraints = "$F = $rd"; +} + +// cond:int, data:float +class CMov_I_F_FT<string opstr, RegisterOperand CRC, RegisterOperand DRC, + InstrItinClass Itin> : + InstSE<(outs DRC:$fd), (ins DRC:$fs, CRC:$rt, DRC:$F), + !strconcat(opstr, "\t$fd, $fs, $rt"), [], Itin, FrmFR, opstr>, + HARDFLOAT { + let Constraints = "$F = $fd"; +} + +// cond:float, data:int +class CMov_F_I_FT<string opstr, RegisterOperand RC, InstrItinClass Itin, + SDPatternOperator OpNode = null_frag> : + InstSE<(outs RC:$rd), (ins RC:$rs, FCCRegsOpnd:$fcc, RC:$F), + !strconcat(opstr, "\t$rd, $rs, $fcc"), + [(set RC:$rd, (OpNode RC:$rs, FCCRegsOpnd:$fcc, RC:$F))], + Itin, FrmFR, opstr>, HARDFLOAT { + let Constraints = "$F = $rd"; +} + +// cond:float, data:float +class CMov_F_F_FT<string opstr, RegisterOperand RC, InstrItinClass Itin, + SDPatternOperator OpNode = null_frag> : + InstSE<(outs RC:$fd), (ins RC:$fs, FCCRegsOpnd:$fcc, RC:$F), + !strconcat(opstr, "\t$fd, $fs, $fcc"), + [(set RC:$fd, (OpNode RC:$fs, FCCRegsOpnd:$fcc, RC:$F))], + Itin, FrmFR, opstr>, HARDFLOAT { + let Constraints = "$F = $fd"; +} + +// select patterns +multiclass MovzPats0<RegisterClass CRC, RegisterClass DRC, + Instruction MOVZInst, Instruction SLTOp, + Instruction SLTuOp, Instruction SLTiOp, + Instruction SLTiuOp> { + def : MipsPat<(select (i32 (setge CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTOp CRC:$lhs, CRC:$rhs), DRC:$F)>; + def : MipsPat<(select (i32 (setuge CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTuOp CRC:$lhs, CRC:$rhs), DRC:$F)>; + def : MipsPat<(select (i32 (setge CRC:$lhs, immSExt16:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTiOp CRC:$lhs, immSExt16:$rhs), DRC:$F)>; + def : MipsPat<(select (i32 (setuge CRC:$lh, immSExt16:$rh)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTiuOp CRC:$lh, immSExt16:$rh), DRC:$F)>; + def : MipsPat<(select (i32 (setle CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTOp CRC:$rhs, CRC:$lhs), DRC:$F)>; + def : MipsPat<(select (i32 (setule CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTuOp CRC:$rhs, CRC:$lhs), DRC:$F)>; + def : MipsPat<(select (i32 (setgt CRC:$lhs, immSExt16Plus1:$rhs)), + DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTiOp CRC:$lhs, (Plus1 imm:$rhs)), DRC:$F)>; + def : MipsPat<(select (i32 (setugt CRC:$lhs, immSExt16Plus1:$rhs)), + DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTiuOp CRC:$lhs, (Plus1 imm:$rhs)), + DRC:$F)>; +} + +multiclass MovzPats1<RegisterClass CRC, RegisterClass DRC, + Instruction MOVZInst, Instruction XOROp> { + def : MipsPat<(select (i32 (seteq CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (XOROp CRC:$lhs, CRC:$rhs), DRC:$F)>; + def : MipsPat<(select (i32 (seteq CRC:$lhs, 0)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, CRC:$lhs, DRC:$F)>; +} + +multiclass MovzPats2<RegisterClass CRC, RegisterClass DRC, + Instruction MOVZInst, Instruction XORiOp> { + def : MipsPat< + (select (i32 (seteq CRC:$lhs, immZExt16:$uimm16)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (XORiOp CRC:$lhs, immZExt16:$uimm16), DRC:$F)>; +} + +multiclass MovnPats<RegisterClass CRC, RegisterClass DRC, Instruction MOVNInst, + Instruction XOROp> { + def : MipsPat<(select (i32 (setne CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVNInst DRC:$T, (XOROp CRC:$lhs, CRC:$rhs), DRC:$F)>; + def : MipsPat<(select CRC:$cond, DRC:$T, DRC:$F), + (MOVNInst DRC:$T, CRC:$cond, DRC:$F)>; + def : MipsPat<(select (i32 (setne CRC:$lhs, 0)),DRC:$T, DRC:$F), + (MOVNInst DRC:$T, CRC:$lhs, DRC:$F)>; +} + +// Instantiation of instructions. +def MOVZ_I_I : MMRel, CMov_I_I_FT<"movz", GPR32Opnd, GPR32Opnd, II_MOVZ>, + ADD_FM<0, 0xa>, INSN_MIPS4_32_NOT_32R6_64R6; + +let isCodeGenOnly = 1 in { + def MOVZ_I_I64 : CMov_I_I_FT<"movz", GPR32Opnd, GPR64Opnd, II_MOVZ>, + ADD_FM<0, 0xa>, INSN_MIPS4_32_NOT_32R6_64R6; + def MOVZ_I64_I : CMov_I_I_FT<"movz", GPR64Opnd, GPR32Opnd, II_MOVZ>, + ADD_FM<0, 0xa>, INSN_MIPS4_32_NOT_32R6_64R6; + def MOVZ_I64_I64 : CMov_I_I_FT<"movz", GPR64Opnd, GPR64Opnd, II_MOVZ>, + ADD_FM<0, 0xa>, INSN_MIPS4_32_NOT_32R6_64R6; +} + +def MOVN_I_I : MMRel, CMov_I_I_FT<"movn", GPR32Opnd, GPR32Opnd, II_MOVN>, + ADD_FM<0, 0xb>, INSN_MIPS4_32_NOT_32R6_64R6; + +let isCodeGenOnly = 1 in { + def MOVN_I_I64 : CMov_I_I_FT<"movn", GPR32Opnd, GPR64Opnd, II_MOVN>, + ADD_FM<0, 0xb>, INSN_MIPS4_32_NOT_32R6_64R6; + def MOVN_I64_I : CMov_I_I_FT<"movn", GPR64Opnd, GPR32Opnd, II_MOVN>, + ADD_FM<0, 0xb>, INSN_MIPS4_32_NOT_32R6_64R6; + def MOVN_I64_I64 : CMov_I_I_FT<"movn", GPR64Opnd, GPR64Opnd, II_MOVN>, + ADD_FM<0, 0xb>, INSN_MIPS4_32_NOT_32R6_64R6; +} + +def MOVZ_I_S : MMRel, CMov_I_F_FT<"movz.s", GPR32Opnd, FGR32Opnd, II_MOVZ_S>, + CMov_I_F_FM<18, 16>, INSN_MIPS4_32_NOT_32R6_64R6; + +let isCodeGenOnly = 1 in +def MOVZ_I64_S : CMov_I_F_FT<"movz.s", GPR64Opnd, FGR32Opnd, II_MOVZ_S>, + CMov_I_F_FM<18, 16>, INSN_MIPS4_32_NOT_32R6_64R6, + AdditionalRequires<[HasMips64]>; + +def MOVN_I_S : MMRel, CMov_I_F_FT<"movn.s", GPR32Opnd, FGR32Opnd, II_MOVN_S>, + CMov_I_F_FM<19, 16>, INSN_MIPS4_32_NOT_32R6_64R6; + +let isCodeGenOnly = 1 in +def MOVN_I64_S : CMov_I_F_FT<"movn.s", GPR64Opnd, FGR32Opnd, II_MOVN_S>, + CMov_I_F_FM<19, 16>, INSN_MIPS4_32_NOT_32R6_64R6, + AdditionalRequires<[IsGP64bit]>; + +def MOVZ_I_D32 : MMRel, CMov_I_F_FT<"movz.d", GPR32Opnd, AFGR64Opnd, + II_MOVZ_D>, CMov_I_F_FM<18, 17>, + INSN_MIPS4_32_NOT_32R6_64R6, FGR_32; +def MOVN_I_D32 : MMRel, CMov_I_F_FT<"movn.d", GPR32Opnd, AFGR64Opnd, + II_MOVN_D>, CMov_I_F_FM<19, 17>, + INSN_MIPS4_32_NOT_32R6_64R6, FGR_32; + +let DecoderNamespace = "Mips64" in { + def MOVZ_I_D64 : CMov_I_F_FT<"movz.d", GPR32Opnd, FGR64Opnd, II_MOVZ_D>, + CMov_I_F_FM<18, 17>, INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; + def MOVN_I_D64 : CMov_I_F_FT<"movn.d", GPR32Opnd, FGR64Opnd, II_MOVN_D>, + CMov_I_F_FM<19, 17>, INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; + let isCodeGenOnly = 1 in { + def MOVZ_I64_D64 : CMov_I_F_FT<"movz.d", GPR64Opnd, FGR64Opnd, II_MOVZ_D>, + CMov_I_F_FM<18, 17>, INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; + def MOVN_I64_D64 : CMov_I_F_FT<"movn.d", GPR64Opnd, FGR64Opnd, II_MOVN_D>, + CMov_I_F_FM<19, 17>, INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; + } +} + +def MOVT_I : MMRel, CMov_F_I_FT<"movt", GPR32Opnd, II_MOVT, MipsCMovFP_T>, + CMov_F_I_FM<1>, INSN_MIPS4_32_NOT_32R6_64R6; + +let isCodeGenOnly = 1 in +def MOVT_I64 : CMov_F_I_FT<"movt", GPR64Opnd, II_MOVT, MipsCMovFP_T>, + CMov_F_I_FM<1>, INSN_MIPS4_32_NOT_32R6_64R6, + AdditionalRequires<[IsGP64bit]>; + +def MOVF_I : MMRel, CMov_F_I_FT<"movf", GPR32Opnd, II_MOVF, MipsCMovFP_F>, + CMov_F_I_FM<0>, INSN_MIPS4_32_NOT_32R6_64R6; + +let isCodeGenOnly = 1 in +def MOVF_I64 : CMov_F_I_FT<"movf", GPR64Opnd, II_MOVF, MipsCMovFP_F>, + CMov_F_I_FM<0>, INSN_MIPS4_32_NOT_32R6_64R6, + AdditionalRequires<[IsGP64bit]>; + +def MOVT_S : MMRel, CMov_F_F_FT<"movt.s", FGR32Opnd, II_MOVT_S, MipsCMovFP_T>, + CMov_F_F_FM<16, 1>, INSN_MIPS4_32_NOT_32R6_64R6; +def MOVF_S : MMRel, CMov_F_F_FT<"movf.s", FGR32Opnd, II_MOVF_S, MipsCMovFP_F>, + CMov_F_F_FM<16, 0>, INSN_MIPS4_32_NOT_32R6_64R6; + +def MOVT_D32 : MMRel, CMov_F_F_FT<"movt.d", AFGR64Opnd, II_MOVT_D, + MipsCMovFP_T>, CMov_F_F_FM<17, 1>, + INSN_MIPS4_32_NOT_32R6_64R6, FGR_32; +def MOVF_D32 : MMRel, CMov_F_F_FT<"movf.d", AFGR64Opnd, II_MOVF_D, + MipsCMovFP_F>, CMov_F_F_FM<17, 0>, + INSN_MIPS4_32_NOT_32R6_64R6, FGR_32; + +let DecoderNamespace = "Mips64" in { + def MOVT_D64 : CMov_F_F_FT<"movt.d", FGR64Opnd, II_MOVT_D, MipsCMovFP_T>, + CMov_F_F_FM<17, 1>, INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; + def MOVF_D64 : CMov_F_F_FT<"movf.d", FGR64Opnd, II_MOVF_D, MipsCMovFP_F>, + CMov_F_F_FM<17, 0>, INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; +} + +// Instantiation of conditional move patterns. +defm : MovzPats0<GPR32, GPR32, MOVZ_I_I, SLT, SLTu, SLTi, SLTiu>, + INSN_MIPS4_32_NOT_32R6_64R6; +defm : MovzPats1<GPR32, GPR32, MOVZ_I_I, XOR>, INSN_MIPS4_32_NOT_32R6_64R6; +defm : MovzPats2<GPR32, GPR32, MOVZ_I_I, XORi>, INSN_MIPS4_32_NOT_32R6_64R6; + +defm : MovzPats0<GPR32, GPR64, MOVZ_I_I64, SLT, SLTu, SLTi, SLTiu>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats0<GPR64, GPR32, MOVZ_I_I, SLT64, SLTu64, SLTi64, SLTiu64>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats0<GPR64, GPR64, MOVZ_I_I64, SLT64, SLTu64, SLTi64, SLTiu64>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats1<GPR32, GPR64, MOVZ_I_I64, XOR>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats1<GPR64, GPR32, MOVZ_I64_I, XOR64>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats1<GPR64, GPR64, MOVZ_I64_I64, XOR64>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats2<GPR32, GPR64, MOVZ_I_I64, XORi>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats2<GPR64, GPR32, MOVZ_I64_I, XORi64>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats2<GPR64, GPR64, MOVZ_I64_I64, XORi64>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; + +defm : MovnPats<GPR32, GPR32, MOVN_I_I, XOR>, INSN_MIPS4_32_NOT_32R6_64R6; + +defm : MovnPats<GPR32, GPR64, MOVN_I_I64, XOR>, INSN_MIPS4_32_NOT_32R6_64R6, + GPR_64; +defm : MovnPats<GPR64, GPR32, MOVN_I64_I, XOR64>, INSN_MIPS4_32_NOT_32R6_64R6, + GPR_64; +defm : MovnPats<GPR64, GPR64, MOVN_I64_I64, XOR64>, INSN_MIPS4_32_NOT_32R6_64R6, + GPR_64; + +defm : MovzPats0<GPR32, FGR32, MOVZ_I_S, SLT, SLTu, SLTi, SLTiu>, + INSN_MIPS4_32_NOT_32R6_64R6; +defm : MovzPats1<GPR32, FGR32, MOVZ_I_S, XOR>, INSN_MIPS4_32_NOT_32R6_64R6; +defm : MovnPats<GPR32, FGR32, MOVN_I_S, XOR>, INSN_MIPS4_32_NOT_32R6_64R6; + +defm : MovzPats0<GPR64, FGR32, MOVZ_I_S, SLT64, SLTu64, SLTi64, SLTiu64>, + INSN_MIPS4_32_NOT_32R6_64R6, GPR_64; +defm : MovzPats1<GPR64, FGR32, MOVZ_I64_S, XOR64>, INSN_MIPS4_32_NOT_32R6_64R6, + GPR_64; +defm : MovnPats<GPR64, FGR32, MOVN_I64_S, XOR64>, INSN_MIPS4_32_NOT_32R6_64R6, + GPR_64; + +defm : MovzPats0<GPR32, AFGR64, MOVZ_I_D32, SLT, SLTu, SLTi, SLTiu>, + INSN_MIPS4_32_NOT_32R6_64R6, FGR_32; +defm : MovzPats1<GPR32, AFGR64, MOVZ_I_D32, XOR>, INSN_MIPS4_32_NOT_32R6_64R6, + FGR_32; +defm : MovnPats<GPR32, AFGR64, MOVN_I_D32, XOR>, INSN_MIPS4_32_NOT_32R6_64R6, + FGR_32; + +defm : MovzPats0<GPR32, FGR64, MOVZ_I_D64, SLT, SLTu, SLTi, SLTiu>, + INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; +defm : MovzPats0<GPR64, FGR64, MOVZ_I_D64, SLT64, SLTu64, SLTi64, SLTiu64>, + INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; +defm : MovzPats1<GPR32, FGR64, MOVZ_I_D64, XOR>, INSN_MIPS4_32_NOT_32R6_64R6, + FGR_64; +defm : MovzPats1<GPR64, FGR64, MOVZ_I64_D64, XOR64>, + INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; +defm : MovnPats<GPR32, FGR64, MOVN_I_D64, XOR>, INSN_MIPS4_32_NOT_32R6_64R6, + FGR_64; +defm : MovnPats<GPR64, FGR64, MOVN_I64_D64, XOR64>, INSN_MIPS4_32_NOT_32R6_64R6, + FGR_64; + +// For targets that don't have conditional-move instructions +// we have to match SELECT nodes with pseudo instructions. +let usesCustomInserter = 1 in { + class Select_Pseudo<RegisterOperand RC> : + PseudoSE<(outs RC:$dst), (ins GPR32Opnd:$cond, RC:$T, RC:$F), + [(set RC:$dst, (select GPR32Opnd:$cond, RC:$T, RC:$F))]>, + ISA_MIPS1_NOT_4_32; + + class SelectFP_Pseudo_T<RegisterOperand RC> : + PseudoSE<(outs RC:$dst), (ins GPR32Opnd:$cond, RC:$T, RC:$F), + [(set RC:$dst, (MipsCMovFP_T RC:$T, GPR32Opnd:$cond, RC:$F))]>, + ISA_MIPS1_NOT_4_32; + + class SelectFP_Pseudo_F<RegisterOperand RC> : + PseudoSE<(outs RC:$dst), (ins GPR32Opnd:$cond, RC:$T, RC:$F), + [(set RC:$dst, (MipsCMovFP_F RC:$T, GPR32Opnd:$cond, RC:$F))]>, + ISA_MIPS1_NOT_4_32; +} + +def PseudoSELECT_I : Select_Pseudo<GPR32Opnd>; +def PseudoSELECT_I64 : Select_Pseudo<GPR64Opnd>; +def PseudoSELECT_S : Select_Pseudo<FGR32Opnd>; +def PseudoSELECT_D32 : Select_Pseudo<AFGR64Opnd>, FGR_32; +def PseudoSELECT_D64 : Select_Pseudo<FGR64Opnd>, FGR_64; + +def PseudoSELECTFP_T_I : SelectFP_Pseudo_T<GPR32Opnd>; +def PseudoSELECTFP_T_I64 : SelectFP_Pseudo_T<GPR64Opnd>; +def PseudoSELECTFP_T_S : SelectFP_Pseudo_T<FGR32Opnd>; +def PseudoSELECTFP_T_D32 : SelectFP_Pseudo_T<AFGR64Opnd>, FGR_32; +def PseudoSELECTFP_T_D64 : SelectFP_Pseudo_T<FGR64Opnd>, FGR_64; + +def PseudoSELECTFP_F_I : SelectFP_Pseudo_F<GPR32Opnd>; +def PseudoSELECTFP_F_I64 : SelectFP_Pseudo_F<GPR64Opnd>; +def PseudoSELECTFP_F_S : SelectFP_Pseudo_F<FGR32Opnd>; +def PseudoSELECTFP_F_D32 : SelectFP_Pseudo_F<AFGR64Opnd>, FGR_32; +def PseudoSELECTFP_F_D64 : SelectFP_Pseudo_F<FGR64Opnd>, FGR_64; diff --git a/contrib/llvm/lib/Target/Mips/MipsConstantIslandPass.cpp b/contrib/llvm/lib/Target/Mips/MipsConstantIslandPass.cpp new file mode 100644 index 0000000..ea8c587 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsConstantIslandPass.cpp @@ -0,0 +1,1713 @@ +//===-- MipsConstantIslandPass.cpp - Emit Pc Relative loads----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +// This pass is used to make Pc relative loads of constants. +// For now, only Mips16 will use this. +// +// Loading constants inline is expensive on Mips16 and it's in general better +// to place the constant nearby in code space and then it can be loaded with a +// simple 16 bit load instruction. +// +// The constants can be not just numbers but addresses of functions and labels. +// This can be particularly helpful in static relocation mode for embedded +// non-linux targets. +// +// + +#include "Mips.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "Mips16InstrInfo.h" +#include "MipsMachineFunction.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#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/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 <algorithm> + +using namespace llvm; + +#define DEBUG_TYPE "mips-constant-islands" + +STATISTIC(NumCPEs, "Number of constpool entries"); +STATISTIC(NumSplit, "Number of uncond branches inserted"); +STATISTIC(NumCBrFixed, "Number of cond branches fixed"); +STATISTIC(NumUBrFixed, "Number of uncond branches fixed"); + +// FIXME: This option should be removed once it has received sufficient testing. +static cl::opt<bool> +AlignConstantIslands("mips-align-constant-islands", cl::Hidden, cl::init(true), + cl::desc("Align constant islands in code")); + + +// Rather than do make check tests with huge amounts of code, we force +// the test to use this amount. +// +static cl::opt<int> ConstantIslandsSmallOffset( + "mips-constant-islands-small-offset", + cl::init(0), + cl::desc("Make small offsets be this amount for testing purposes"), + cl::Hidden); + +// +// For testing purposes we tell it to not use relaxed load forms so that it +// will split blocks. +// +static cl::opt<bool> NoLoadRelaxation( + "mips-constant-islands-no-load-relaxation", + cl::init(false), + cl::desc("Don't relax loads to long loads - for testing purposes"), + cl::Hidden); + +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 { + + + typedef MachineBasicBlock::iterator Iter; + typedef MachineBasicBlock::reverse_iterator ReverseIter; + + /// MipsConstantIslands - Due to limited PC-relative displacements, Mips + /// requires constant pool entries to be scattered among the instructions + /// inside a function. To do this, it completely ignores the normal LLVM + /// constant pool; instead, it places constants wherever it feels like with + /// special instructions. + /// + /// The terminology used in this pass includes: + /// Islands - Clumps of constants placed in the function. + /// Water - Potential places where an island could be formed. + /// CPE - A constant pool entry that has been placed somewhere, which + /// tracks a list of users. + + class MipsConstantIslands : public MachineFunctionPass { + + /// BasicBlockInfo - Information about the offset and size of a single + /// basic block. + struct BasicBlockInfo { + /// Offset - Distance from the beginning of the function to the beginning + /// of this basic block. + /// + /// Offsets are computed assuming worst case padding before an aligned + /// block. This means that subtracting basic block offsets always gives a + /// conservative estimate of the real distance which may be smaller. + /// + /// Because worst case padding is used, the computed offset of an aligned + /// block may not actually be aligned. + unsigned Offset; + + /// Size - Size of the basic block in bytes. If the block contains + /// inline assembly, this is a worst case estimate. + /// + /// The size does not include any alignment padding whether from the + /// beginning of the block, or from an aligned jump table at the end. + unsigned Size; + + // FIXME: ignore LogAlign for this patch + // + unsigned postOffset(unsigned LogAlign = 0) const { + unsigned PO = Offset + Size; + return PO; + } + + BasicBlockInfo() : Offset(0), Size(0) {} + + }; + + std::vector<BasicBlockInfo> BBInfo; + + /// WaterList - A sorted list of basic blocks where islands could be placed + /// (i.e. blocks that don't fall through to the following block, due + /// to a return, unreachable, or unconditional branch). + std::vector<MachineBasicBlock*> WaterList; + + /// NewWaterList - The subset of WaterList that was created since the + /// previous iteration by inserting unconditional branches. + SmallSet<MachineBasicBlock*, 4> NewWaterList; + + typedef std::vector<MachineBasicBlock*>::iterator water_iterator; + + /// CPUser - One user of a constant pool, keeping the machine instruction + /// pointer, the constant pool being referenced, and the max displacement + /// allowed from the instruction to the CP. The HighWaterMark records the + /// highest basic block where a new CPEntry can be placed. To ensure this + /// pass terminates, the CP entries are initially placed at the end of the + /// function and then move monotonically to lower addresses. The + /// exception to this rule is when the current CP entry for a particular + /// CPUser is out of range, but there is another CP entry for the same + /// constant value in range. We want to use the existing in-range CP + /// entry, but if it later moves out of range, the search for new water + /// should resume where it left off. The HighWaterMark is used to record + /// that point. + struct CPUser { + MachineInstr *MI; + MachineInstr *CPEMI; + MachineBasicBlock *HighWaterMark; + private: + unsigned MaxDisp; + unsigned LongFormMaxDisp; // mips16 has 16/32 bit instructions + // with different displacements + unsigned LongFormOpcode; + public: + bool NegOk; + CPUser(MachineInstr *mi, MachineInstr *cpemi, unsigned maxdisp, + bool neg, + unsigned longformmaxdisp, unsigned longformopcode) + : MI(mi), CPEMI(cpemi), MaxDisp(maxdisp), + LongFormMaxDisp(longformmaxdisp), LongFormOpcode(longformopcode), + NegOk(neg){ + HighWaterMark = CPEMI->getParent(); + } + /// getMaxDisp - Returns the maximum displacement supported by MI. + unsigned getMaxDisp() const { + unsigned xMaxDisp = ConstantIslandsSmallOffset? + ConstantIslandsSmallOffset: MaxDisp; + return xMaxDisp; + } + void setMaxDisp(unsigned val) { + MaxDisp = val; + } + unsigned getLongFormMaxDisp() const { + return LongFormMaxDisp; + } + unsigned getLongFormOpcode() const { + return LongFormOpcode; + } + }; + + /// CPUsers - Keep track of all of the machine instructions that use various + /// constant pools and their max displacement. + std::vector<CPUser> CPUsers; + + /// CPEntry - One per constant pool entry, keeping the machine instruction + /// pointer, the constpool index, and the number of CPUser's which + /// reference this entry. + struct CPEntry { + MachineInstr *CPEMI; + unsigned CPI; + unsigned RefCount; + CPEntry(MachineInstr *cpemi, unsigned cpi, unsigned rc = 0) + : CPEMI(cpemi), CPI(cpi), RefCount(rc) {} + }; + + /// CPEntries - Keep track of all of the constant pool entry machine + /// instructions. For each original constpool index (i.e. those that + /// existed upon entry to this pass), it keeps a vector of entries. + /// Original elements are cloned as we go along; the clones are + /// put in the vector of the original element, but have distinct CPIs. + std::vector<std::vector<CPEntry> > CPEntries; + + /// ImmBranch - One per immediate branch, keeping the machine instruction + /// pointer, conditional or unconditional, the max displacement, + /// and (if isCond is true) the corresponding unconditional branch + /// opcode. + struct ImmBranch { + MachineInstr *MI; + unsigned MaxDisp : 31; + bool isCond : 1; + int UncondBr; + ImmBranch(MachineInstr *mi, unsigned maxdisp, bool cond, int ubr) + : MI(mi), MaxDisp(maxdisp), isCond(cond), UncondBr(ubr) {} + }; + + /// ImmBranches - Keep track of all the immediate branch instructions. + /// + std::vector<ImmBranch> ImmBranches; + + /// HasFarJump - True if any far jump instruction has been emitted during + /// the branch fix up pass. + bool HasFarJump; + + const TargetMachine &TM; + bool IsPIC; + const MipsSubtarget *STI; + const Mips16InstrInfo *TII; + MipsFunctionInfo *MFI; + MachineFunction *MF; + MachineConstantPool *MCP; + + unsigned PICLabelUId; + bool PrescannedForConstants; + + void initPICLabelUId(unsigned UId) { + PICLabelUId = UId; + } + + + unsigned createPICLabelUId() { + return PICLabelUId++; + } + + public: + static char ID; + MipsConstantIslands(TargetMachine &tm) + : MachineFunctionPass(ID), TM(tm), + IsPIC(TM.getRelocationModel() == Reloc::PIC_), STI(nullptr), + MF(nullptr), MCP(nullptr), PrescannedForConstants(false) {} + + const char *getPassName() const override { + return "Mips Constant Islands"; + } + + bool runOnMachineFunction(MachineFunction &F) override; + + void doInitialPlacement(std::vector<MachineInstr*> &CPEMIs); + CPEntry *findConstPoolEntry(unsigned CPI, const MachineInstr *CPEMI); + unsigned getCPELogAlign(const MachineInstr *CPEMI); + void initializeFunctionInfo(const std::vector<MachineInstr*> &CPEMIs); + unsigned getOffsetOf(MachineInstr *MI) const; + unsigned getUserOffset(CPUser&) const; + void dumpBBs(); + + bool isOffsetInRange(unsigned UserOffset, unsigned TrialOffset, + unsigned Disp, bool NegativeOK); + bool isOffsetInRange(unsigned UserOffset, unsigned TrialOffset, + const CPUser &U); + + void computeBlockSize(MachineBasicBlock *MBB); + MachineBasicBlock *splitBlockBeforeInstr(MachineInstr *MI); + void updateForInsertedWaterBlock(MachineBasicBlock *NewBB); + void adjustBBOffsetsAfter(MachineBasicBlock *BB); + bool decrementCPEReferenceCount(unsigned CPI, MachineInstr* CPEMI); + int findInRangeCPEntry(CPUser& U, unsigned UserOffset); + int findLongFormInRangeCPEntry(CPUser& U, unsigned UserOffset); + bool findAvailableWater(CPUser&U, unsigned UserOffset, + water_iterator &WaterIter); + void createNewWater(unsigned CPUserIndex, unsigned UserOffset, + MachineBasicBlock *&NewMBB); + bool handleConstantPoolUser(unsigned CPUserIndex); + void removeDeadCPEMI(MachineInstr *CPEMI); + bool removeUnusedCPEntries(); + bool isCPEntryInRange(MachineInstr *MI, unsigned UserOffset, + MachineInstr *CPEMI, unsigned Disp, bool NegOk, + bool DoDump = false); + bool isWaterInRange(unsigned UserOffset, MachineBasicBlock *Water, + CPUser &U, unsigned &Growth); + bool isBBInRange(MachineInstr *MI, MachineBasicBlock *BB, unsigned Disp); + bool fixupImmediateBr(ImmBranch &Br); + bool fixupConditionalBr(ImmBranch &Br); + bool fixupUnconditionalBr(ImmBranch &Br); + + void prescanForConstants(); + + private: + + }; + + char MipsConstantIslands::ID = 0; +} // end of anonymous namespace + +bool MipsConstantIslands::isOffsetInRange + (unsigned UserOffset, unsigned TrialOffset, + const CPUser &U) { + return isOffsetInRange(UserOffset, TrialOffset, + U.getMaxDisp(), U.NegOk); +} +/// print block size and offset information - debugging +void MipsConstantIslands::dumpBBs() { + DEBUG({ + for (unsigned J = 0, E = BBInfo.size(); J !=E; ++J) { + const BasicBlockInfo &BBI = BBInfo[J]; + dbgs() << format("%08x BB#%u\t", BBI.Offset, J) + << format(" size=%#x\n", BBInfo[J].Size); + } + }); +} +/// createMipsLongBranchPass - Returns a pass that converts branches to long +/// branches. +FunctionPass *llvm::createMipsConstantIslandPass(MipsTargetMachine &tm) { + return new MipsConstantIslands(tm); +} + +bool MipsConstantIslands::runOnMachineFunction(MachineFunction &mf) { + // The intention is for this to be a mips16 only pass for now + // FIXME: + MF = &mf; + MCP = mf.getConstantPool(); + STI = &static_cast<const MipsSubtarget &>(mf.getSubtarget()); + DEBUG(dbgs() << "constant island machine function " << "\n"); + if (!STI->inMips16Mode() || !MipsSubtarget::useConstantIslands()) { + return false; + } + TII = (const Mips16InstrInfo *)STI->getInstrInfo(); + MFI = MF->getInfo<MipsFunctionInfo>(); + DEBUG(dbgs() << "constant island processing " << "\n"); + // + // will need to make predermination if there is any constants we need to + // put in constant islands. TBD. + // + if (!PrescannedForConstants) prescanForConstants(); + + HasFarJump = false; + // This pass invalidates liveness information when it splits basic blocks. + MF->getRegInfo().invalidateLiveness(); + + // Renumber all of the machine basic blocks in the function, guaranteeing that + // the numbers agree with the position of the block in the function. + MF->RenumberBlocks(); + + bool MadeChange = false; + + // Perform the initial placement of the constant pool entries. To start with, + // we put them all at the end of the function. + std::vector<MachineInstr*> CPEMIs; + if (!MCP->isEmpty()) + doInitialPlacement(CPEMIs); + + /// The next UID to take is the first unused one. + initPICLabelUId(CPEMIs.size()); + + // Do the initial scan of the function, building up information about the + // sizes of each block, the location of all the water, and finding all of the + // constant pool users. + initializeFunctionInfo(CPEMIs); + CPEMIs.clear(); + DEBUG(dumpBBs()); + + /// Remove dead constant pool entries. + MadeChange |= removeUnusedCPEntries(); + + // Iteratively place constant pool entries and fix up branches until there + // is no change. + unsigned NoCPIters = 0, NoBRIters = 0; + (void)NoBRIters; + while (true) { + DEBUG(dbgs() << "Beginning CP iteration #" << NoCPIters << '\n'); + bool CPChange = false; + for (unsigned i = 0, e = CPUsers.size(); i != e; ++i) + CPChange |= handleConstantPoolUser(i); + if (CPChange && ++NoCPIters > 30) + report_fatal_error("Constant Island pass failed to converge!"); + DEBUG(dumpBBs()); + + // Clear NewWaterList now. If we split a block for branches, it should + // appear as "new water" for the next iteration of constant pool placement. + NewWaterList.clear(); + + DEBUG(dbgs() << "Beginning BR iteration #" << NoBRIters << '\n'); + bool BRChange = false; + for (unsigned i = 0, e = ImmBranches.size(); i != e; ++i) + BRChange |= fixupImmediateBr(ImmBranches[i]); + if (BRChange && ++NoBRIters > 30) + report_fatal_error("Branch Fix Up pass failed to converge!"); + DEBUG(dumpBBs()); + if (!CPChange && !BRChange) + break; + MadeChange = true; + } + + DEBUG(dbgs() << '\n'; dumpBBs()); + + BBInfo.clear(); + WaterList.clear(); + CPUsers.clear(); + CPEntries.clear(); + ImmBranches.clear(); + return MadeChange; +} + +/// doInitialPlacement - Perform the initial placement of the constant pool +/// entries. To start with, we put them all at the end of the function. +void +MipsConstantIslands::doInitialPlacement(std::vector<MachineInstr*> &CPEMIs) { + // Create the basic block to hold the CPE's. + MachineBasicBlock *BB = MF->CreateMachineBasicBlock(); + MF->push_back(BB); + + + // MachineConstantPool measures alignment in bytes. We measure in log2(bytes). + unsigned MaxAlign = Log2_32(MCP->getConstantPoolAlignment()); + + // Mark the basic block as required by the const-pool. + // If AlignConstantIslands isn't set, use 4-byte alignment for everything. + BB->setAlignment(AlignConstantIslands ? MaxAlign : 2); + + // The function needs to be as aligned as the basic blocks. The linker may + // move functions around based on their alignment. + MF->ensureAlignment(BB->getAlignment()); + + // Order the entries in BB by descending alignment. That ensures correct + // alignment of all entries as long as BB is sufficiently aligned. Keep + // track of the insertion point for each alignment. We are going to bucket + // sort the entries as they are created. + SmallVector<MachineBasicBlock::iterator, 8> InsPoint(MaxAlign + 1, BB->end()); + + // Add all of the constants from the constant pool to the end block, use an + // identity mapping of CPI's to CPE's. + const std::vector<MachineConstantPoolEntry> &CPs = MCP->getConstants(); + + const DataLayout &TD = MF->getDataLayout(); + for (unsigned i = 0, e = CPs.size(); i != e; ++i) { + unsigned Size = TD.getTypeAllocSize(CPs[i].getType()); + assert(Size >= 4 && "Too small constant pool entry"); + unsigned Align = CPs[i].getAlignment(); + assert(isPowerOf2_32(Align) && "Invalid alignment"); + // Verify that all constant pool entries are a multiple of their alignment. + // If not, we would have to pad them out so that instructions stay aligned. + assert((Size % Align) == 0 && "CP Entry not multiple of 4 bytes!"); + + // Insert CONSTPOOL_ENTRY before entries with a smaller alignment. + unsigned LogAlign = Log2_32(Align); + MachineBasicBlock::iterator InsAt = InsPoint[LogAlign]; + + MachineInstr *CPEMI = + BuildMI(*BB, InsAt, DebugLoc(), TII->get(Mips::CONSTPOOL_ENTRY)) + .addImm(i).addConstantPoolIndex(i).addImm(Size); + + CPEMIs.push_back(CPEMI); + + // Ensure that future entries with higher alignment get inserted before + // CPEMI. This is bucket sort with iterators. + for (unsigned a = LogAlign + 1; a <= MaxAlign; ++a) + if (InsPoint[a] == InsAt) + InsPoint[a] = CPEMI; + // Add a new CPEntry, but no corresponding CPUser yet. + CPEntries.emplace_back(1, CPEntry(CPEMI, i)); + ++NumCPEs; + DEBUG(dbgs() << "Moved CPI#" << i << " to end of function, size = " + << Size << ", align = " << Align <<'\n'); + } + DEBUG(BB->dump()); +} + +/// BBHasFallthrough - Return true if the specified basic block can fallthrough +/// into the block immediately after it. +static bool BBHasFallthrough(MachineBasicBlock *MBB) { + // Get the next machine basic block in the function. + MachineFunction::iterator MBBI = MBB->getIterator(); + // Can't fall off end of function. + if (std::next(MBBI) == MBB->getParent()->end()) + return false; + + MachineBasicBlock *NextBB = &*std::next(MBBI); + for (MachineBasicBlock::succ_iterator I = MBB->succ_begin(), + E = MBB->succ_end(); I != E; ++I) + if (*I == NextBB) + return true; + + return false; +} + +/// findConstPoolEntry - Given the constpool index and CONSTPOOL_ENTRY MI, +/// look up the corresponding CPEntry. +MipsConstantIslands::CPEntry +*MipsConstantIslands::findConstPoolEntry(unsigned CPI, + const MachineInstr *CPEMI) { + std::vector<CPEntry> &CPEs = CPEntries[CPI]; + // Number of entries per constpool index should be small, just do a + // linear search. + for (unsigned i = 0, e = CPEs.size(); i != e; ++i) { + if (CPEs[i].CPEMI == CPEMI) + return &CPEs[i]; + } + return nullptr; +} + +/// getCPELogAlign - Returns the required alignment of the constant pool entry +/// represented by CPEMI. Alignment is measured in log2(bytes) units. +unsigned MipsConstantIslands::getCPELogAlign(const MachineInstr *CPEMI) { + assert(CPEMI && CPEMI->getOpcode() == Mips::CONSTPOOL_ENTRY); + + // Everything is 4-byte aligned unless AlignConstantIslands is set. + if (!AlignConstantIslands) + return 2; + + unsigned CPI = CPEMI->getOperand(1).getIndex(); + assert(CPI < MCP->getConstants().size() && "Invalid constant pool index."); + unsigned Align = MCP->getConstants()[CPI].getAlignment(); + assert(isPowerOf2_32(Align) && "Invalid CPE alignment"); + return Log2_32(Align); +} + +/// initializeFunctionInfo - Do the initial scan of the function, building up +/// information about the sizes of each block, the location of all the water, +/// and finding all of the constant pool users. +void MipsConstantIslands:: +initializeFunctionInfo(const std::vector<MachineInstr*> &CPEMIs) { + BBInfo.clear(); + BBInfo.resize(MF->getNumBlockIDs()); + + // First thing, compute the size of all basic blocks, and see if the function + // has any inline assembly in it. If so, we have to be conservative about + // alignment assumptions, as we don't know for sure the size of any + // instructions in the inline assembly. + for (MachineFunction::iterator I = MF->begin(), E = MF->end(); I != E; ++I) + computeBlockSize(&*I); + + + // Compute block offsets. + adjustBBOffsetsAfter(&MF->front()); + + // Now go back through the instructions and build up our data structures. + for (MachineFunction::iterator MBBI = MF->begin(), E = MF->end(); + MBBI != E; ++MBBI) { + MachineBasicBlock &MBB = *MBBI; + + // If this block doesn't fall through into the next MBB, then this is + // 'water' that a constant pool island could be placed. + if (!BBHasFallthrough(&MBB)) + WaterList.push_back(&MBB); + for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); + I != E; ++I) { + if (I->isDebugValue()) + continue; + + int Opc = I->getOpcode(); + if (I->isBranch()) { + bool isCond = false; + unsigned Bits = 0; + unsigned Scale = 1; + int UOpc = Opc; + switch (Opc) { + default: + continue; // Ignore other branches for now + case Mips::Bimm16: + Bits = 11; + Scale = 2; + isCond = false; + break; + case Mips::BimmX16: + Bits = 16; + Scale = 2; + isCond = false; + 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; + ImmBranches.push_back(ImmBranch(I, MaxOffs, isCond, UOpc)); + } + + if (Opc == Mips::CONSTPOOL_ENTRY) + continue; + + + // Scan the instructions for constant pool operands. + for (unsigned op = 0, e = I->getNumOperands(); op != e; ++op) + if (I->getOperand(op).isCPI()) { + + // We found one. The addressing mode tells us the max displacement + // from the PC that this instruction permits. + + // Basic size info comes from the TSFlags field. + unsigned Bits = 0; + unsigned Scale = 1; + bool NegOk = false; + unsigned LongFormBits = 0; + unsigned LongFormScale = 0; + unsigned LongFormOpcode = 0; + switch (Opc) { + default: + llvm_unreachable("Unknown addressing mode for CP reference!"); + case Mips::LwRxPcTcp16: + Bits = 8; + Scale = 4; + LongFormOpcode = Mips::LwRxPcTcpX16; + LongFormBits = 14; + LongFormScale = 1; + break; + case Mips::LwRxPcTcpX16: + Bits = 14; + Scale = 1; + NegOk = true; + break; + } + // Remember that this is a user of a CP entry. + unsigned CPI = I->getOperand(op).getIndex(); + MachineInstr *CPEMI = CPEMIs[CPI]; + unsigned MaxOffs = ((1 << Bits)-1) * Scale; + unsigned LongFormMaxOffs = ((1 << LongFormBits)-1) * LongFormScale; + CPUsers.push_back(CPUser(I, CPEMI, MaxOffs, NegOk, + LongFormMaxOffs, LongFormOpcode)); + + // Increment corresponding CPEntry reference count. + CPEntry *CPE = findConstPoolEntry(CPI, CPEMI); + assert(CPE && "Cannot find a corresponding CPEntry!"); + CPE->RefCount++; + + // Instructions can only use one CP entry, don't bother scanning the + // rest of the operands. + break; + + } + + } + } + +} + +/// computeBlockSize - Compute the size and some alignment information for MBB. +/// This function updates BBInfo directly. +void MipsConstantIslands::computeBlockSize(MachineBasicBlock *MBB) { + BasicBlockInfo &BBI = BBInfo[MBB->getNumber()]; + BBI.Size = 0; + + for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E; + ++I) + BBI.Size += TII->GetInstSizeInBytes(I); + +} + +/// getOffsetOf - Return the current offset of the specified machine instruction +/// from the start of the function. This offset changes as stuff is moved +/// around inside the function. +unsigned MipsConstantIslands::getOffsetOf(MachineInstr *MI) const { + MachineBasicBlock *MBB = MI->getParent(); + + // The offset is composed of two things: the sum of the sizes of all MBB's + // before this instruction's block, and the offset from the start of the block + // it is in. + unsigned Offset = BBInfo[MBB->getNumber()].Offset; + + // Sum instructions before MI in MBB. + for (MachineBasicBlock::iterator I = MBB->begin(); &*I != MI; ++I) { + assert(I != MBB->end() && "Didn't find MI in its own basic block?"); + Offset += TII->GetInstSizeInBytes(I); + } + return Offset; +} + +/// CompareMBBNumbers - Little predicate function to sort the WaterList by MBB +/// ID. +static bool CompareMBBNumbers(const MachineBasicBlock *LHS, + const MachineBasicBlock *RHS) { + return LHS->getNumber() < RHS->getNumber(); +} + +/// updateForInsertedWaterBlock - When a block is newly inserted into the +/// machine function, it upsets all of the block numbers. Renumber the blocks +/// and update the arrays that parallel this numbering. +void MipsConstantIslands::updateForInsertedWaterBlock + (MachineBasicBlock *NewBB) { + // Renumber the MBB's to keep them consecutive. + NewBB->getParent()->RenumberBlocks(NewBB); + + // Insert an entry into BBInfo to align it properly with the (newly + // renumbered) block numbers. + BBInfo.insert(BBInfo.begin() + NewBB->getNumber(), BasicBlockInfo()); + + // Next, update WaterList. Specifically, we need to add NewMBB as having + // available water after it. + water_iterator IP = + std::lower_bound(WaterList.begin(), WaterList.end(), NewBB, + CompareMBBNumbers); + WaterList.insert(IP, NewBB); +} + +unsigned MipsConstantIslands::getUserOffset(CPUser &U) const { + return getOffsetOf(U.MI); +} + +/// Split the basic block containing MI into two blocks, which are joined by +/// an unconditional branch. Update data structures and renumber blocks to +/// account for this change and returns the newly created block. +MachineBasicBlock *MipsConstantIslands::splitBlockBeforeInstr + (MachineInstr *MI) { + MachineBasicBlock *OrigBB = MI->getParent(); + + // Create a new MBB for the code after the OrigBB. + MachineBasicBlock *NewBB = + MF->CreateMachineBasicBlock(OrigBB->getBasicBlock()); + MachineFunction::iterator MBBI = ++OrigBB->getIterator(); + MF->insert(MBBI, NewBB); + + // Splice the instructions starting with MI over to NewBB. + NewBB->splice(NewBB->end(), OrigBB, MI, OrigBB->end()); + + // Add an unconditional branch from OrigBB to NewBB. + // Note the new unconditional branch is not being recorded. + // There doesn't seem to be meaningful DebugInfo available; this doesn't + // correspond to anything in the source. + BuildMI(OrigBB, DebugLoc(), TII->get(Mips::Bimm16)).addMBB(NewBB); + ++NumSplit; + + // Update the CFG. All succs of OrigBB are now succs of NewBB. + NewBB->transferSuccessors(OrigBB); + + // OrigBB branches to NewBB. + OrigBB->addSuccessor(NewBB); + + // Update internal data structures to account for the newly inserted MBB. + // This is almost the same as updateForInsertedWaterBlock, except that + // the Water goes after OrigBB, not NewBB. + MF->RenumberBlocks(NewBB); + + // Insert an entry into BBInfo to align it properly with the (newly + // renumbered) block numbers. + BBInfo.insert(BBInfo.begin() + NewBB->getNumber(), BasicBlockInfo()); + + // Next, update WaterList. Specifically, we need to add OrigMBB as having + // available water after it (but not if it's already there, which happens + // when splitting before a conditional branch that is followed by an + // unconditional branch - in that case we want to insert NewBB). + water_iterator IP = + std::lower_bound(WaterList.begin(), WaterList.end(), OrigBB, + CompareMBBNumbers); + MachineBasicBlock* WaterBB = *IP; + if (WaterBB == OrigBB) + WaterList.insert(std::next(IP), NewBB); + else + WaterList.insert(IP, OrigBB); + NewWaterList.insert(OrigBB); + + // Figure out how large the OrigBB is. As the first half of the original + // block, it cannot contain a tablejump. The size includes + // the new jump we added. (It should be possible to do this without + // recounting everything, but it's very confusing, and this is rarely + // executed.) + computeBlockSize(OrigBB); + + // Figure out how large the NewMBB is. As the second half of the original + // block, it may contain a tablejump. + computeBlockSize(NewBB); + + // All BBOffsets following these blocks must be modified. + adjustBBOffsetsAfter(OrigBB); + + return NewBB; +} + + + +/// isOffsetInRange - Checks whether UserOffset (the location of a constant pool +/// reference) is within MaxDisp of TrialOffset (a proposed location of a +/// constant pool entry). +bool MipsConstantIslands::isOffsetInRange(unsigned UserOffset, + unsigned TrialOffset, unsigned MaxDisp, + bool NegativeOK) { + if (UserOffset <= TrialOffset) { + // User before the Trial. + if (TrialOffset - UserOffset <= MaxDisp) + return true; + } else if (NegativeOK) { + if (UserOffset - TrialOffset <= MaxDisp) + return true; + } + return false; +} + +/// isWaterInRange - Returns true if a CPE placed after the specified +/// Water (a basic block) will be in range for the specific MI. +/// +/// Compute how much the function will grow by inserting a CPE after Water. +bool MipsConstantIslands::isWaterInRange(unsigned UserOffset, + MachineBasicBlock* Water, CPUser &U, + unsigned &Growth) { + unsigned CPELogAlign = getCPELogAlign(U.CPEMI); + unsigned CPEOffset = BBInfo[Water->getNumber()].postOffset(CPELogAlign); + unsigned NextBlockOffset, NextBlockAlignment; + MachineFunction::const_iterator NextBlock = ++Water->getIterator(); + if (NextBlock == MF->end()) { + NextBlockOffset = BBInfo[Water->getNumber()].postOffset(); + NextBlockAlignment = 0; + } else { + NextBlockOffset = BBInfo[NextBlock->getNumber()].Offset; + NextBlockAlignment = NextBlock->getAlignment(); + } + unsigned Size = U.CPEMI->getOperand(2).getImm(); + unsigned CPEEnd = CPEOffset + Size; + + // The CPE may be able to hide in the alignment padding before the next + // block. It may also cause more padding to be required if it is more aligned + // that the next block. + if (CPEEnd > NextBlockOffset) { + Growth = CPEEnd - NextBlockOffset; + // Compute the padding that would go at the end of the CPE to align the next + // block. + Growth += OffsetToAlignment(CPEEnd, 1u << NextBlockAlignment); + + // If the CPE is to be inserted before the instruction, that will raise + // the offset of the instruction. Also account for unknown alignment padding + // in blocks between CPE and the user. + if (CPEOffset < UserOffset) + UserOffset += Growth; + } else + // CPE fits in existing padding. + Growth = 0; + + return isOffsetInRange(UserOffset, CPEOffset, U); +} + +/// isCPEntryInRange - Returns true if the distance between specific MI and +/// specific ConstPool entry instruction can fit in MI's displacement field. +bool MipsConstantIslands::isCPEntryInRange + (MachineInstr *MI, unsigned UserOffset, + MachineInstr *CPEMI, unsigned MaxDisp, + bool NegOk, bool DoDump) { + unsigned CPEOffset = getOffsetOf(CPEMI); + + if (DoDump) { + DEBUG({ + unsigned Block = MI->getParent()->getNumber(); + const BasicBlockInfo &BBI = BBInfo[Block]; + dbgs() << "User of CPE#" << CPEMI->getOperand(0).getImm() + << " max delta=" << MaxDisp + << format(" insn address=%#x", UserOffset) + << " in BB#" << Block << ": " + << format("%#x-%x\t", BBI.Offset, BBI.postOffset()) << *MI + << format("CPE address=%#x offset=%+d: ", CPEOffset, + int(CPEOffset-UserOffset)); + }); + } + + return isOffsetInRange(UserOffset, CPEOffset, MaxDisp, NegOk); +} + +#ifndef NDEBUG +/// BBIsJumpedOver - Return true of the specified basic block's only predecessor +/// unconditionally branches to its only successor. +static bool BBIsJumpedOver(MachineBasicBlock *MBB) { + if (MBB->pred_size() != 1 || MBB->succ_size() != 1) + return false; + MachineBasicBlock *Succ = *MBB->succ_begin(); + MachineBasicBlock *Pred = *MBB->pred_begin(); + MachineInstr *PredMI = &Pred->back(); + if (PredMI->getOpcode() == Mips::Bimm16) + return PredMI->getOperand(0).getMBB() == Succ; + return false; +} +#endif + +void MipsConstantIslands::adjustBBOffsetsAfter(MachineBasicBlock *BB) { + unsigned BBNum = BB->getNumber(); + for(unsigned i = BBNum + 1, e = MF->getNumBlockIDs(); i < e; ++i) { + // Get the offset and known bits at the end of the layout predecessor. + // Include the alignment of the current block. + unsigned Offset = BBInfo[i - 1].Offset + BBInfo[i - 1].Size; + BBInfo[i].Offset = Offset; + } +} + +/// decrementCPEReferenceCount - find the constant pool entry with index CPI +/// and instruction CPEMI, and decrement its refcount. If the refcount +/// becomes 0 remove the entry and instruction. Returns true if we removed +/// the entry, false if we didn't. + +bool MipsConstantIslands::decrementCPEReferenceCount(unsigned CPI, + MachineInstr *CPEMI) { + // Find the old entry. Eliminate it if it is no longer used. + CPEntry *CPE = findConstPoolEntry(CPI, CPEMI); + assert(CPE && "Unexpected!"); + if (--CPE->RefCount == 0) { + removeDeadCPEMI(CPEMI); + CPE->CPEMI = nullptr; + --NumCPEs; + return true; + } + return false; +} + +/// LookForCPEntryInRange - see if the currently referenced CPE is in range; +/// if not, see if an in-range clone of the CPE is in range, and if so, +/// change the data structures so the user references the clone. Returns: +/// 0 = no existing entry found +/// 1 = entry found, and there were no code insertions or deletions +/// 2 = entry found, and there were code insertions or deletions +int MipsConstantIslands::findInRangeCPEntry(CPUser& U, unsigned UserOffset) +{ + MachineInstr *UserMI = U.MI; + MachineInstr *CPEMI = U.CPEMI; + + // Check to see if the CPE is already in-range. + if (isCPEntryInRange(UserMI, UserOffset, CPEMI, U.getMaxDisp(), U.NegOk, + true)) { + DEBUG(dbgs() << "In range\n"); + return 1; + } + + // No. Look for previously created clones of the CPE that are in range. + unsigned CPI = CPEMI->getOperand(1).getIndex(); + std::vector<CPEntry> &CPEs = CPEntries[CPI]; + for (unsigned i = 0, e = CPEs.size(); i != e; ++i) { + // We already tried this one + if (CPEs[i].CPEMI == CPEMI) + continue; + // Removing CPEs can leave empty entries, skip + if (CPEs[i].CPEMI == nullptr) + continue; + if (isCPEntryInRange(UserMI, UserOffset, CPEs[i].CPEMI, U.getMaxDisp(), + U.NegOk)) { + DEBUG(dbgs() << "Replacing CPE#" << CPI << " with CPE#" + << CPEs[i].CPI << "\n"); + // Point the CPUser node to the replacement + U.CPEMI = CPEs[i].CPEMI; + // Change the CPI in the instruction operand to refer to the clone. + for (unsigned j = 0, e = UserMI->getNumOperands(); j != e; ++j) + if (UserMI->getOperand(j).isCPI()) { + UserMI->getOperand(j).setIndex(CPEs[i].CPI); + break; + } + // Adjust the refcount of the clone... + CPEs[i].RefCount++; + // ...and the original. If we didn't remove the old entry, none of the + // addresses changed, so we don't need another pass. + return decrementCPEReferenceCount(CPI, CPEMI) ? 2 : 1; + } + } + return 0; +} + +/// LookForCPEntryInRange - see if the currently referenced CPE is in range; +/// This version checks if the longer form of the instruction can be used to +/// to satisfy things. +/// if not, see if an in-range clone of the CPE is in range, and if so, +/// change the data structures so the user references the clone. Returns: +/// 0 = no existing entry found +/// 1 = entry found, and there were no code insertions or deletions +/// 2 = entry found, and there were code insertions or deletions +int MipsConstantIslands::findLongFormInRangeCPEntry + (CPUser& U, unsigned UserOffset) +{ + MachineInstr *UserMI = U.MI; + MachineInstr *CPEMI = U.CPEMI; + + // Check to see if the CPE is already in-range. + if (isCPEntryInRange(UserMI, UserOffset, CPEMI, + U.getLongFormMaxDisp(), U.NegOk, + true)) { + DEBUG(dbgs() << "In range\n"); + UserMI->setDesc(TII->get(U.getLongFormOpcode())); + U.setMaxDisp(U.getLongFormMaxDisp()); + return 2; // instruction is longer length now + } + + // No. Look for previously created clones of the CPE that are in range. + unsigned CPI = CPEMI->getOperand(1).getIndex(); + std::vector<CPEntry> &CPEs = CPEntries[CPI]; + for (unsigned i = 0, e = CPEs.size(); i != e; ++i) { + // We already tried this one + if (CPEs[i].CPEMI == CPEMI) + continue; + // Removing CPEs can leave empty entries, skip + if (CPEs[i].CPEMI == nullptr) + continue; + if (isCPEntryInRange(UserMI, UserOffset, CPEs[i].CPEMI, + U.getLongFormMaxDisp(), U.NegOk)) { + DEBUG(dbgs() << "Replacing CPE#" << CPI << " with CPE#" + << CPEs[i].CPI << "\n"); + // Point the CPUser node to the replacement + U.CPEMI = CPEs[i].CPEMI; + // Change the CPI in the instruction operand to refer to the clone. + for (unsigned j = 0, e = UserMI->getNumOperands(); j != e; ++j) + if (UserMI->getOperand(j).isCPI()) { + UserMI->getOperand(j).setIndex(CPEs[i].CPI); + break; + } + // Adjust the refcount of the clone... + CPEs[i].RefCount++; + // ...and the original. If we didn't remove the old entry, none of the + // addresses changed, so we don't need another pass. + return decrementCPEReferenceCount(CPI, CPEMI) ? 2 : 1; + } + } + return 0; +} + +/// getUnconditionalBrDisp - Returns the maximum displacement that can fit in +/// the specific unconditional branch instruction. +static inline unsigned getUnconditionalBrDisp(int Opc) { + switch (Opc) { + case Mips::Bimm16: + return ((1<<10)-1)*2; + case Mips::BimmX16: + return ((1<<16)-1)*2; + default: + break; + } + return ((1<<16)-1)*2; +} + +/// findAvailableWater - Look for an existing entry in the WaterList in which +/// we can place the CPE referenced from U so it's within range of U's MI. +/// Returns true if found, false if not. If it returns true, WaterIter +/// is set to the WaterList entry. +/// To ensure that this pass +/// terminates, the CPE location for a particular CPUser is only allowed to +/// move to a lower address, so search backward from the end of the list and +/// prefer the first water that is in range. +bool MipsConstantIslands::findAvailableWater(CPUser &U, unsigned UserOffset, + water_iterator &WaterIter) { + if (WaterList.empty()) + return false; + + unsigned BestGrowth = ~0u; + for (water_iterator IP = 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 + // current "high water mark" or a new water block that was created since + // the previous iteration by inserting an unconditional branch. In the + // latter case, we want to allow resetting the high water mark back to + // this new water since we haven't seen it before. Inserting branches + // should be relatively uncommon and when it does happen, we want to be + // sure to take advantage of it for all the CPEs near that block, so that + // we don't insert more branches than necessary. + unsigned Growth; + if (isWaterInRange(UserOffset, WaterBB, U, Growth) && + (WaterBB->getNumber() < U.HighWaterMark->getNumber() || + NewWaterList.count(WaterBB)) && Growth < BestGrowth) { + // This is the least amount of required padding seen so far. + BestGrowth = Growth; + WaterIter = IP; + DEBUG(dbgs() << "Found water after BB#" << WaterBB->getNumber() + << " Growth=" << Growth << '\n'); + + // Keep looking unless it is perfect. + if (BestGrowth == 0) + return true; + } + if (IP == B) + break; + } + return BestGrowth != ~0u; +} + +/// createNewWater - No existing WaterList entry will work for +/// CPUsers[CPUserIndex], so create a place to put the CPE. The end of the +/// block is used if in range, and the conditional branch munged so control +/// flow is correct. Otherwise the block is split to create a hole with an +/// unconditional branch around it. In either case NewMBB is set to a +/// block following which the new island can be inserted (the WaterList +/// is not adjusted). +void MipsConstantIslands::createNewWater(unsigned CPUserIndex, + unsigned UserOffset, + MachineBasicBlock *&NewMBB) { + CPUser &U = CPUsers[CPUserIndex]; + MachineInstr *UserMI = U.MI; + MachineInstr *CPEMI = U.CPEMI; + unsigned CPELogAlign = getCPELogAlign(CPEMI); + MachineBasicBlock *UserMBB = UserMI->getParent(); + const BasicBlockInfo &UserBBI = BBInfo[UserMBB->getNumber()]; + + // If the block does not end in an unconditional branch already, and if the + // end of the block is within range, make new water there. + if (BBHasFallthrough(UserMBB)) { + // Size of branch to insert. + unsigned Delta = 2; + // Compute the offset where the CPE will begin. + unsigned CPEOffset = UserBBI.postOffset(CPELogAlign) + Delta; + + if (isOffsetInRange(UserOffset, CPEOffset, U)) { + DEBUG(dbgs() << "Split at end of BB#" << UserMBB->getNumber() + << format(", expected CPE offset %#x\n", CPEOffset)); + NewMBB = &*++UserMBB->getIterator(); + // Add an unconditional branch from UserMBB to fallthrough block. Record + // it for branch lengthening; this new branch will not get out of range, + // but if the preceding conditional branch is out of range, the targets + // will be exchanged, and the altered branch may be out of range, so the + // machinery has to know about it. + int UncondBr = Mips::Bimm16; + BuildMI(UserMBB, DebugLoc(), TII->get(UncondBr)).addMBB(NewMBB); + unsigned MaxDisp = getUnconditionalBrDisp(UncondBr); + ImmBranches.push_back(ImmBranch(&UserMBB->back(), + MaxDisp, false, UncondBr)); + BBInfo[UserMBB->getNumber()].Size += Delta; + adjustBBOffsetsAfter(UserMBB); + return; + } + } + + // What a big block. Find a place within the block to split it. + + // Try to split the block so it's fully aligned. Compute the latest split + // point where we can add a 4-byte branch instruction, and then align to + // LogAlign which is the largest possible alignment in the function. + unsigned LogAlign = MF->getAlignment(); + assert(LogAlign >= CPELogAlign && "Over-aligned constant pool entry"); + unsigned BaseInsertOffset = UserOffset + U.getMaxDisp(); + DEBUG(dbgs() << format("Split in middle of big block before %#x", + BaseInsertOffset)); + + // The 4 in the following is for the unconditional branch we'll be inserting + // Alignment of the island is handled + // inside isOffsetInRange. + BaseInsertOffset -= 4; + + DEBUG(dbgs() << format(", adjusted to %#x", BaseInsertOffset) + << " la=" << LogAlign << '\n'); + + // This could point off the end of the block if we've already got constant + // pool entries following this block; only the last one is in the water list. + // Back past any possible branches (allow for a conditional and a maximally + // long unconditional). + if (BaseInsertOffset + 8 >= UserBBI.postOffset()) { + BaseInsertOffset = UserBBI.postOffset() - 8; + DEBUG(dbgs() << format("Move inside block: %#x\n", BaseInsertOffset)); + } + unsigned EndInsertOffset = BaseInsertOffset + 4 + + CPEMI->getOperand(2).getImm(); + MachineBasicBlock::iterator MI = UserMI; + ++MI; + unsigned CPUIndex = CPUserIndex+1; + unsigned NumCPUsers = CPUsers.size(); + //MachineInstr *LastIT = 0; + for (unsigned Offset = UserOffset+TII->GetInstSizeInBytes(UserMI); + Offset < BaseInsertOffset; + Offset += TII->GetInstSizeInBytes(MI), MI = std::next(MI)) { + assert(MI != UserMBB->end() && "Fell off end of block"); + if (CPUIndex < NumCPUsers && CPUsers[CPUIndex].MI == MI) { + CPUser &U = CPUsers[CPUIndex]; + if (!isOffsetInRange(Offset, EndInsertOffset, U)) { + // Shift intertion point by one unit of alignment so it is within reach. + BaseInsertOffset -= 1u << LogAlign; + EndInsertOffset -= 1u << LogAlign; + } + // This is overly conservative, as we don't account for CPEMIs being + // reused within the block, but it doesn't matter much. Also assume CPEs + // are added in order with alignment padding. We may eventually be able + // to pack the aligned CPEs better. + EndInsertOffset += U.CPEMI->getOperand(2).getImm(); + CPUIndex++; + } + } + + --MI; + NewMBB = splitBlockBeforeInstr(MI); +} + +/// handleConstantPoolUser - Analyze the specified user, checking to see if it +/// is out-of-range. If so, pick up the constant pool value and move it some +/// place in-range. Return true if we changed any addresses (thus must run +/// another pass of branch lengthening), false otherwise. +bool MipsConstantIslands::handleConstantPoolUser(unsigned CPUserIndex) { + CPUser &U = CPUsers[CPUserIndex]; + MachineInstr *UserMI = U.MI; + MachineInstr *CPEMI = U.CPEMI; + unsigned CPI = CPEMI->getOperand(1).getIndex(); + unsigned Size = CPEMI->getOperand(2).getImm(); + // Compute this only once, it's expensive. + unsigned UserOffset = getUserOffset(U); + + // See if the current entry is within range, or there is a clone of it + // in range. + int result = findInRangeCPEntry(U, UserOffset); + if (result==1) return false; + else if (result==2) return true; + + + // Look for water where we can place this CPE. + MachineBasicBlock *NewIsland = MF->CreateMachineBasicBlock(); + MachineBasicBlock *NewMBB; + water_iterator IP; + if (findAvailableWater(U, UserOffset, IP)) { + DEBUG(dbgs() << "Found water in range\n"); + MachineBasicBlock *WaterBB = *IP; + + // If the original WaterList entry was "new water" on this iteration, + // propagate that to the new island. This is just keeping NewWaterList + // updated to match the WaterList, which will be updated below. + if (NewWaterList.erase(WaterBB)) + NewWaterList.insert(NewIsland); + + // The new CPE goes before the following block (NewMBB). + NewMBB = &*++WaterBB->getIterator(); + } else { + // No water found. + // we first see if a longer form of the instrucion could have reached + // the constant. in that case we won't bother to split + if (!NoLoadRelaxation) { + result = findLongFormInRangeCPEntry(U, UserOffset); + if (result != 0) return true; + } + DEBUG(dbgs() << "No water found\n"); + createNewWater(CPUserIndex, UserOffset, NewMBB); + + // splitBlockBeforeInstr adds to WaterList, which is important when it is + // called while handling branches so that the water will be seen on the + // next iteration for constant pools, but in this context, we don't want + // it. Check for this so it will be removed from the WaterList. + // Also remove any entry from NewWaterList. + MachineBasicBlock *WaterBB = &*--NewMBB->getIterator(); + IP = std::find(WaterList.begin(), WaterList.end(), WaterBB); + if (IP != WaterList.end()) + NewWaterList.erase(WaterBB); + + // We are adding new water. Update NewWaterList. + NewWaterList.insert(NewIsland); + } + + // Remove the original WaterList entry; we want subsequent insertions in + // this vicinity to go after the one we're about to insert. This + // considerably reduces the number of times we have to move the same CPE + // more than once and is also important to ensure the algorithm terminates. + if (IP != WaterList.end()) + WaterList.erase(IP); + + // Okay, we know we can put an island before NewMBB now, do it! + MF->insert(NewMBB->getIterator(), NewIsland); + + // Update internal data structures to account for the newly inserted MBB. + updateForInsertedWaterBlock(NewIsland); + + // Decrement the old entry, and remove it if refcount becomes 0. + decrementCPEReferenceCount(CPI, CPEMI); + + // 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; + U.CPEMI = BuildMI(NewIsland, DebugLoc(), TII->get(Mips::CONSTPOOL_ENTRY)) + .addImm(ID).addConstantPoolIndex(CPI).addImm(Size); + CPEntries[CPI].push_back(CPEntry(U.CPEMI, ID, 1)); + ++NumCPEs; + + // Mark the basic block as aligned as required by the const-pool entry. + NewIsland->setAlignment(getCPELogAlign(U.CPEMI)); + + // Increase the size of the island block to account for the new entry. + BBInfo[NewIsland->getNumber()].Size += Size; + adjustBBOffsetsAfter(&*--NewIsland->getIterator()); + + // Finally, change the CPI in the instruction operand to be ID. + for (unsigned i = 0, e = UserMI->getNumOperands(); i != e; ++i) + if (UserMI->getOperand(i).isCPI()) { + UserMI->getOperand(i).setIndex(ID); + break; + } + + DEBUG(dbgs() << " Moved CPE to #" << ID << " CPI=" << CPI + << format(" offset=%#x\n", BBInfo[NewIsland->getNumber()].Offset)); + + return true; +} + +/// removeDeadCPEMI - Remove a dead constant pool entry instruction. Update +/// sizes and offsets of impacted basic blocks. +void MipsConstantIslands::removeDeadCPEMI(MachineInstr *CPEMI) { + MachineBasicBlock *CPEBB = CPEMI->getParent(); + unsigned Size = CPEMI->getOperand(2).getImm(); + CPEMI->eraseFromParent(); + BBInfo[CPEBB->getNumber()].Size -= Size; + // All succeeding offsets have the current size value added in, fix this. + if (CPEBB->empty()) { + BBInfo[CPEBB->getNumber()].Size = 0; + + // This block no longer needs to be aligned. + CPEBB->setAlignment(0); + } else + // Entries are sorted by descending alignment, so realign from the front. + CPEBB->setAlignment(getCPELogAlign(CPEBB->begin())); + + adjustBBOffsetsAfter(CPEBB); + // An island has only one predecessor BB and one successor BB. Check if + // this BB's predecessor jumps directly to this BB's successor. This + // shouldn't happen currently. + assert(!BBIsJumpedOver(CPEBB) && "How did this happen?"); + // FIXME: remove the empty blocks after all the work is done? +} + +/// removeUnusedCPEntries - Remove constant pool entries whose refcounts +/// are zero. +bool MipsConstantIslands::removeUnusedCPEntries() { + unsigned MadeChange = false; + for (unsigned i = 0, e = CPEntries.size(); i != e; ++i) { + std::vector<CPEntry> &CPEs = CPEntries[i]; + for (unsigned j = 0, ee = CPEs.size(); j != ee; ++j) { + if (CPEs[j].RefCount == 0 && CPEs[j].CPEMI) { + removeDeadCPEMI(CPEs[j].CPEMI); + CPEs[j].CPEMI = nullptr; + MadeChange = true; + } + } + } + return MadeChange; +} + +/// isBBInRange - Returns true if the distance between specific MI and +/// specific BB can fit in MI's displacement field. +bool MipsConstantIslands::isBBInRange + (MachineInstr *MI,MachineBasicBlock *DestBB, unsigned MaxDisp) { + +unsigned PCAdj = 4; + + unsigned BrOffset = getOffsetOf(MI) + PCAdj; + unsigned DestOffset = BBInfo[DestBB->getNumber()].Offset; + + DEBUG(dbgs() << "Branch of destination BB#" << DestBB->getNumber() + << " from BB#" << MI->getParent()->getNumber() + << " max delta=" << MaxDisp + << " from " << getOffsetOf(MI) << " to " << DestOffset + << " offset " << int(DestOffset-BrOffset) << "\t" << *MI); + + if (BrOffset <= DestOffset) { + // Branch before the Dest. + if (DestOffset-BrOffset <= MaxDisp) + return true; + } else { + if (BrOffset-DestOffset <= MaxDisp) + return true; + } + return false; +} + +/// fixupImmediateBr - Fix up an immediate branch whose destination is too far +/// away to fit in its displacement field. +bool MipsConstantIslands::fixupImmediateBr(ImmBranch &Br) { + MachineInstr *MI = Br.MI; + 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)) + return false; + + if (!Br.isCond) + return fixupUnconditionalBr(Br); + return fixupConditionalBr(Br); +} + +/// fixupUnconditionalBr - Fix up an unconditional branch whose destination is +/// too far away to fit in its displacement field. If the LR register has been +/// spilled in the epilogue, then we can use BL to implement a far jump. +/// Otherwise, add an intermediate branch instruction to a branch. +bool +MipsConstantIslands::fixupUnconditionalBr(ImmBranch &Br) { + MachineInstr *MI = Br.MI; + MachineBasicBlock *MBB = MI->getParent(); + MachineBasicBlock *DestBB = MI->getOperand(0).getMBB(); + // Use BL to implement far jump. + 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; + ++NumUBrFixed; + + DEBUG(dbgs() << " Changed B to long jump " << *MI); + + return true; +} + + +/// fixupConditionalBr - Fix up a conditional branch whose destination is too +/// far away to fit in its displacement field. It is converted to an inverse +/// conditional branch + an unconditional branch to the destination. +bool +MipsConstantIslands::fixupConditionalBr(ImmBranch &Br) { + MachineInstr *MI = Br.MI; + 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: + // bteqz L1 + // => + // bnez L2 + // b L1 + // L2: + + // If the branch is at the end of its MBB and that has a fall-through block, + // direct the updated conditional branch to the fall-through block. Otherwise, + // split the MBB before the next instruction. + MachineBasicBlock *MBB = MI->getParent(); + MachineInstr *BMI = &MBB->back(); + bool NeedSplit = (BMI != MI) || !BBHasFallthrough(MBB); + unsigned OppositeBranchOpcode = TII->getOppositeBranchOpc(Opcode); + + ++NumCBrFixed; + if (BMI != MI) { + 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: + // beqz L1 + // b L2 + // => + // bnez L2 + // b L1 + 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); + 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 + // branch to the destination. + int delta = TII->GetInstSizeInBytes(&MBB->back()); + BBInfo[MBB->getNumber()].Size -= delta; + MBB->back().eraseFromParent(); + // BBInfo[SplitBB].Offset is wrong temporarily, fixed below + } + MachineBasicBlock *NextBB = &*++MBB->getIterator(); + + DEBUG(dbgs() << " Insert B to BB#" << DestBB->getNumber() + << " also invert condition and change dest. to BB#" + << NextBB->getNumber() << "\n"); + + // Insert a new conditional branch and a new unconditional branch. + // Also update the ImmBranch as well as adding a new entry for the new branch. + 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); + BBInfo[MBB->getNumber()].Size += TII->GetInstSizeInBytes(&MBB->back()); + unsigned MaxDisp = getUnconditionalBrDisp(Br.UncondBr); + ImmBranches.push_back(ImmBranch(&MBB->back(), MaxDisp, false, Br.UncondBr)); + + // Remove the old conditional branch. It may or may not still be in MBB. + BBInfo[MI->getParent()->getNumber()].Size -= TII->GetInstSizeInBytes(MI); + MI->eraseFromParent(); + adjustBBOffsetsAfter(MBB); + return true; +} + + +void MipsConstantIslands::prescanForConstants() { + unsigned J = 0; + (void)J; + 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"); + MachineOperand& Literal = I->getOperand(1); + if (Literal.isImm()) { + int64_t V = Literal.getImm(); + DEBUG(dbgs() << "literal " << V << "\n"); + Type *Int32Ty = + Type::getInt32Ty(MF->getFunction()->getContext()); + const Constant *C = ConstantInt::get(Int32Ty, V); + unsigned index = MCP->getConstantPoolIndex(C, 4); + I->getOperand(2).ChangeToImmediate(index); + DEBUG(dbgs() << "constant island constant " << *I << "\n"); + I->setDesc(TII->get(Mips::LwRxPcTcp16)); + I->RemoveOperand(1); + I->RemoveOperand(1); + I->addOperand(MachineOperand::CreateCPI(index, 0)); + I->addOperand(MachineOperand::CreateImm(4)); + } + break; + } + default: + break; + } + } + } +} + diff --git a/contrib/llvm/lib/Target/Mips/MipsDSPInstrFormats.td b/contrib/llvm/lib/Target/Mips/MipsDSPInstrFormats.td new file mode 100644 index 0000000..f959bd4 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsDSPInstrFormats.td @@ -0,0 +1,365 @@ +//===- MipsDSPInstrFormats.td - Mips Instruction Formats ---*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +class DspMMRel; + +def Dsp2MicroMips : InstrMapping { + let FilterClass = "DspMMRel"; + // Instructions with the same BaseOpcode and isNVStore values form a row. + let RowFields = ["BaseOpcode"]; + // Instructions with the same predicate sense form a column. + let ColFields = ["Arch"]; + // The key column is the unpredicated instructions. + let KeyCol = ["dsp"]; + // Value columns are PredSense=true and PredSense=false + let ValueCols = [["dsp"], ["mmdsp"]]; +} + +def HasDSP : Predicate<"Subtarget->hasDSP()">, + AssemblerPredicate<"FeatureDSP">; +def HasDSPR2 : Predicate<"Subtarget->hasDSPR2()">, + AssemblerPredicate<"FeatureDSPR2">; +def HasDSPR3 : Predicate<"Subtarget->hasDSPR3()">, + AssemblerPredicate<"FeatureDSPR3">; + +class ISA_DSPR2 { + list<Predicate> InsnPredicates = [HasDSPR2]; +} + +// Fields. +class Field6<bits<6> val> { + bits<6> V = val; +} + +def SPECIAL3_OPCODE : Field6<0b011111>; +def REGIMM_OPCODE : Field6<0b000001>; + +class DSPInst<string opstr = ""> + : MipsInst<(outs), (ins), "", [], NoItinerary, FrmOther>, PredicateControl { + let InsnPredicates = [HasDSP]; + string BaseOpcode = opstr; + string Arch = "dsp"; +} + +class PseudoDSP<dag outs, dag ins, list<dag> pattern, + InstrItinClass itin = IIPseudo> + : MipsPseudo<outs, ins, pattern, itin>, PredicateControl { + let InsnPredicates = [HasDSP]; +} + +class DSPInstAlias<string Asm, dag Result, bit Emit = 0b1> + : InstAlias<Asm, Result, Emit>, PredicateControl { + let InsnPredicates = [HasDSP]; +} + +// ADDU.QB sub-class format. +class ADDU_QB_FMT<bits<5> op> : DSPInst { + bits<5> rd; + bits<5> rs; + bits<5> rt; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b010000; +} + +class RADDU_W_QB_FMT<bits<5> op> : DSPInst { + bits<5> rd; + bits<5> rs; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = 0; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b010000; +} + +// CMPU.EQ.QB sub-class format. +class CMP_EQ_QB_R2_FMT<bits<5> op> : DSPInst { + bits<5> rs; + bits<5> rt; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = 0; + let Inst{10-6} = op; + let Inst{5-0} = 0b010001; +} + +class CMP_EQ_QB_R3_FMT<bits<5> op> : DSPInst { + bits<5> rs; + bits<5> rt; + bits<5> rd; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b010001; +} + +class PRECR_SRA_PH_W_FMT<bits<5> op> : DSPInst { + bits<5> rs; + bits<5> rt; + bits<5> sa; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = sa; + let Inst{10-6} = op; + let Inst{5-0} = 0b010001; +} + +// ABSQ_S.PH sub-class format. +class ABSQ_S_PH_R2_FMT<bits<5> op> : DSPInst { + bits<5> rd; + bits<5> rt; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = 0; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b010010; +} + + +class REPL_FMT<bits<5> op> : DSPInst { + bits<5> rd; + bits<10> imm; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-16} = imm; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b010010; +} + +// SHLL.QB sub-class format. +class SHLL_QB_FMT<bits<5> op> : DSPInst { + bits<5> rd; + bits<5> rt; + bits<5> rs_sa; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs_sa; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b010011; +} + +// LX sub-class format. +class LX_FMT<bits<5> op> : DSPInst { + bits<5> rd; + bits<5> base; + bits<5> index; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = base; + let Inst{20-16} = index; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b001010; +} + +// ADDUH.QB sub-class format. +class ADDUH_QB_FMT<bits<5> op> : DSPInst { + bits<5> rd; + bits<5> rs; + bits<5> rt; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b011000; +} + +// APPEND sub-class format. +class APPEND_FMT<bits<5> op> : DSPInst { + bits<5> rt; + bits<5> rs; + bits<5> sa; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = sa; + let Inst{10-6} = op; + let Inst{5-0} = 0b110001; +} + +// DPA.W.PH sub-class format. +class DPA_W_PH_FMT<bits<5> op> : DSPInst { + bits<2> ac; + bits<5> rs; + bits<5> rt; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-13} = 0; + let Inst{12-11} = ac; + let Inst{10-6} = op; + let Inst{5-0} = 0b110000; +} + +// MULT sub-class format. +class MULT_FMT<bits<6> opcode, bits<6> funct> : DSPInst { + bits<2> ac; + bits<5> rs; + bits<5> rt; + + let Opcode = opcode; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-13} = 0; + let Inst{12-11} = ac; + let Inst{10-6} = 0; + let Inst{5-0} = funct; +} + +// MFHI sub-class format. +class MFHI_FMT<bits<6> funct> : DSPInst { + bits<5> rd; + bits<2> ac; + + let Inst{31-26} = 0; + let Inst{25-23} = 0; + let Inst{22-21} = ac; + let Inst{20-16} = 0; + let Inst{15-11} = rd; + let Inst{10-6} = 0; + let Inst{5-0} = funct; +} + +// MTHI sub-class format. +class MTHI_FMT<bits<6> funct> : DSPInst { + bits<5> rs; + bits<2> ac; + + let Inst{31-26} = 0; + let Inst{25-21} = rs; + let Inst{20-13} = 0; + let Inst{12-11} = ac; + let Inst{10-6} = 0; + let Inst{5-0} = funct; +} + +// EXTR.W sub-class format (type 1). +class EXTR_W_TY1_FMT<bits<5> op> : DSPInst { + bits<5> rt; + bits<2> ac; + bits<5> shift_rs; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = shift_rs; + let Inst{20-16} = rt; + let Inst{15-13} = 0; + let Inst{12-11} = ac; + let Inst{10-6} = op; + let Inst{5-0} = 0b111000; +} + +// SHILO sub-class format. +class SHILO_R1_FMT<bits<5> op> : DSPInst { + bits<2> ac; + bits<6> shift; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-20} = shift; + let Inst{19-13} = 0; + let Inst{12-11} = ac; + let Inst{10-6} = op; + let Inst{5-0} = 0b111000; +} + +class SHILO_R2_FMT<bits<5> op> : DSPInst { + bits<2> ac; + bits<5> rs; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-13} = 0; + let Inst{12-11} = ac; + let Inst{10-6} = op; + let Inst{5-0} = 0b111000; +} + +class RDDSP_FMT<bits<5> op> : DSPInst { + bits<5> rd; + bits<10> mask; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-16} = mask; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b111000; +} + +class WRDSP_FMT<bits<5> op> : DSPInst { + bits<5> rs; + bits<10> mask; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-11} = mask; + let Inst{10-6} = op; + let Inst{5-0} = 0b111000; +} + +class BPOSGE32_FMT<bits<5> op> : DSPInst { + bits<16> offset; + + let Opcode = REGIMM_OPCODE.V; + + let Inst{25-21} = 0; + let Inst{20-16} = op; + let Inst{15-0} = offset; +} + +// INSV sub-class format. +class INSV_FMT<bits<6> op> : DSPInst { + bits<5> rt; + bits<5> rs; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-6} = 0; + let Inst{5-0} = op; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsDSPInstrInfo.td b/contrib/llvm/lib/Target/Mips/MipsDSPInstrInfo.td new file mode 100644 index 0000000..da6f174 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsDSPInstrInfo.td @@ -0,0 +1,1451 @@ +//===- MipsDSPInstrInfo.td - DSP ASE instructions -*- tablegen ------------*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes Mips DSP ASE instructions. +// +//===----------------------------------------------------------------------===// + +// ImmLeaf +def immZExt1 : ImmLeaf<i32, [{return isUInt<1>(Imm);}]>; +def immZExt2 : ImmLeaf<i32, [{return isUInt<2>(Imm);}]>; +def immZExt3 : ImmLeaf<i32, [{return isUInt<3>(Imm);}]>; +def immZExt4 : ImmLeaf<i32, [{return isUInt<4>(Imm);}]>; +def immZExt7 : ImmLeaf<i32, [{return isUInt<7>(Imm);}]>; +def immZExt8 : ImmLeaf<i32, [{return isUInt<8>(Imm);}]>; +def immZExt10 : ImmLeaf<i32, [{return isUInt<10>(Imm);}]>; +def immSExt6 : ImmLeaf<i32, [{return isInt<6>(Imm);}]>; + +// Mips-specific dsp nodes +def SDT_MipsExtr : SDTypeProfile<1, 2, [SDTCisVT<0, i32>, SDTCisSameAs<0, 1>, + SDTCisVT<2, untyped>]>; +def SDT_MipsShilo : SDTypeProfile<1, 2, [SDTCisVT<0, untyped>, + SDTCisSameAs<0, 2>, SDTCisVT<1, i32>]>; +def SDT_MipsDPA : SDTypeProfile<1, 3, [SDTCisVT<0, untyped>, SDTCisSameAs<0, 3>, + SDTCisVT<1, i32>, SDTCisSameAs<1, 2>]>; +def SDT_MipsSHIFT_DSP : SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisSameAs<0, 1>, + SDTCisVT<2, i32>]>; + +class MipsDSPBase<string Opc, SDTypeProfile Prof> : + SDNode<!strconcat("MipsISD::", Opc), Prof>; + +class MipsDSPSideEffectBase<string Opc, SDTypeProfile Prof> : + SDNode<!strconcat("MipsISD::", Opc), Prof, [SDNPHasChain, SDNPSideEffect]>; + +def MipsEXTP : MipsDSPSideEffectBase<"EXTP", SDT_MipsExtr>; +def MipsEXTPDP : MipsDSPSideEffectBase<"EXTPDP", SDT_MipsExtr>; +def MipsEXTR_S_H : MipsDSPSideEffectBase<"EXTR_S_H", SDT_MipsExtr>; +def MipsEXTR_W : MipsDSPSideEffectBase<"EXTR_W", SDT_MipsExtr>; +def MipsEXTR_R_W : MipsDSPSideEffectBase<"EXTR_R_W", SDT_MipsExtr>; +def MipsEXTR_RS_W : MipsDSPSideEffectBase<"EXTR_RS_W", SDT_MipsExtr>; + +def MipsSHILO : MipsDSPBase<"SHILO", SDT_MipsShilo>; +def MipsMTHLIP : MipsDSPSideEffectBase<"MTHLIP", SDT_MipsShilo>; + +def MipsMULSAQ_S_W_PH : MipsDSPSideEffectBase<"MULSAQ_S_W_PH", SDT_MipsDPA>; +def MipsMAQ_S_W_PHL : MipsDSPSideEffectBase<"MAQ_S_W_PHL", SDT_MipsDPA>; +def MipsMAQ_S_W_PHR : MipsDSPSideEffectBase<"MAQ_S_W_PHR", SDT_MipsDPA>; +def MipsMAQ_SA_W_PHL : MipsDSPSideEffectBase<"MAQ_SA_W_PHL", SDT_MipsDPA>; +def MipsMAQ_SA_W_PHR : MipsDSPSideEffectBase<"MAQ_SA_W_PHR", SDT_MipsDPA>; + +def MipsDPAU_H_QBL : MipsDSPBase<"DPAU_H_QBL", SDT_MipsDPA>; +def MipsDPAU_H_QBR : MipsDSPBase<"DPAU_H_QBR", SDT_MipsDPA>; +def MipsDPSU_H_QBL : MipsDSPBase<"DPSU_H_QBL", SDT_MipsDPA>; +def MipsDPSU_H_QBR : MipsDSPBase<"DPSU_H_QBR", SDT_MipsDPA>; +def MipsDPAQ_S_W_PH : MipsDSPSideEffectBase<"DPAQ_S_W_PH", SDT_MipsDPA>; +def MipsDPSQ_S_W_PH : MipsDSPSideEffectBase<"DPSQ_S_W_PH", SDT_MipsDPA>; +def MipsDPAQ_SA_L_W : MipsDSPSideEffectBase<"DPAQ_SA_L_W", SDT_MipsDPA>; +def MipsDPSQ_SA_L_W : MipsDSPSideEffectBase<"DPSQ_SA_L_W", SDT_MipsDPA>; + +def MipsDPA_W_PH : MipsDSPBase<"DPA_W_PH", SDT_MipsDPA>; +def MipsDPS_W_PH : MipsDSPBase<"DPS_W_PH", SDT_MipsDPA>; +def MipsDPAQX_S_W_PH : MipsDSPSideEffectBase<"DPAQX_S_W_PH", SDT_MipsDPA>; +def MipsDPAQX_SA_W_PH : MipsDSPSideEffectBase<"DPAQX_SA_W_PH", SDT_MipsDPA>; +def MipsDPAX_W_PH : MipsDSPBase<"DPAX_W_PH", SDT_MipsDPA>; +def MipsDPSX_W_PH : MipsDSPBase<"DPSX_W_PH", SDT_MipsDPA>; +def MipsDPSQX_S_W_PH : MipsDSPSideEffectBase<"DPSQX_S_W_PH", SDT_MipsDPA>; +def MipsDPSQX_SA_W_PH : MipsDSPSideEffectBase<"DPSQX_SA_W_PH", SDT_MipsDPA>; +def MipsMULSA_W_PH : MipsDSPBase<"MULSA_W_PH", SDT_MipsDPA>; + +def MipsMULT : MipsDSPBase<"MULT", SDT_MipsDPA>; +def MipsMULTU : MipsDSPBase<"MULTU", SDT_MipsDPA>; +def MipsMADD_DSP : MipsDSPBase<"MADD_DSP", SDT_MipsDPA>; +def MipsMADDU_DSP : MipsDSPBase<"MADDU_DSP", SDT_MipsDPA>; +def MipsMSUB_DSP : MipsDSPBase<"MSUB_DSP", SDT_MipsDPA>; +def MipsMSUBU_DSP : MipsDSPBase<"MSUBU_DSP", SDT_MipsDPA>; +def MipsSHLL_DSP : MipsDSPBase<"SHLL_DSP", SDT_MipsSHIFT_DSP>; +def MipsSHRA_DSP : MipsDSPBase<"SHRA_DSP", SDT_MipsSHIFT_DSP>; +def MipsSHRL_DSP : MipsDSPBase<"SHRL_DSP", SDT_MipsSHIFT_DSP>; +def MipsSETCC_DSP : MipsDSPBase<"SETCC_DSP", SDTSetCC>; +def MipsSELECT_CC_DSP : MipsDSPBase<"SELECT_CC_DSP", SDTSelectCC>; + +// Flags. +class Uses<list<Register> Regs> { + list<Register> Uses = Regs; +} + +class Defs<list<Register> Regs> { + list<Register> Defs = Regs; +} + +// Instruction encoding. +class ADDU_QB_ENC : ADDU_QB_FMT<0b00000>; +class ADDU_S_QB_ENC : ADDU_QB_FMT<0b00100>; +class SUBU_QB_ENC : ADDU_QB_FMT<0b00001>; +class SUBU_S_QB_ENC : ADDU_QB_FMT<0b00101>; +class ADDQ_PH_ENC : ADDU_QB_FMT<0b01010>; +class ADDQ_S_PH_ENC : ADDU_QB_FMT<0b01110>; +class SUBQ_PH_ENC : ADDU_QB_FMT<0b01011>; +class SUBQ_S_PH_ENC : ADDU_QB_FMT<0b01111>; +class ADDQ_S_W_ENC : ADDU_QB_FMT<0b10110>; +class SUBQ_S_W_ENC : ADDU_QB_FMT<0b10111>; +class ADDSC_ENC : ADDU_QB_FMT<0b10000>; +class ADDWC_ENC : ADDU_QB_FMT<0b10001>; +class MODSUB_ENC : ADDU_QB_FMT<0b10010>; +class RADDU_W_QB_ENC : RADDU_W_QB_FMT<0b10100>; +class ABSQ_S_PH_ENC : ABSQ_S_PH_R2_FMT<0b01001>; +class ABSQ_S_W_ENC : ABSQ_S_PH_R2_FMT<0b10001>; +class PRECRQ_QB_PH_ENC : CMP_EQ_QB_R3_FMT<0b01100>; +class PRECRQ_PH_W_ENC : CMP_EQ_QB_R3_FMT<0b10100>; +class PRECRQ_RS_PH_W_ENC : CMP_EQ_QB_R3_FMT<0b10101>; +class PRECRQU_S_QB_PH_ENC : CMP_EQ_QB_R3_FMT<0b01111>; +class PRECEQ_W_PHL_ENC : ABSQ_S_PH_R2_FMT<0b01100>; +class PRECEQ_W_PHR_ENC : ABSQ_S_PH_R2_FMT<0b01101>; +class PRECEQU_PH_QBL_ENC : ABSQ_S_PH_R2_FMT<0b00100>; +class PRECEQU_PH_QBR_ENC : ABSQ_S_PH_R2_FMT<0b00101>; +class PRECEQU_PH_QBLA_ENC : ABSQ_S_PH_R2_FMT<0b00110>; +class PRECEQU_PH_QBRA_ENC : ABSQ_S_PH_R2_FMT<0b00111>; +class PRECEU_PH_QBL_ENC : ABSQ_S_PH_R2_FMT<0b11100>; +class PRECEU_PH_QBR_ENC : ABSQ_S_PH_R2_FMT<0b11101>; +class PRECEU_PH_QBLA_ENC : ABSQ_S_PH_R2_FMT<0b11110>; +class PRECEU_PH_QBRA_ENC : ABSQ_S_PH_R2_FMT<0b11111>; +class SHLL_QB_ENC : SHLL_QB_FMT<0b00000>; +class SHLLV_QB_ENC : SHLL_QB_FMT<0b00010>; +class SHRL_QB_ENC : SHLL_QB_FMT<0b00001>; +class SHRLV_QB_ENC : SHLL_QB_FMT<0b00011>; +class SHLL_PH_ENC : SHLL_QB_FMT<0b01000>; +class SHLLV_PH_ENC : SHLL_QB_FMT<0b01010>; +class SHLL_S_PH_ENC : SHLL_QB_FMT<0b01100>; +class SHLLV_S_PH_ENC : SHLL_QB_FMT<0b01110>; +class SHRA_PH_ENC : SHLL_QB_FMT<0b01001>; +class SHRAV_PH_ENC : SHLL_QB_FMT<0b01011>; +class SHRA_R_PH_ENC : SHLL_QB_FMT<0b01101>; +class SHRAV_R_PH_ENC : SHLL_QB_FMT<0b01111>; +class SHLL_S_W_ENC : SHLL_QB_FMT<0b10100>; +class SHLLV_S_W_ENC : SHLL_QB_FMT<0b10110>; +class SHRA_R_W_ENC : SHLL_QB_FMT<0b10101>; +class SHRAV_R_W_ENC : SHLL_QB_FMT<0b10111>; +class MULEU_S_PH_QBL_ENC : ADDU_QB_FMT<0b00110>; +class MULEU_S_PH_QBR_ENC : ADDU_QB_FMT<0b00111>; +class MULEQ_S_W_PHL_ENC : ADDU_QB_FMT<0b11100>; +class MULEQ_S_W_PHR_ENC : ADDU_QB_FMT<0b11101>; +class MULQ_RS_PH_ENC : ADDU_QB_FMT<0b11111>; +class MULSAQ_S_W_PH_ENC : DPA_W_PH_FMT<0b00110>; +class MAQ_S_W_PHL_ENC : DPA_W_PH_FMT<0b10100>; +class MAQ_S_W_PHR_ENC : DPA_W_PH_FMT<0b10110>; +class MAQ_SA_W_PHL_ENC : DPA_W_PH_FMT<0b10000>; +class MAQ_SA_W_PHR_ENC : DPA_W_PH_FMT<0b10010>; +class MFHI_ENC : MFHI_FMT<0b010000>; +class MFLO_ENC : MFHI_FMT<0b010010>; +class MTHI_ENC : MTHI_FMT<0b010001>; +class MTLO_ENC : MTHI_FMT<0b010011>; +class DPAU_H_QBL_ENC : DPA_W_PH_FMT<0b00011>; +class DPAU_H_QBR_ENC : DPA_W_PH_FMT<0b00111>; +class DPSU_H_QBL_ENC : DPA_W_PH_FMT<0b01011>; +class DPSU_H_QBR_ENC : DPA_W_PH_FMT<0b01111>; +class DPAQ_S_W_PH_ENC : DPA_W_PH_FMT<0b00100>; +class DPSQ_S_W_PH_ENC : DPA_W_PH_FMT<0b00101>; +class DPAQ_SA_L_W_ENC : DPA_W_PH_FMT<0b01100>; +class DPSQ_SA_L_W_ENC : DPA_W_PH_FMT<0b01101>; +class MULT_DSP_ENC : MULT_FMT<0b000000, 0b011000>; +class MULTU_DSP_ENC : MULT_FMT<0b000000, 0b011001>; +class MADD_DSP_ENC : MULT_FMT<0b011100, 0b000000>; +class MADDU_DSP_ENC : MULT_FMT<0b011100, 0b000001>; +class MSUB_DSP_ENC : MULT_FMT<0b011100, 0b000100>; +class MSUBU_DSP_ENC : MULT_FMT<0b011100, 0b000101>; +class CMPU_EQ_QB_ENC : CMP_EQ_QB_R2_FMT<0b00000>; +class CMPU_LT_QB_ENC : CMP_EQ_QB_R2_FMT<0b00001>; +class CMPU_LE_QB_ENC : CMP_EQ_QB_R2_FMT<0b00010>; +class CMPGU_EQ_QB_ENC : CMP_EQ_QB_R3_FMT<0b00100>; +class CMPGU_LT_QB_ENC : CMP_EQ_QB_R3_FMT<0b00101>; +class CMPGU_LE_QB_ENC : CMP_EQ_QB_R3_FMT<0b00110>; +class CMP_EQ_PH_ENC : CMP_EQ_QB_R2_FMT<0b01000>; +class CMP_LT_PH_ENC : CMP_EQ_QB_R2_FMT<0b01001>; +class CMP_LE_PH_ENC : CMP_EQ_QB_R2_FMT<0b01010>; +class BITREV_ENC : ABSQ_S_PH_R2_FMT<0b11011>; +class PACKRL_PH_ENC : CMP_EQ_QB_R3_FMT<0b01110>; +class REPL_QB_ENC : REPL_FMT<0b00010>; +class REPL_PH_ENC : REPL_FMT<0b01010>; +class REPLV_QB_ENC : ABSQ_S_PH_R2_FMT<0b00011>; +class REPLV_PH_ENC : ABSQ_S_PH_R2_FMT<0b01011>; +class PICK_QB_ENC : CMP_EQ_QB_R3_FMT<0b00011>; +class PICK_PH_ENC : CMP_EQ_QB_R3_FMT<0b01011>; +class LWX_ENC : LX_FMT<0b00000>; +class LHX_ENC : LX_FMT<0b00100>; +class LBUX_ENC : LX_FMT<0b00110>; +class BPOSGE32_ENC : BPOSGE32_FMT<0b11100>; +class INSV_ENC : INSV_FMT<0b001100>; + +class EXTP_ENC : EXTR_W_TY1_FMT<0b00010>; +class EXTPV_ENC : EXTR_W_TY1_FMT<0b00011>; +class EXTPDP_ENC : EXTR_W_TY1_FMT<0b01010>; +class EXTPDPV_ENC : EXTR_W_TY1_FMT<0b01011>; +class EXTR_W_ENC : EXTR_W_TY1_FMT<0b00000>; +class EXTRV_W_ENC : EXTR_W_TY1_FMT<0b00001>; +class EXTR_R_W_ENC : EXTR_W_TY1_FMT<0b00100>; +class EXTRV_R_W_ENC : EXTR_W_TY1_FMT<0b00101>; +class EXTR_RS_W_ENC : EXTR_W_TY1_FMT<0b00110>; +class EXTRV_RS_W_ENC : EXTR_W_TY1_FMT<0b00111>; +class EXTR_S_H_ENC : EXTR_W_TY1_FMT<0b01110>; +class EXTRV_S_H_ENC : EXTR_W_TY1_FMT<0b01111>; +class SHILO_ENC : SHILO_R1_FMT<0b11010>; +class SHILOV_ENC : SHILO_R2_FMT<0b11011>; +class MTHLIP_ENC : SHILO_R2_FMT<0b11111>; + +class RDDSP_ENC : RDDSP_FMT<0b10010>; +class WRDSP_ENC : WRDSP_FMT<0b10011>; +class ADDU_PH_ENC : ADDU_QB_FMT<0b01000>; +class ADDU_S_PH_ENC : ADDU_QB_FMT<0b01100>; +class SUBU_PH_ENC : ADDU_QB_FMT<0b01001>; +class SUBU_S_PH_ENC : ADDU_QB_FMT<0b01101>; +class CMPGDU_EQ_QB_ENC : CMP_EQ_QB_R3_FMT<0b11000>; +class CMPGDU_LT_QB_ENC : CMP_EQ_QB_R3_FMT<0b11001>; +class CMPGDU_LE_QB_ENC : CMP_EQ_QB_R3_FMT<0b11010>; +class ABSQ_S_QB_ENC : ABSQ_S_PH_R2_FMT<0b00001>; +class ADDUH_QB_ENC : ADDUH_QB_FMT<0b00000>; +class ADDUH_R_QB_ENC : ADDUH_QB_FMT<0b00010>; +class SUBUH_QB_ENC : ADDUH_QB_FMT<0b00001>; +class SUBUH_R_QB_ENC : ADDUH_QB_FMT<0b00011>; +class ADDQH_PH_ENC : ADDUH_QB_FMT<0b01000>; +class ADDQH_R_PH_ENC : ADDUH_QB_FMT<0b01010>; +class SUBQH_PH_ENC : ADDUH_QB_FMT<0b01001>; +class SUBQH_R_PH_ENC : ADDUH_QB_FMT<0b01011>; +class ADDQH_W_ENC : ADDUH_QB_FMT<0b10000>; +class ADDQH_R_W_ENC : ADDUH_QB_FMT<0b10010>; +class SUBQH_W_ENC : ADDUH_QB_FMT<0b10001>; +class SUBQH_R_W_ENC : ADDUH_QB_FMT<0b10011>; +class MUL_PH_ENC : ADDUH_QB_FMT<0b01100>; +class MUL_S_PH_ENC : ADDUH_QB_FMT<0b01110>; +class MULQ_S_W_ENC : ADDUH_QB_FMT<0b10110>; +class MULQ_RS_W_ENC : ADDUH_QB_FMT<0b10111>; +class MULQ_S_PH_ENC : ADDU_QB_FMT<0b11110>; +class DPA_W_PH_ENC : DPA_W_PH_FMT<0b00000>; +class DPS_W_PH_ENC : DPA_W_PH_FMT<0b00001>; +class DPAQX_S_W_PH_ENC : DPA_W_PH_FMT<0b11000>; +class DPAQX_SA_W_PH_ENC : DPA_W_PH_FMT<0b11010>; +class DPAX_W_PH_ENC : DPA_W_PH_FMT<0b01000>; +class DPSX_W_PH_ENC : DPA_W_PH_FMT<0b01001>; +class DPSQX_S_W_PH_ENC : DPA_W_PH_FMT<0b11001>; +class DPSQX_SA_W_PH_ENC : DPA_W_PH_FMT<0b11011>; +class MULSA_W_PH_ENC : DPA_W_PH_FMT<0b00010>; +class PRECR_QB_PH_ENC : CMP_EQ_QB_R3_FMT<0b01101>; +class PRECR_SRA_PH_W_ENC : PRECR_SRA_PH_W_FMT<0b11110>; +class PRECR_SRA_R_PH_W_ENC : PRECR_SRA_PH_W_FMT<0b11111>; +class SHRA_QB_ENC : SHLL_QB_FMT<0b00100>; +class SHRAV_QB_ENC : SHLL_QB_FMT<0b00110>; +class SHRA_R_QB_ENC : SHLL_QB_FMT<0b00101>; +class SHRAV_R_QB_ENC : SHLL_QB_FMT<0b00111>; +class SHRL_PH_ENC : SHLL_QB_FMT<0b11001>; +class SHRLV_PH_ENC : SHLL_QB_FMT<0b11011>; +class APPEND_ENC : APPEND_FMT<0b00000>; +class BALIGN_ENC : APPEND_FMT<0b10000>; +class PREPEND_ENC : APPEND_FMT<0b00001>; + +// Instruction desc. +class ADDU_QB_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand ROD, + RegisterOperand ROS, RegisterOperand ROT = ROS> { + dag OutOperandList = (outs ROD:$rd); + dag InOperandList = (ins ROS:$rs, ROT:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt"); + list<dag> Pattern = [(set ROD:$rd, (OpNode ROS:$rs, ROT:$rt))]; + InstrItinClass Itinerary = itin; + string BaseOpcode = instr_asm; +} + +class RADDU_W_QB_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand ROD, + RegisterOperand ROS = ROD> { + dag OutOperandList = (outs ROD:$rd); + dag InOperandList = (ins ROS:$rs); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs"); + list<dag> Pattern = [(set ROD:$rd, (OpNode ROS:$rs))]; + InstrItinClass Itinerary = itin; + string BaseOpcode = instr_asm; +} + +class CMP_EQ_QB_R2_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand ROS, + RegisterOperand ROT = ROS> { + dag OutOperandList = (outs); + dag InOperandList = (ins ROS:$rs, ROT:$rt); + string AsmString = !strconcat(instr_asm, "\t$rs, $rt"); + list<dag> Pattern = [(OpNode ROS:$rs, ROT:$rt)]; + InstrItinClass Itinerary = itin; +} + +class CMP_EQ_QB_R3_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand ROD, + RegisterOperand ROS, RegisterOperand ROT = ROS> { + dag OutOperandList = (outs ROD:$rd); + dag InOperandList = (ins ROS:$rs, ROT:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt"); + list<dag> Pattern = [(set ROD:$rd, (OpNode ROS:$rs, ROT:$rt))]; + InstrItinClass Itinerary = itin; + string BaseOpcode = instr_asm; +} + +class PRECR_SRA_PH_W_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand ROT, + RegisterOperand ROS = ROT> { + dag OutOperandList = (outs ROT:$rt); + dag InOperandList = (ins ROS:$rs, uimm5:$sa, ROS:$src); + string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $sa"); + list<dag> Pattern = [(set ROT:$rt, (OpNode ROS:$src, ROS:$rs, immZExt5:$sa))]; + InstrItinClass Itinerary = itin; + string Constraints = "$src = $rt"; + string BaseOpcode = instr_asm; +} + +class ABSQ_S_PH_R2_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand ROD, + RegisterOperand ROT = ROD> { + dag OutOperandList = (outs ROD:$rd); + dag InOperandList = (ins ROT:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rt"); + list<dag> Pattern = [(set ROD:$rd, (OpNode ROT:$rt))]; + InstrItinClass Itinerary = itin; + string BaseOpcode = instr_asm; +} + +class REPL_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + ImmLeaf immPat, InstrItinClass itin, RegisterOperand RO> { + dag OutOperandList = (outs RO:$rd); + dag InOperandList = (ins uimm16:$imm); + string AsmString = !strconcat(instr_asm, "\t$rd, $imm"); + list<dag> Pattern = [(set RO:$rd, (OpNode immPat:$imm))]; + InstrItinClass Itinerary = itin; + string BaseOpcode = instr_asm; +} + +class SHLL_QB_R3_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand RO> { + dag OutOperandList = (outs RO:$rd); + dag InOperandList = (ins RO:$rt, GPR32Opnd:$rs_sa); + string AsmString = !strconcat(instr_asm, "\t$rd, $rt, $rs_sa"); + list<dag> Pattern = [(set RO:$rd, (OpNode RO:$rt, GPR32Opnd:$rs_sa))]; + InstrItinClass Itinerary = itin; + string BaseOpcode = instr_asm; +} + +class SHLL_QB_R2_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + SDPatternOperator ImmPat, InstrItinClass itin, + RegisterOperand RO, Operand ImmOpnd> { + dag OutOperandList = (outs RO:$rd); + dag InOperandList = (ins RO:$rt, ImmOpnd:$rs_sa); + string AsmString = !strconcat(instr_asm, "\t$rd, $rt, $rs_sa"); + list<dag> Pattern = [(set RO:$rd, (OpNode RO:$rt, ImmPat:$rs_sa))]; + InstrItinClass Itinerary = itin; + bit hasSideEffects = 1; + string BaseOpcode = instr_asm; +} + +class LX_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs GPR32Opnd:$rd); + dag InOperandList = (ins PtrRC:$base, PtrRC:$index); + string AsmString = !strconcat(instr_asm, "\t$rd, ${index}(${base})"); + list<dag> Pattern = [(set GPR32Opnd:$rd, (OpNode iPTR:$base, iPTR:$index))]; + InstrItinClass Itinerary = itin; + bit mayLoad = 1; + string BaseOpcode = instr_asm; +} + +class ADDUH_QB_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand ROD, + RegisterOperand ROS = ROD, RegisterOperand ROT = ROD> { + dag OutOperandList = (outs ROD:$rd); + dag InOperandList = (ins ROS:$rs, ROT:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt"); + list<dag> Pattern = [(set ROD:$rd, (OpNode ROS:$rs, ROT:$rt))]; + InstrItinClass Itinerary = itin; + string BaseOpcode = instr_asm; +} + +class APPEND_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + Operand ImmOp, SDPatternOperator Imm, InstrItinClass itin> { + dag OutOperandList = (outs GPR32Opnd:$rt); + dag InOperandList = (ins GPR32Opnd:$rs, ImmOp:$sa, GPR32Opnd:$src); + string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $sa"); + list<dag> Pattern = [(set GPR32Opnd:$rt, + (OpNode GPR32Opnd:$src, GPR32Opnd:$rs, Imm:$sa))]; + InstrItinClass Itinerary = itin; + string Constraints = "$src = $rt"; + string BaseOpcode = instr_asm; +} + +class EXTR_W_TY1_R2_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs GPR32Opnd:$rt); + dag InOperandList = (ins ACC64DSPOpnd:$ac, GPR32Opnd:$shift_rs); + string AsmString = !strconcat(instr_asm, "\t$rt, $ac, $shift_rs"); + InstrItinClass Itinerary = itin; + string BaseOpcode = instr_asm; +} + +class EXTR_W_TY1_R1_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs GPR32Opnd:$rt); + dag InOperandList = (ins ACC64DSPOpnd:$ac, uimm16:$shift_rs); + string AsmString = !strconcat(instr_asm, "\t$rt, $ac, $shift_rs"); + InstrItinClass Itinerary = itin; + string BaseOpcode = instr_asm; +} + +class SHILO_R1_DESC_BASE<string instr_asm, SDPatternOperator OpNode> { + dag OutOperandList = (outs ACC64DSPOpnd:$ac); + dag InOperandList = (ins simm6:$shift, ACC64DSPOpnd:$acin); + string AsmString = !strconcat(instr_asm, "\t$ac, $shift"); + list<dag> Pattern = [(set ACC64DSPOpnd:$ac, + (OpNode immSExt6:$shift, ACC64DSPOpnd:$acin))]; + string Constraints = "$acin = $ac"; + string BaseOpcode = instr_asm; +} + +class SHILO_R2_DESC_BASE<string instr_asm, SDPatternOperator OpNode> { + dag OutOperandList = (outs ACC64DSPOpnd:$ac); + dag InOperandList = (ins GPR32Opnd:$rs, ACC64DSPOpnd:$acin); + string AsmString = !strconcat(instr_asm, "\t$ac, $rs"); + list<dag> Pattern = [(set ACC64DSPOpnd:$ac, + (OpNode GPR32Opnd:$rs, ACC64DSPOpnd:$acin))]; + string Constraints = "$acin = $ac"; + string BaseOpcode = instr_asm; +} + +class MTHLIP_DESC_BASE<string instr_asm, SDPatternOperator OpNode> { + dag OutOperandList = (outs ACC64DSPOpnd:$ac); + dag InOperandList = (ins GPR32Opnd:$rs, ACC64DSPOpnd:$acin); + string AsmString = !strconcat(instr_asm, "\t$rs, $ac"); + list<dag> Pattern = [(set ACC64DSPOpnd:$ac, + (OpNode GPR32Opnd:$rs, ACC64DSPOpnd:$acin))]; + string Constraints = "$acin = $ac"; + string BaseOpcode = instr_asm; +} + +class RDDSP_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs GPR32Opnd:$rd); + dag InOperandList = (ins uimm16:$mask); + string AsmString = !strconcat(instr_asm, "\t$rd, $mask"); + list<dag> Pattern = [(set GPR32Opnd:$rd, (OpNode immZExt10:$mask))]; + InstrItinClass Itinerary = itin; + string BaseOpcode = instr_asm; +} + +class WRDSP_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs); + dag InOperandList = (ins GPR32Opnd:$rs, uimm10:$mask); + string AsmString = !strconcat(instr_asm, "\t$rs, $mask"); + list<dag> Pattern = [(OpNode GPR32Opnd:$rs, immZExt10:$mask)]; + InstrItinClass Itinerary = itin; + string BaseOpcode = instr_asm; +} + +class DPA_W_PH_DESC_BASE<string instr_asm, SDPatternOperator OpNode> { + dag OutOperandList = (outs ACC64DSPOpnd:$ac); + dag InOperandList = (ins GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64DSPOpnd:$acin); + string AsmString = !strconcat(instr_asm, "\t$ac, $rs, $rt"); + list<dag> Pattern = [(set ACC64DSPOpnd:$ac, + (OpNode GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64DSPOpnd:$acin))]; + string Constraints = "$acin = $ac"; + string BaseOpcode = instr_asm; +} + +class MULT_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs ACC64DSPOpnd:$ac); + dag InOperandList = (ins GPR32Opnd:$rs, GPR32Opnd:$rt); + string AsmString = !strconcat(instr_asm, "\t$ac, $rs, $rt"); + list<dag> Pattern = [(set ACC64DSPOpnd:$ac, (OpNode GPR32Opnd:$rs, GPR32Opnd:$rt))]; + InstrItinClass Itinerary = itin; + bit isCommutable = 1; + string BaseOpcode = instr_asm; +} + +class MADD_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs ACC64DSPOpnd:$ac); + dag InOperandList = (ins GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64DSPOpnd:$acin); + string AsmString = !strconcat(instr_asm, "\t$ac, $rs, $rt"); + list<dag> Pattern = [(set ACC64DSPOpnd:$ac, + (OpNode GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64DSPOpnd:$acin))]; + InstrItinClass Itinerary = itin; + string Constraints = "$acin = $ac"; + string BaseOpcode = instr_asm; +} + +class MFHI_DESC_BASE<string instr_asm, RegisterOperand RO, SDNode OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs GPR32Opnd:$rd); + dag InOperandList = (ins RO:$ac); + string AsmString = !strconcat(instr_asm, "\t$rd, $ac"); + list<dag> Pattern = [(set GPR32Opnd:$rd, (OpNode RO:$ac))]; + InstrItinClass Itinerary = itin; + string BaseOpcode = instr_asm; +} + +class MTHI_DESC_BASE<string instr_asm, RegisterOperand RO, InstrItinClass itin> { + dag OutOperandList = (outs RO:$ac); + dag InOperandList = (ins GPR32Opnd:$rs); + string AsmString = !strconcat(instr_asm, "\t$rs, $ac"); + InstrItinClass Itinerary = itin; + string BaseOpcode = instr_asm; +} + +class BPOSGE32_PSEUDO_DESC_BASE<SDPatternOperator OpNode, InstrItinClass itin> : + MipsPseudo<(outs GPR32Opnd:$dst), (ins), [(set GPR32Opnd:$dst, (OpNode))]> { + bit usesCustomInserter = 1; +} + +class BPOSGE32_DESC_BASE<string instr_asm, InstrItinClass itin> { + dag OutOperandList = (outs); + dag InOperandList = (ins brtarget:$offset); + string AsmString = !strconcat(instr_asm, "\t$offset"); + InstrItinClass Itinerary = itin; + bit isBranch = 1; + bit isTerminator = 1; + bit hasDelaySlot = 1; +} + +class INSV_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs GPR32Opnd:$rt); + dag InOperandList = (ins GPR32Opnd:$src, GPR32Opnd:$rs); + string AsmString = !strconcat(instr_asm, "\t$rt, $rs"); + list<dag> Pattern = [(set GPR32Opnd:$rt, (OpNode GPR32Opnd:$src, GPR32Opnd:$rs))]; + InstrItinClass Itinerary = itin; + string Constraints = "$src = $rt"; + string BaseOpcode = instr_asm; +} + +//===----------------------------------------------------------------------===// +// MIPS DSP Rev 1 +//===----------------------------------------------------------------------===// + +// Addition/subtraction +class ADDU_QB_DESC : ADDU_QB_DESC_BASE<"addu.qb", null_frag, NoItinerary, + DSPROpnd, DSPROpnd>, IsCommutable, + Defs<[DSPOutFlag20]>; + +class ADDU_S_QB_DESC : ADDU_QB_DESC_BASE<"addu_s.qb", int_mips_addu_s_qb, + NoItinerary, DSPROpnd, DSPROpnd>, + IsCommutable, Defs<[DSPOutFlag20]>; + +class SUBU_QB_DESC : ADDU_QB_DESC_BASE<"subu.qb", null_frag, NoItinerary, + DSPROpnd, DSPROpnd>, + Defs<[DSPOutFlag20]>; + +class SUBU_S_QB_DESC : ADDU_QB_DESC_BASE<"subu_s.qb", int_mips_subu_s_qb, + NoItinerary, DSPROpnd, DSPROpnd>, + Defs<[DSPOutFlag20]>; + +class ADDQ_PH_DESC : ADDU_QB_DESC_BASE<"addq.ph", null_frag, NoItinerary, + DSPROpnd, DSPROpnd>, IsCommutable, + Defs<[DSPOutFlag20]>; + +class ADDQ_S_PH_DESC : ADDU_QB_DESC_BASE<"addq_s.ph", int_mips_addq_s_ph, + NoItinerary, DSPROpnd, DSPROpnd>, + IsCommutable, Defs<[DSPOutFlag20]>; + +class SUBQ_PH_DESC : ADDU_QB_DESC_BASE<"subq.ph", null_frag, NoItinerary, + DSPROpnd, DSPROpnd>, + Defs<[DSPOutFlag20]>; + +class SUBQ_S_PH_DESC : ADDU_QB_DESC_BASE<"subq_s.ph", int_mips_subq_s_ph, + NoItinerary, DSPROpnd, DSPROpnd>, + Defs<[DSPOutFlag20]>; + +class ADDQ_S_W_DESC : ADDU_QB_DESC_BASE<"addq_s.w", int_mips_addq_s_w, + NoItinerary, GPR32Opnd, GPR32Opnd>, + IsCommutable, Defs<[DSPOutFlag20]>; + +class SUBQ_S_W_DESC : ADDU_QB_DESC_BASE<"subq_s.w", int_mips_subq_s_w, + NoItinerary, GPR32Opnd, GPR32Opnd>, + Defs<[DSPOutFlag20]>; + +class ADDSC_DESC : ADDU_QB_DESC_BASE<"addsc", null_frag, NoItinerary, + GPR32Opnd, GPR32Opnd>, IsCommutable, + Defs<[DSPCarry]>; + +class ADDWC_DESC : ADDU_QB_DESC_BASE<"addwc", null_frag, NoItinerary, + GPR32Opnd, GPR32Opnd>, + IsCommutable, Uses<[DSPCarry]>, Defs<[DSPOutFlag20]>; + +class MODSUB_DESC : ADDU_QB_DESC_BASE<"modsub", int_mips_modsub, NoItinerary, + GPR32Opnd, GPR32Opnd>; + +class RADDU_W_QB_DESC : RADDU_W_QB_DESC_BASE<"raddu.w.qb", int_mips_raddu_w_qb, + NoItinerary, GPR32Opnd, DSPROpnd>; + +// Absolute value +class ABSQ_S_PH_DESC : ABSQ_S_PH_R2_DESC_BASE<"absq_s.ph", int_mips_absq_s_ph, + NoItinerary, DSPROpnd>, + Defs<[DSPOutFlag20]>; + +class ABSQ_S_W_DESC : ABSQ_S_PH_R2_DESC_BASE<"absq_s.w", int_mips_absq_s_w, + NoItinerary, GPR32Opnd>, + Defs<[DSPOutFlag20]>; + +// Precision reduce/expand +class PRECRQ_QB_PH_DESC : CMP_EQ_QB_R3_DESC_BASE<"precrq.qb.ph", + int_mips_precrq_qb_ph, + NoItinerary, DSPROpnd, DSPROpnd>; + +class PRECRQ_PH_W_DESC : CMP_EQ_QB_R3_DESC_BASE<"precrq.ph.w", + int_mips_precrq_ph_w, + NoItinerary, DSPROpnd, GPR32Opnd>; + +class PRECRQ_RS_PH_W_DESC : CMP_EQ_QB_R3_DESC_BASE<"precrq_rs.ph.w", + int_mips_precrq_rs_ph_w, + NoItinerary, DSPROpnd, + GPR32Opnd>, + Defs<[DSPOutFlag22]>; + +class PRECRQU_S_QB_PH_DESC : CMP_EQ_QB_R3_DESC_BASE<"precrqu_s.qb.ph", + int_mips_precrqu_s_qb_ph, + NoItinerary, DSPROpnd, + DSPROpnd>, + Defs<[DSPOutFlag22]>; + +class PRECEQ_W_PHL_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceq.w.phl", + int_mips_preceq_w_phl, + NoItinerary, GPR32Opnd, DSPROpnd>; + +class PRECEQ_W_PHR_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceq.w.phr", + int_mips_preceq_w_phr, + NoItinerary, GPR32Opnd, DSPROpnd>; + +class PRECEQU_PH_QBL_DESC : ABSQ_S_PH_R2_DESC_BASE<"precequ.ph.qbl", + int_mips_precequ_ph_qbl, + NoItinerary, DSPROpnd>; + +class PRECEQU_PH_QBR_DESC : ABSQ_S_PH_R2_DESC_BASE<"precequ.ph.qbr", + int_mips_precequ_ph_qbr, + NoItinerary, DSPROpnd>; + +class PRECEQU_PH_QBLA_DESC : ABSQ_S_PH_R2_DESC_BASE<"precequ.ph.qbla", + int_mips_precequ_ph_qbla, + NoItinerary, DSPROpnd>; + +class PRECEQU_PH_QBRA_DESC : ABSQ_S_PH_R2_DESC_BASE<"precequ.ph.qbra", + int_mips_precequ_ph_qbra, + NoItinerary, DSPROpnd>; + +class PRECEU_PH_QBL_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceu.ph.qbl", + int_mips_preceu_ph_qbl, + NoItinerary, DSPROpnd>; + +class PRECEU_PH_QBR_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceu.ph.qbr", + int_mips_preceu_ph_qbr, + NoItinerary, DSPROpnd>; + +class PRECEU_PH_QBLA_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceu.ph.qbla", + int_mips_preceu_ph_qbla, + NoItinerary, DSPROpnd>; + +class PRECEU_PH_QBRA_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceu.ph.qbra", + int_mips_preceu_ph_qbra, + NoItinerary, DSPROpnd>; + +// Shift +class SHLL_QB_DESC : SHLL_QB_R2_DESC_BASE<"shll.qb", null_frag, immZExt3, + NoItinerary, DSPROpnd, uimm3>, + Defs<[DSPOutFlag22]>; + +class SHLLV_QB_DESC : SHLL_QB_R3_DESC_BASE<"shllv.qb", int_mips_shll_qb, + NoItinerary, DSPROpnd>, + Defs<[DSPOutFlag22]>; + +class SHRL_QB_DESC : SHLL_QB_R2_DESC_BASE<"shrl.qb", null_frag, immZExt3, + NoItinerary, DSPROpnd, uimm3>; + +class SHRLV_QB_DESC : SHLL_QB_R3_DESC_BASE<"shrlv.qb", int_mips_shrl_qb, + NoItinerary, DSPROpnd>; + +class SHLL_PH_DESC : SHLL_QB_R2_DESC_BASE<"shll.ph", null_frag, immZExt4, + NoItinerary, DSPROpnd, uimm4>, + Defs<[DSPOutFlag22]>; + +class SHLLV_PH_DESC : SHLL_QB_R3_DESC_BASE<"shllv.ph", int_mips_shll_ph, + NoItinerary, DSPROpnd>, + Defs<[DSPOutFlag22]>; + +class SHLL_S_PH_DESC : SHLL_QB_R2_DESC_BASE<"shll_s.ph", int_mips_shll_s_ph, + immZExt4, NoItinerary, DSPROpnd, + uimm4>, + Defs<[DSPOutFlag22]>; + +class SHLLV_S_PH_DESC : SHLL_QB_R3_DESC_BASE<"shllv_s.ph", int_mips_shll_s_ph, + NoItinerary, DSPROpnd>, + Defs<[DSPOutFlag22]>; + +class SHRA_PH_DESC : SHLL_QB_R2_DESC_BASE<"shra.ph", null_frag, immZExt4, + NoItinerary, DSPROpnd, uimm4>; + +class SHRAV_PH_DESC : SHLL_QB_R3_DESC_BASE<"shrav.ph", int_mips_shra_ph, + NoItinerary, DSPROpnd>; + +class SHRA_R_PH_DESC : SHLL_QB_R2_DESC_BASE<"shra_r.ph", int_mips_shra_r_ph, + immZExt4, NoItinerary, DSPROpnd, + uimm4>; + +class SHRAV_R_PH_DESC : SHLL_QB_R3_DESC_BASE<"shrav_r.ph", int_mips_shra_r_ph, + NoItinerary, DSPROpnd>; + +class SHLL_S_W_DESC : SHLL_QB_R2_DESC_BASE<"shll_s.w", int_mips_shll_s_w, + immZExt5, NoItinerary, GPR32Opnd, + uimm5>, + Defs<[DSPOutFlag22]>; + +class SHLLV_S_W_DESC : SHLL_QB_R3_DESC_BASE<"shllv_s.w", int_mips_shll_s_w, + NoItinerary, GPR32Opnd>, + Defs<[DSPOutFlag22]>; + +class SHRA_R_W_DESC : SHLL_QB_R2_DESC_BASE<"shra_r.w", int_mips_shra_r_w, + immZExt5, NoItinerary, GPR32Opnd, + uimm5>; + +class SHRAV_R_W_DESC : SHLL_QB_R3_DESC_BASE<"shrav_r.w", int_mips_shra_r_w, + NoItinerary, GPR32Opnd>; + +// Multiplication +class MULEU_S_PH_QBL_DESC : ADDU_QB_DESC_BASE<"muleu_s.ph.qbl", + int_mips_muleu_s_ph_qbl, + NoItinerary, DSPROpnd, DSPROpnd>, + Defs<[DSPOutFlag21]>; + +class MULEU_S_PH_QBR_DESC : ADDU_QB_DESC_BASE<"muleu_s.ph.qbr", + int_mips_muleu_s_ph_qbr, + NoItinerary, DSPROpnd, DSPROpnd>, + Defs<[DSPOutFlag21]>; + +class MULEQ_S_W_PHL_DESC : ADDU_QB_DESC_BASE<"muleq_s.w.phl", + int_mips_muleq_s_w_phl, + NoItinerary, GPR32Opnd, DSPROpnd>, + IsCommutable, Defs<[DSPOutFlag21]>; + +class MULEQ_S_W_PHR_DESC : ADDU_QB_DESC_BASE<"muleq_s.w.phr", + int_mips_muleq_s_w_phr, + NoItinerary, GPR32Opnd, DSPROpnd>, + IsCommutable, Defs<[DSPOutFlag21]>; + +class MULQ_RS_PH_DESC : ADDU_QB_DESC_BASE<"mulq_rs.ph", int_mips_mulq_rs_ph, + NoItinerary, DSPROpnd, DSPROpnd>, + IsCommutable, Defs<[DSPOutFlag21]>; + +class MULSAQ_S_W_PH_DESC : DPA_W_PH_DESC_BASE<"mulsaq_s.w.ph", + MipsMULSAQ_S_W_PH>, + Defs<[DSPOutFlag16_19]>; + +class MAQ_S_W_PHL_DESC : DPA_W_PH_DESC_BASE<"maq_s.w.phl", MipsMAQ_S_W_PHL>, + Defs<[DSPOutFlag16_19]>; + +class MAQ_S_W_PHR_DESC : DPA_W_PH_DESC_BASE<"maq_s.w.phr", MipsMAQ_S_W_PHR>, + Defs<[DSPOutFlag16_19]>; + +class MAQ_SA_W_PHL_DESC : DPA_W_PH_DESC_BASE<"maq_sa.w.phl", MipsMAQ_SA_W_PHL>, + Defs<[DSPOutFlag16_19]>; + +class MAQ_SA_W_PHR_DESC : DPA_W_PH_DESC_BASE<"maq_sa.w.phr", MipsMAQ_SA_W_PHR>, + Defs<[DSPOutFlag16_19]>; + +// Move from/to hi/lo. +class MFHI_DESC : MFHI_DESC_BASE<"mfhi", ACC64DSPOpnd, MipsMFHI, NoItinerary>; +class MFLO_DESC : MFHI_DESC_BASE<"mflo", ACC64DSPOpnd, MipsMFLO, NoItinerary>; +class MTHI_DESC : MTHI_DESC_BASE<"mthi", HI32DSPOpnd, NoItinerary>; +class MTLO_DESC : MTHI_DESC_BASE<"mtlo", LO32DSPOpnd, NoItinerary>; + +// Dot product with accumulate/subtract +class DPAU_H_QBL_DESC : DPA_W_PH_DESC_BASE<"dpau.h.qbl", MipsDPAU_H_QBL>; + +class DPAU_H_QBR_DESC : DPA_W_PH_DESC_BASE<"dpau.h.qbr", MipsDPAU_H_QBR>; + +class DPSU_H_QBL_DESC : DPA_W_PH_DESC_BASE<"dpsu.h.qbl", MipsDPSU_H_QBL>; + +class DPSU_H_QBR_DESC : DPA_W_PH_DESC_BASE<"dpsu.h.qbr", MipsDPSU_H_QBR>; + +class DPAQ_S_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpaq_s.w.ph", MipsDPAQ_S_W_PH>, + Defs<[DSPOutFlag16_19]>; + +class DPSQ_S_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpsq_s.w.ph", MipsDPSQ_S_W_PH>, + Defs<[DSPOutFlag16_19]>; + +class DPAQ_SA_L_W_DESC : DPA_W_PH_DESC_BASE<"dpaq_sa.l.w", MipsDPAQ_SA_L_W>, + Defs<[DSPOutFlag16_19]>; + +class DPSQ_SA_L_W_DESC : DPA_W_PH_DESC_BASE<"dpsq_sa.l.w", MipsDPSQ_SA_L_W>, + Defs<[DSPOutFlag16_19]>; + +class MULT_DSP_DESC : MULT_DESC_BASE<"mult", MipsMult, NoItinerary>; +class MULTU_DSP_DESC : MULT_DESC_BASE<"multu", MipsMultu, NoItinerary>; +class MADD_DSP_DESC : MADD_DESC_BASE<"madd", MipsMAdd, NoItinerary>; +class MADDU_DSP_DESC : MADD_DESC_BASE<"maddu", MipsMAddu, NoItinerary>; +class MSUB_DSP_DESC : MADD_DESC_BASE<"msub", MipsMSub, NoItinerary>; +class MSUBU_DSP_DESC : MADD_DESC_BASE<"msubu", MipsMSubu, NoItinerary>; + +// Comparison +class CMPU_EQ_QB_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmpu.eq.qb", + int_mips_cmpu_eq_qb, NoItinerary, + DSPROpnd>, + IsCommutable, Defs<[DSPCCond]>; + +class CMPU_LT_QB_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmpu.lt.qb", + int_mips_cmpu_lt_qb, NoItinerary, + DSPROpnd>, Defs<[DSPCCond]>; + +class CMPU_LE_QB_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmpu.le.qb", + int_mips_cmpu_le_qb, NoItinerary, + DSPROpnd>, Defs<[DSPCCond]>; + +class CMPGU_EQ_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgu.eq.qb", + int_mips_cmpgu_eq_qb, + NoItinerary, GPR32Opnd, DSPROpnd>, + IsCommutable; + +class CMPGU_LT_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgu.lt.qb", + int_mips_cmpgu_lt_qb, + NoItinerary, GPR32Opnd, DSPROpnd>; + +class CMPGU_LE_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgu.le.qb", + int_mips_cmpgu_le_qb, + NoItinerary, GPR32Opnd, DSPROpnd>; + +class CMP_EQ_PH_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmp.eq.ph", int_mips_cmp_eq_ph, + NoItinerary, DSPROpnd>, + IsCommutable, Defs<[DSPCCond]>; + +class CMP_LT_PH_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmp.lt.ph", int_mips_cmp_lt_ph, + NoItinerary, DSPROpnd>, + Defs<[DSPCCond]>; + +class CMP_LE_PH_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmp.le.ph", int_mips_cmp_le_ph, + NoItinerary, DSPROpnd>, + Defs<[DSPCCond]>; + +// Misc +class BITREV_DESC : ABSQ_S_PH_R2_DESC_BASE<"bitrev", int_mips_bitrev, + NoItinerary, GPR32Opnd>; + +class PACKRL_PH_DESC : CMP_EQ_QB_R3_DESC_BASE<"packrl.ph", int_mips_packrl_ph, + NoItinerary, DSPROpnd, DSPROpnd>; + +class REPL_QB_DESC : REPL_DESC_BASE<"repl.qb", int_mips_repl_qb, immZExt8, + NoItinerary, DSPROpnd>; + +class REPL_PH_DESC : REPL_DESC_BASE<"repl.ph", int_mips_repl_ph, immZExt10, + NoItinerary, DSPROpnd>; + +class REPLV_QB_DESC : ABSQ_S_PH_R2_DESC_BASE<"replv.qb", int_mips_repl_qb, + NoItinerary, DSPROpnd, GPR32Opnd>; + +class REPLV_PH_DESC : ABSQ_S_PH_R2_DESC_BASE<"replv.ph", int_mips_repl_ph, + NoItinerary, DSPROpnd, GPR32Opnd>; + +class PICK_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"pick.qb", int_mips_pick_qb, + NoItinerary, DSPROpnd, DSPROpnd>, + Uses<[DSPCCond]>; + +class PICK_PH_DESC : CMP_EQ_QB_R3_DESC_BASE<"pick.ph", int_mips_pick_ph, + NoItinerary, DSPROpnd, DSPROpnd>, + Uses<[DSPCCond]>; + +class LWX_DESC : LX_DESC_BASE<"lwx", int_mips_lwx, NoItinerary>; + +class LHX_DESC : LX_DESC_BASE<"lhx", int_mips_lhx, NoItinerary>; + +class LBUX_DESC : LX_DESC_BASE<"lbux", int_mips_lbux, NoItinerary>; + +class BPOSGE32_DESC : BPOSGE32_DESC_BASE<"bposge32", NoItinerary>; + +// Extr +class EXTP_DESC : EXTR_W_TY1_R1_DESC_BASE<"extp", MipsEXTP, NoItinerary>, + Uses<[DSPPos]>, Defs<[DSPEFI]>; + +class EXTPV_DESC : EXTR_W_TY1_R2_DESC_BASE<"extpv", MipsEXTP, NoItinerary>, + Uses<[DSPPos]>, Defs<[DSPEFI]>; + +class EXTPDP_DESC : EXTR_W_TY1_R1_DESC_BASE<"extpdp", MipsEXTPDP, NoItinerary>, + Uses<[DSPPos]>, Defs<[DSPPos, DSPEFI]>; + +class EXTPDPV_DESC : EXTR_W_TY1_R2_DESC_BASE<"extpdpv", MipsEXTPDP, + NoItinerary>, + Uses<[DSPPos]>, Defs<[DSPPos, DSPEFI]>; + +class EXTR_W_DESC : EXTR_W_TY1_R1_DESC_BASE<"extr.w", MipsEXTR_W, NoItinerary>, + Defs<[DSPOutFlag23]>; + +class EXTRV_W_DESC : EXTR_W_TY1_R2_DESC_BASE<"extrv.w", MipsEXTR_W, + NoItinerary>, Defs<[DSPOutFlag23]>; + +class EXTR_R_W_DESC : EXTR_W_TY1_R1_DESC_BASE<"extr_r.w", MipsEXTR_R_W, + NoItinerary>, + Defs<[DSPOutFlag23]>; + +class EXTRV_R_W_DESC : EXTR_W_TY1_R2_DESC_BASE<"extrv_r.w", MipsEXTR_R_W, + NoItinerary>, + Defs<[DSPOutFlag23]>; + +class EXTR_RS_W_DESC : EXTR_W_TY1_R1_DESC_BASE<"extr_rs.w", MipsEXTR_RS_W, + NoItinerary>, + Defs<[DSPOutFlag23]>; + +class EXTRV_RS_W_DESC : EXTR_W_TY1_R2_DESC_BASE<"extrv_rs.w", MipsEXTR_RS_W, + NoItinerary>, + Defs<[DSPOutFlag23]>; + +class EXTR_S_H_DESC : EXTR_W_TY1_R1_DESC_BASE<"extr_s.h", MipsEXTR_S_H, + NoItinerary>, + Defs<[DSPOutFlag23]>; + +class EXTRV_S_H_DESC : EXTR_W_TY1_R2_DESC_BASE<"extrv_s.h", MipsEXTR_S_H, + NoItinerary>, + Defs<[DSPOutFlag23]>; + +class SHILO_DESC : SHILO_R1_DESC_BASE<"shilo", MipsSHILO>; + +class SHILOV_DESC : SHILO_R2_DESC_BASE<"shilov", MipsSHILO>; + +class MTHLIP_DESC : MTHLIP_DESC_BASE<"mthlip", MipsMTHLIP>, Defs<[DSPPos]>; + +class RDDSP_DESC : RDDSP_DESC_BASE<"rddsp", int_mips_rddsp, NoItinerary>; + +class WRDSP_DESC : WRDSP_DESC_BASE<"wrdsp", int_mips_wrdsp, NoItinerary>; + +class INSV_DESC : INSV_DESC_BASE<"insv", int_mips_insv, NoItinerary>, + Uses<[DSPPos, DSPSCount]>; + +//===----------------------------------------------------------------------===// +// MIPS DSP Rev 2 +// Addition/subtraction +class ADDU_PH_DESC : ADDU_QB_DESC_BASE<"addu.ph", int_mips_addu_ph, NoItinerary, + DSPROpnd, DSPROpnd>, IsCommutable, + Defs<[DSPOutFlag20]>; + +class ADDU_S_PH_DESC : ADDU_QB_DESC_BASE<"addu_s.ph", int_mips_addu_s_ph, + NoItinerary, DSPROpnd, DSPROpnd>, + IsCommutable, Defs<[DSPOutFlag20]>; + +class SUBU_PH_DESC : ADDU_QB_DESC_BASE<"subu.ph", int_mips_subu_ph, NoItinerary, + DSPROpnd, DSPROpnd>, + Defs<[DSPOutFlag20]>; + +class SUBU_S_PH_DESC : ADDU_QB_DESC_BASE<"subu_s.ph", int_mips_subu_s_ph, + NoItinerary, DSPROpnd, DSPROpnd>, + Defs<[DSPOutFlag20]>; + +class ADDUH_QB_DESC : ADDUH_QB_DESC_BASE<"adduh.qb", int_mips_adduh_qb, + NoItinerary, DSPROpnd>, IsCommutable; + +class ADDUH_R_QB_DESC : ADDUH_QB_DESC_BASE<"adduh_r.qb", int_mips_adduh_r_qb, + NoItinerary, DSPROpnd>, IsCommutable; + +class SUBUH_QB_DESC : ADDUH_QB_DESC_BASE<"subuh.qb", int_mips_subuh_qb, + NoItinerary, DSPROpnd>; + +class SUBUH_R_QB_DESC : ADDUH_QB_DESC_BASE<"subuh_r.qb", int_mips_subuh_r_qb, + NoItinerary, DSPROpnd>; + +class ADDQH_PH_DESC : ADDUH_QB_DESC_BASE<"addqh.ph", int_mips_addqh_ph, + NoItinerary, DSPROpnd>, IsCommutable; + +class ADDQH_R_PH_DESC : ADDUH_QB_DESC_BASE<"addqh_r.ph", int_mips_addqh_r_ph, + NoItinerary, DSPROpnd>, IsCommutable; + +class SUBQH_PH_DESC : ADDUH_QB_DESC_BASE<"subqh.ph", int_mips_subqh_ph, + NoItinerary, DSPROpnd>; + +class SUBQH_R_PH_DESC : ADDUH_QB_DESC_BASE<"subqh_r.ph", int_mips_subqh_r_ph, + NoItinerary, DSPROpnd>; + +class ADDQH_W_DESC : ADDUH_QB_DESC_BASE<"addqh.w", int_mips_addqh_w, + NoItinerary, GPR32Opnd>, IsCommutable; + +class ADDQH_R_W_DESC : ADDUH_QB_DESC_BASE<"addqh_r.w", int_mips_addqh_r_w, + NoItinerary, GPR32Opnd>, IsCommutable; + +class SUBQH_W_DESC : ADDUH_QB_DESC_BASE<"subqh.w", int_mips_subqh_w, + NoItinerary, GPR32Opnd>; + +class SUBQH_R_W_DESC : ADDUH_QB_DESC_BASE<"subqh_r.w", int_mips_subqh_r_w, + NoItinerary, GPR32Opnd>; + +// Comparison +class CMPGDU_EQ_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgdu.eq.qb", + int_mips_cmpgdu_eq_qb, + NoItinerary, GPR32Opnd, DSPROpnd>, + IsCommutable, Defs<[DSPCCond]>; + +class CMPGDU_LT_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgdu.lt.qb", + int_mips_cmpgdu_lt_qb, + NoItinerary, GPR32Opnd, DSPROpnd>, + Defs<[DSPCCond]>; + +class CMPGDU_LE_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgdu.le.qb", + int_mips_cmpgdu_le_qb, + NoItinerary, GPR32Opnd, DSPROpnd>, + Defs<[DSPCCond]>; + +// Absolute +class ABSQ_S_QB_DESC : ABSQ_S_PH_R2_DESC_BASE<"absq_s.qb", int_mips_absq_s_qb, + NoItinerary, DSPROpnd>, + Defs<[DSPOutFlag20]>; + +// Multiplication +class MUL_PH_DESC : ADDUH_QB_DESC_BASE<"mul.ph", null_frag, NoItinerary, + DSPROpnd>, IsCommutable, + Defs<[DSPOutFlag21]>; + +class MUL_S_PH_DESC : ADDUH_QB_DESC_BASE<"mul_s.ph", int_mips_mul_s_ph, + NoItinerary, DSPROpnd>, IsCommutable, + Defs<[DSPOutFlag21]>; + +class MULQ_S_W_DESC : ADDUH_QB_DESC_BASE<"mulq_s.w", int_mips_mulq_s_w, + NoItinerary, GPR32Opnd>, IsCommutable, + Defs<[DSPOutFlag21]>; + +class MULQ_RS_W_DESC : ADDUH_QB_DESC_BASE<"mulq_rs.w", int_mips_mulq_rs_w, + NoItinerary, GPR32Opnd>, IsCommutable, + Defs<[DSPOutFlag21]>; + +class MULQ_S_PH_DESC : ADDU_QB_DESC_BASE<"mulq_s.ph", int_mips_mulq_s_ph, + NoItinerary, DSPROpnd, DSPROpnd>, + IsCommutable, Defs<[DSPOutFlag21]>; + +// Dot product with accumulate/subtract +class DPA_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpa.w.ph", MipsDPA_W_PH>; + +class DPS_W_PH_DESC : DPA_W_PH_DESC_BASE<"dps.w.ph", MipsDPS_W_PH>; + +class DPAQX_S_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpaqx_s.w.ph", MipsDPAQX_S_W_PH>, + Defs<[DSPOutFlag16_19]>; + +class DPAQX_SA_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpaqx_sa.w.ph", + MipsDPAQX_SA_W_PH>, + Defs<[DSPOutFlag16_19]>; + +class DPAX_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpax.w.ph", MipsDPAX_W_PH>; + +class DPSX_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpsx.w.ph", MipsDPSX_W_PH>; + +class DPSQX_S_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpsqx_s.w.ph", MipsDPSQX_S_W_PH>, + Defs<[DSPOutFlag16_19]>; + +class DPSQX_SA_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpsqx_sa.w.ph", + MipsDPSQX_SA_W_PH>, + Defs<[DSPOutFlag16_19]>; + +class MULSA_W_PH_DESC : DPA_W_PH_DESC_BASE<"mulsa.w.ph", MipsMULSA_W_PH>; + +// Precision reduce/expand +class PRECR_QB_PH_DESC : CMP_EQ_QB_R3_DESC_BASE<"precr.qb.ph", + int_mips_precr_qb_ph, + NoItinerary, DSPROpnd, DSPROpnd>; + +class PRECR_SRA_PH_W_DESC : PRECR_SRA_PH_W_DESC_BASE<"precr_sra.ph.w", + int_mips_precr_sra_ph_w, + NoItinerary, DSPROpnd, + GPR32Opnd>; + +class PRECR_SRA_R_PH_W_DESC : PRECR_SRA_PH_W_DESC_BASE<"precr_sra_r.ph.w", + int_mips_precr_sra_r_ph_w, + NoItinerary, DSPROpnd, + GPR32Opnd>; + +// Shift +class SHRA_QB_DESC : SHLL_QB_R2_DESC_BASE<"shra.qb", null_frag, immZExt3, + NoItinerary, DSPROpnd, uimm3>; + +class SHRAV_QB_DESC : SHLL_QB_R3_DESC_BASE<"shrav.qb", int_mips_shra_qb, + NoItinerary, DSPROpnd>; + +class SHRA_R_QB_DESC : SHLL_QB_R2_DESC_BASE<"shra_r.qb", int_mips_shra_r_qb, + immZExt3, NoItinerary, DSPROpnd, + uimm3>; + +class SHRAV_R_QB_DESC : SHLL_QB_R3_DESC_BASE<"shrav_r.qb", int_mips_shra_r_qb, + NoItinerary, DSPROpnd>; + +class SHRL_PH_DESC : SHLL_QB_R2_DESC_BASE<"shrl.ph", null_frag, immZExt4, + NoItinerary, DSPROpnd, uimm4>; + +class SHRLV_PH_DESC : SHLL_QB_R3_DESC_BASE<"shrlv.ph", int_mips_shrl_ph, + NoItinerary, DSPROpnd>; + +// Misc +class APPEND_DESC : APPEND_DESC_BASE<"append", int_mips_append, uimm5, immZExt5, + NoItinerary>; + +class BALIGN_DESC : APPEND_DESC_BASE<"balign", int_mips_balign, uimm2, immZExt2, + NoItinerary>; + +class PREPEND_DESC : APPEND_DESC_BASE<"prepend", int_mips_prepend, uimm5, + immZExt5, NoItinerary>; + +// Pseudos. +def BPOSGE32_PSEUDO : BPOSGE32_PSEUDO_DESC_BASE<int_mips_bposge32, + NoItinerary>, Uses<[DSPPos]>; + +// Instruction defs. +// MIPS DSP Rev 1 +def ADDU_QB : DspMMRel, ADDU_QB_ENC, ADDU_QB_DESC; +def ADDU_S_QB : DspMMRel, ADDU_S_QB_ENC, ADDU_S_QB_DESC; +def SUBU_QB : DspMMRel, SUBU_QB_ENC, SUBU_QB_DESC; +def SUBU_S_QB : DspMMRel, SUBU_S_QB_ENC, SUBU_S_QB_DESC; +def ADDQ_PH : DspMMRel, ADDQ_PH_ENC, ADDQ_PH_DESC; +def ADDQ_S_PH : DspMMRel, ADDQ_S_PH_ENC, ADDQ_S_PH_DESC; +def SUBQ_PH : DspMMRel, SUBQ_PH_ENC, SUBQ_PH_DESC; +def SUBQ_S_PH : DspMMRel, SUBQ_S_PH_ENC, SUBQ_S_PH_DESC; +def ADDQ_S_W : DspMMRel, ADDQ_S_W_ENC, ADDQ_S_W_DESC; +def SUBQ_S_W : DspMMRel, SUBQ_S_W_ENC, SUBQ_S_W_DESC; +def ADDSC : DspMMRel, ADDSC_ENC, ADDSC_DESC; +def ADDWC : DspMMRel, ADDWC_ENC, ADDWC_DESC; +def MODSUB : MODSUB_ENC, MODSUB_DESC; +def RADDU_W_QB : DspMMRel, RADDU_W_QB_ENC, RADDU_W_QB_DESC; +def ABSQ_S_PH : DspMMRel, ABSQ_S_PH_ENC, ABSQ_S_PH_DESC; +def ABSQ_S_W : DspMMRel, ABSQ_S_W_ENC, ABSQ_S_W_DESC; +def PRECRQ_QB_PH : DspMMRel, PRECRQ_QB_PH_ENC, PRECRQ_QB_PH_DESC; +def PRECRQ_PH_W : DspMMRel, PRECRQ_PH_W_ENC, PRECRQ_PH_W_DESC; +def PRECRQ_RS_PH_W : DspMMRel, PRECRQ_RS_PH_W_ENC, PRECRQ_RS_PH_W_DESC; +def PRECRQU_S_QB_PH : DspMMRel, PRECRQU_S_QB_PH_ENC, PRECRQU_S_QB_PH_DESC; +def PRECEQ_W_PHL : DspMMRel, PRECEQ_W_PHL_ENC, PRECEQ_W_PHL_DESC; +def PRECEQ_W_PHR : DspMMRel, PRECEQ_W_PHR_ENC, PRECEQ_W_PHR_DESC; +def PRECEQU_PH_QBL : DspMMRel, PRECEQU_PH_QBL_ENC, PRECEQU_PH_QBL_DESC; +def PRECEQU_PH_QBR : DspMMRel, PRECEQU_PH_QBR_ENC, PRECEQU_PH_QBR_DESC; +def PRECEQU_PH_QBLA : DspMMRel, PRECEQU_PH_QBLA_ENC, PRECEQU_PH_QBLA_DESC; +def PRECEQU_PH_QBRA : DspMMRel, PRECEQU_PH_QBRA_ENC, PRECEQU_PH_QBRA_DESC; +def PRECEU_PH_QBL : DspMMRel, PRECEU_PH_QBL_ENC, PRECEU_PH_QBL_DESC; +def PRECEU_PH_QBR : DspMMRel, PRECEU_PH_QBR_ENC, PRECEU_PH_QBR_DESC; +def PRECEU_PH_QBLA : DspMMRel, PRECEU_PH_QBLA_ENC, PRECEU_PH_QBLA_DESC; +def PRECEU_PH_QBRA : DspMMRel, PRECEU_PH_QBRA_ENC, PRECEU_PH_QBRA_DESC; +def SHLL_QB : DspMMRel, SHLL_QB_ENC, SHLL_QB_DESC; +def SHLLV_QB : DspMMRel, SHLLV_QB_ENC, SHLLV_QB_DESC; +def SHRL_QB : DspMMRel, SHRL_QB_ENC, SHRL_QB_DESC; +def SHRLV_QB : DspMMRel, SHRLV_QB_ENC, SHRLV_QB_DESC; +def SHLL_PH : DspMMRel, SHLL_PH_ENC, SHLL_PH_DESC; +def SHLLV_PH : DspMMRel, SHLLV_PH_ENC, SHLLV_PH_DESC; +def SHLL_S_PH : DspMMRel, SHLL_S_PH_ENC, SHLL_S_PH_DESC; +def SHLLV_S_PH : DspMMRel, SHLLV_S_PH_ENC, SHLLV_S_PH_DESC; +def SHRA_PH : DspMMRel, SHRA_PH_ENC, SHRA_PH_DESC; +def SHRAV_PH : DspMMRel, SHRAV_PH_ENC, SHRAV_PH_DESC; +def SHRA_R_PH : DspMMRel, SHRA_R_PH_ENC, SHRA_R_PH_DESC; +def SHRAV_R_PH : DspMMRel, SHRAV_R_PH_ENC, SHRAV_R_PH_DESC; +def SHLL_S_W : DspMMRel, SHLL_S_W_ENC, SHLL_S_W_DESC; +def SHLLV_S_W : DspMMRel, SHLLV_S_W_ENC, SHLLV_S_W_DESC; +def SHRA_R_W : DspMMRel, SHRA_R_W_ENC, SHRA_R_W_DESC; +def SHRAV_R_W : DspMMRel, SHRAV_R_W_ENC, SHRAV_R_W_DESC; +def MULEU_S_PH_QBL : DspMMRel, MULEU_S_PH_QBL_ENC, MULEU_S_PH_QBL_DESC; +def MULEU_S_PH_QBR : DspMMRel, MULEU_S_PH_QBR_ENC, MULEU_S_PH_QBR_DESC; +def MULEQ_S_W_PHL : DspMMRel, MULEQ_S_W_PHL_ENC, MULEQ_S_W_PHL_DESC; +def MULEQ_S_W_PHR : DspMMRel, MULEQ_S_W_PHR_ENC, MULEQ_S_W_PHR_DESC; +def MULQ_RS_PH : DspMMRel, MULQ_RS_PH_ENC, MULQ_RS_PH_DESC; +def MULSAQ_S_W_PH : MULSAQ_S_W_PH_ENC, MULSAQ_S_W_PH_DESC; +def MAQ_S_W_PHL : DspMMRel, MAQ_S_W_PHL_ENC, MAQ_S_W_PHL_DESC; +def MAQ_S_W_PHR : DspMMRel, MAQ_S_W_PHR_ENC, MAQ_S_W_PHR_DESC; +def MAQ_SA_W_PHL : DspMMRel, MAQ_SA_W_PHL_ENC, MAQ_SA_W_PHL_DESC; +def MAQ_SA_W_PHR : DspMMRel, MAQ_SA_W_PHR_ENC, MAQ_SA_W_PHR_DESC; +def MFHI_DSP : DspMMRel, MFHI_ENC, MFHI_DESC; +def MFLO_DSP : DspMMRel, MFLO_ENC, MFLO_DESC; +def MTHI_DSP : DspMMRel, MTHI_ENC, MTHI_DESC; +def MTLO_DSP : DspMMRel, MTLO_ENC, MTLO_DESC; +def DPAU_H_QBL : DspMMRel, DPAU_H_QBL_ENC, DPAU_H_QBL_DESC; +def DPAU_H_QBR : DspMMRel, DPAU_H_QBR_ENC, DPAU_H_QBR_DESC; +def DPSU_H_QBL : DspMMRel, DPSU_H_QBL_ENC, DPSU_H_QBL_DESC; +def DPSU_H_QBR : DspMMRel, DPSU_H_QBR_ENC, DPSU_H_QBR_DESC; +def DPAQ_S_W_PH : DspMMRel, DPAQ_S_W_PH_ENC, DPAQ_S_W_PH_DESC; +def DPSQ_S_W_PH : DspMMRel, DPSQ_S_W_PH_ENC, DPSQ_S_W_PH_DESC; +def DPAQ_SA_L_W : DspMMRel, DPAQ_SA_L_W_ENC, DPAQ_SA_L_W_DESC; +def DPSQ_SA_L_W : DspMMRel, DPSQ_SA_L_W_ENC, DPSQ_SA_L_W_DESC; +def MULT_DSP : DspMMRel, MULT_DSP_ENC, MULT_DSP_DESC; +def MULTU_DSP : DspMMRel, MULTU_DSP_ENC, MULTU_DSP_DESC; +def MADD_DSP : DspMMRel, MADD_DSP_ENC, MADD_DSP_DESC; +def MADDU_DSP : DspMMRel, MADDU_DSP_ENC, MADDU_DSP_DESC; +def MSUB_DSP : DspMMRel, MSUB_DSP_ENC, MSUB_DSP_DESC; +def MSUBU_DSP : DspMMRel, MSUBU_DSP_ENC, MSUBU_DSP_DESC; +def CMPU_EQ_QB : CMPU_EQ_QB_ENC, CMPU_EQ_QB_DESC; +def CMPU_LT_QB : CMPU_LT_QB_ENC, CMPU_LT_QB_DESC; +def CMPU_LE_QB : CMPU_LE_QB_ENC, CMPU_LE_QB_DESC; +def CMPGU_EQ_QB : CMPGU_EQ_QB_ENC, CMPGU_EQ_QB_DESC; +def CMPGU_LT_QB : CMPGU_LT_QB_ENC, CMPGU_LT_QB_DESC; +def CMPGU_LE_QB : CMPGU_LE_QB_ENC, CMPGU_LE_QB_DESC; +def CMP_EQ_PH : CMP_EQ_PH_ENC, CMP_EQ_PH_DESC; +def CMP_LT_PH : CMP_LT_PH_ENC, CMP_LT_PH_DESC; +def CMP_LE_PH : CMP_LE_PH_ENC, CMP_LE_PH_DESC; +def BITREV : BITREV_ENC, BITREV_DESC; +def PACKRL_PH : DspMMRel, PACKRL_PH_ENC, PACKRL_PH_DESC; +def REPL_QB : DspMMRel, REPL_QB_ENC, REPL_QB_DESC; +def REPL_PH : DspMMRel, REPL_PH_ENC, REPL_PH_DESC; +def REPLV_QB : DspMMRel, REPLV_QB_ENC, REPLV_QB_DESC; +def REPLV_PH : DspMMRel, REPLV_PH_ENC, REPLV_PH_DESC; +def PICK_QB : DspMMRel, PICK_QB_ENC, PICK_QB_DESC; +def PICK_PH : DspMMRel, PICK_PH_ENC, PICK_PH_DESC; +def LWX : DspMMRel, LWX_ENC, LWX_DESC; +def LHX : DspMMRel, LHX_ENC, LHX_DESC; +def LBUX : DspMMRel, LBUX_ENC, LBUX_DESC; +def BPOSGE32 : BPOSGE32_ENC, BPOSGE32_DESC; +def INSV : DspMMRel, INSV_ENC, INSV_DESC; +def EXTP : DspMMRel, EXTP_ENC, EXTP_DESC; +def EXTPV : DspMMRel, EXTPV_ENC, EXTPV_DESC; +def EXTPDP : DspMMRel, EXTPDP_ENC, EXTPDP_DESC; +def EXTPDPV : DspMMRel, EXTPDPV_ENC, EXTPDPV_DESC; +def EXTR_W : DspMMRel, EXTR_W_ENC, EXTR_W_DESC; +def EXTRV_W : DspMMRel, EXTRV_W_ENC, EXTRV_W_DESC; +def EXTR_R_W : DspMMRel, EXTR_R_W_ENC, EXTR_R_W_DESC; +def EXTRV_R_W : DspMMRel, EXTRV_R_W_ENC, EXTRV_R_W_DESC; +def EXTR_RS_W : DspMMRel, EXTR_RS_W_ENC, EXTR_RS_W_DESC; +def EXTRV_RS_W : DspMMRel, EXTRV_RS_W_ENC, EXTRV_RS_W_DESC; +def EXTR_S_H : DspMMRel, EXTR_S_H_ENC, EXTR_S_H_DESC; +def EXTRV_S_H : DspMMRel, EXTRV_S_H_ENC, EXTRV_S_H_DESC; +def SHILO : DspMMRel, SHILO_ENC, SHILO_DESC; +def SHILOV : DspMMRel, SHILOV_ENC, SHILOV_DESC; +def MTHLIP : DspMMRel, MTHLIP_ENC, MTHLIP_DESC; +def RDDSP : DspMMRel, RDDSP_ENC, RDDSP_DESC; +let AdditionalPredicates = [NotInMicroMips] in { + def WRDSP : WRDSP_ENC, WRDSP_DESC; +} + +// MIPS DSP Rev 2 +def ADDU_PH : DspMMRel, ADDU_PH_ENC, ADDU_PH_DESC, ISA_DSPR2; +def ADDU_S_PH : DspMMRel, ADDU_S_PH_ENC, ADDU_S_PH_DESC, ISA_DSPR2; +def SUBU_PH : DspMMRel, SUBU_PH_ENC, SUBU_PH_DESC, ISA_DSPR2; +def SUBU_S_PH : DspMMRel, SUBU_S_PH_ENC, SUBU_S_PH_DESC, ISA_DSPR2; +def CMPGDU_EQ_QB : CMPGDU_EQ_QB_ENC, CMPGDU_EQ_QB_DESC, ISA_DSPR2; +def CMPGDU_LT_QB : CMPGDU_LT_QB_ENC, CMPGDU_LT_QB_DESC, ISA_DSPR2; +def CMPGDU_LE_QB : CMPGDU_LE_QB_ENC, CMPGDU_LE_QB_DESC, ISA_DSPR2; +def ABSQ_S_QB : DspMMRel, ABSQ_S_QB_ENC, ABSQ_S_QB_DESC, ISA_DSPR2; +def ADDUH_QB : DspMMRel, ADDUH_QB_ENC, ADDUH_QB_DESC, ISA_DSPR2; +def ADDUH_R_QB : DspMMRel, ADDUH_R_QB_ENC, ADDUH_R_QB_DESC, ISA_DSPR2; +def SUBUH_QB : DspMMRel, SUBUH_QB_ENC, SUBUH_QB_DESC, ISA_DSPR2; +def SUBUH_R_QB : DspMMRel, SUBUH_R_QB_ENC, SUBUH_R_QB_DESC, ISA_DSPR2; +def ADDQH_PH : DspMMRel, ADDQH_PH_ENC, ADDQH_PH_DESC, ISA_DSPR2; +def ADDQH_R_PH : DspMMRel, ADDQH_R_PH_ENC, ADDQH_R_PH_DESC, ISA_DSPR2; +def SUBQH_PH : DspMMRel, SUBQH_PH_ENC, SUBQH_PH_DESC, ISA_DSPR2; +def SUBQH_R_PH : DspMMRel, SUBQH_R_PH_ENC, SUBQH_R_PH_DESC, ISA_DSPR2; +def ADDQH_W : DspMMRel, ADDQH_W_ENC, ADDQH_W_DESC, ISA_DSPR2; +def ADDQH_R_W : DspMMRel, ADDQH_R_W_ENC, ADDQH_R_W_DESC, ISA_DSPR2; +def SUBQH_W : DspMMRel, SUBQH_W_ENC, SUBQH_W_DESC, ISA_DSPR2; +def SUBQH_R_W : DspMMRel, SUBQH_R_W_ENC, SUBQH_R_W_DESC, ISA_DSPR2; +def MUL_PH : DspMMRel, MUL_PH_ENC, MUL_PH_DESC, ISA_DSPR2; +def MUL_S_PH : DspMMRel, MUL_S_PH_ENC, MUL_S_PH_DESC, ISA_DSPR2; +def MULQ_S_W : DspMMRel, MULQ_S_W_ENC, MULQ_S_W_DESC, ISA_DSPR2; +def MULQ_RS_W : DspMMRel, MULQ_RS_W_ENC, MULQ_RS_W_DESC, ISA_DSPR2; +def MULQ_S_PH : DspMMRel, MULQ_S_PH_ENC, MULQ_S_PH_DESC, ISA_DSPR2; +def DPA_W_PH : DspMMRel, DPA_W_PH_ENC, DPA_W_PH_DESC, ISA_DSPR2; +def DPS_W_PH : DspMMRel, DPS_W_PH_ENC, DPS_W_PH_DESC, ISA_DSPR2; +def DPAQX_S_W_PH : DspMMRel, DPAQX_S_W_PH_ENC, DPAQX_S_W_PH_DESC, ISA_DSPR2; +def DPAQX_SA_W_PH : DspMMRel, DPAQX_SA_W_PH_ENC, DPAQX_SA_W_PH_DESC, ISA_DSPR2; +def DPAX_W_PH : DspMMRel, DPAX_W_PH_ENC, DPAX_W_PH_DESC, ISA_DSPR2; +def DPSX_W_PH : DspMMRel, DPSX_W_PH_ENC, DPSX_W_PH_DESC, ISA_DSPR2; +def DPSQX_S_W_PH : DspMMRel, DPSQX_S_W_PH_ENC, DPSQX_S_W_PH_DESC, ISA_DSPR2; +def DPSQX_SA_W_PH : DspMMRel, DPSQX_SA_W_PH_ENC, DPSQX_SA_W_PH_DESC, ISA_DSPR2; +def MULSA_W_PH : MULSA_W_PH_ENC, MULSA_W_PH_DESC, ISA_DSPR2; +def PRECR_QB_PH : DspMMRel, PRECR_QB_PH_ENC, PRECR_QB_PH_DESC, ISA_DSPR2; +def PRECR_SRA_PH_W : DspMMRel, PRECR_SRA_PH_W_ENC, PRECR_SRA_PH_W_DESC, ISA_DSPR2; +def PRECR_SRA_R_PH_W : DspMMRel, PRECR_SRA_R_PH_W_ENC, PRECR_SRA_R_PH_W_DESC, ISA_DSPR2; +def SHRA_QB : DspMMRel, SHRA_QB_ENC, SHRA_QB_DESC, ISA_DSPR2; +def SHRAV_QB : DspMMRel, SHRAV_QB_ENC, SHRAV_QB_DESC, ISA_DSPR2; +def SHRA_R_QB : DspMMRel, SHRA_R_QB_ENC, SHRA_R_QB_DESC, ISA_DSPR2; +def SHRAV_R_QB : DspMMRel, SHRAV_R_QB_ENC, SHRAV_R_QB_DESC, ISA_DSPR2; +def SHRL_PH : DspMMRel, SHRL_PH_ENC, SHRL_PH_DESC, ISA_DSPR2; +def SHRLV_PH : DspMMRel, SHRLV_PH_ENC, SHRLV_PH_DESC, ISA_DSPR2; +def APPEND : APPEND_ENC, APPEND_DESC, ISA_DSPR2; +def BALIGN : BALIGN_ENC, BALIGN_DESC, ISA_DSPR2; +def PREPEND : DspMMRel, PREPEND_ENC, PREPEND_DESC, ISA_DSPR2; + +// Pseudos. +let isPseudo = 1, isCodeGenOnly = 1 in { + // Pseudo instructions for loading and storing accumulator registers. + def LOAD_ACC64DSP : Load<"", ACC64DSPOpnd>; + def STORE_ACC64DSP : Store<"", ACC64DSPOpnd>; + + // Pseudos for loading and storing ccond field of DSP control register. + def LOAD_CCOND_DSP : Load<"load_ccond_dsp", DSPCC>; + def STORE_CCOND_DSP : Store<"store_ccond_dsp", DSPCC>; +} + +// Pseudo CMP and PICK instructions. +class PseudoCMP<Instruction RealInst> : + PseudoDSP<(outs DSPCC:$cmp), (ins DSPROpnd:$rs, DSPROpnd:$rt), []>, + PseudoInstExpansion<(RealInst DSPROpnd:$rs, DSPROpnd:$rt)>, NeverHasSideEffects; + +class PseudoPICK<Instruction RealInst> : + PseudoDSP<(outs DSPROpnd:$rd), (ins DSPCC:$cmp, DSPROpnd:$rs, DSPROpnd:$rt), []>, + PseudoInstExpansion<(RealInst DSPROpnd:$rd, DSPROpnd:$rs, DSPROpnd:$rt)>, + NeverHasSideEffects; + +def PseudoCMP_EQ_PH : PseudoCMP<CMP_EQ_PH>; +def PseudoCMP_LT_PH : PseudoCMP<CMP_LT_PH>; +def PseudoCMP_LE_PH : PseudoCMP<CMP_LE_PH>; +def PseudoCMPU_EQ_QB : PseudoCMP<CMPU_EQ_QB>; +def PseudoCMPU_LT_QB : PseudoCMP<CMPU_LT_QB>; +def PseudoCMPU_LE_QB : PseudoCMP<CMPU_LE_QB>; + +def PseudoPICK_PH : PseudoPICK<PICK_PH>; +def PseudoPICK_QB : PseudoPICK<PICK_QB>; + +def PseudoMTLOHI_DSP : PseudoMTLOHI<ACC64DSP, GPR32>; + +// Patterns. +class DSPPat<dag pattern, dag result, Predicate pred = HasDSP> : + Pat<pattern, result>, Requires<[pred]>; + +class BitconvertPat<ValueType DstVT, ValueType SrcVT, RegisterClass DstRC, + RegisterClass SrcRC> : + DSPPat<(DstVT (bitconvert (SrcVT SrcRC:$src))), + (COPY_TO_REGCLASS SrcRC:$src, DstRC)>; + +def : BitconvertPat<i32, v2i16, GPR32, DSPR>; +def : BitconvertPat<i32, v4i8, GPR32, DSPR>; +def : BitconvertPat<v2i16, i32, DSPR, GPR32>; +def : BitconvertPat<v4i8, i32, DSPR, GPR32>; + +def : DSPPat<(v2i16 (load addr:$a)), + (v2i16 (COPY_TO_REGCLASS (LW addr:$a), DSPR))>; +def : DSPPat<(v4i8 (load addr:$a)), + (v4i8 (COPY_TO_REGCLASS (LW addr:$a), DSPR))>; +def : DSPPat<(store (v2i16 DSPR:$val), addr:$a), + (SW (COPY_TO_REGCLASS DSPR:$val, GPR32), addr:$a)>; +def : DSPPat<(store (v4i8 DSPR:$val), addr:$a), + (SW (COPY_TO_REGCLASS DSPR:$val, GPR32), addr:$a)>; + +// Binary operations. +class DSPBinPat<Instruction Inst, ValueType ValTy, SDPatternOperator Node, + Predicate Pred = HasDSP> : + DSPPat<(Node ValTy:$a, ValTy:$b), (Inst ValTy:$a, ValTy:$b), Pred>; + +def : DSPBinPat<ADDQ_PH, v2i16, int_mips_addq_ph>; +def : DSPBinPat<ADDQ_PH, v2i16, add>; +def : DSPBinPat<SUBQ_PH, v2i16, int_mips_subq_ph>; +def : DSPBinPat<SUBQ_PH, v2i16, sub>; +def : DSPBinPat<MUL_PH, v2i16, int_mips_mul_ph, HasDSPR2>; +def : DSPBinPat<MUL_PH, v2i16, mul, HasDSPR2>; +def : DSPBinPat<ADDU_QB, v4i8, int_mips_addu_qb>; +def : DSPBinPat<ADDU_QB, v4i8, add>; +def : DSPBinPat<SUBU_QB, v4i8, int_mips_subu_qb>; +def : DSPBinPat<SUBU_QB, v4i8, sub>; +def : DSPBinPat<ADDSC, i32, int_mips_addsc>; +def : DSPBinPat<ADDSC, i32, addc>; +def : DSPBinPat<ADDWC, i32, int_mips_addwc>; +def : DSPBinPat<ADDWC, i32, adde>; + +// Shift immediate patterns. +class DSPShiftPat<Instruction Inst, ValueType ValTy, SDPatternOperator Node, + SDPatternOperator Imm, Predicate Pred = HasDSP> : + DSPPat<(Node ValTy:$a, Imm:$shamt), (Inst ValTy:$a, Imm:$shamt), Pred>; + +def : DSPShiftPat<SHLL_PH, v2i16, MipsSHLL_DSP, imm>; +def : DSPShiftPat<SHRA_PH, v2i16, MipsSHRA_DSP, imm>; +def : DSPShiftPat<SHRL_PH, v2i16, MipsSHRL_DSP, imm, HasDSPR2>; +def : DSPShiftPat<SHLL_PH, v2i16, int_mips_shll_ph, immZExt4>; +def : DSPShiftPat<SHRA_PH, v2i16, int_mips_shra_ph, immZExt4>; +def : DSPShiftPat<SHRL_PH, v2i16, int_mips_shrl_ph, immZExt4, HasDSPR2>; +def : DSPShiftPat<SHLL_QB, v4i8, MipsSHLL_DSP, imm>; +def : DSPShiftPat<SHRA_QB, v4i8, MipsSHRA_DSP, imm, HasDSPR2>; +def : DSPShiftPat<SHRL_QB, v4i8, MipsSHRL_DSP, imm>; +def : DSPShiftPat<SHLL_QB, v4i8, int_mips_shll_qb, immZExt3>; +def : DSPShiftPat<SHRA_QB, v4i8, int_mips_shra_qb, immZExt3, HasDSPR2>; +def : DSPShiftPat<SHRL_QB, v4i8, int_mips_shrl_qb, immZExt3>; + +// SETCC/SELECT_CC patterns. +class DSPSetCCPat<Instruction Cmp, Instruction Pick, ValueType ValTy, + CondCode CC> : + DSPPat<(ValTy (MipsSETCC_DSP ValTy:$a, ValTy:$b, CC)), + (ValTy (Pick (ValTy (Cmp ValTy:$a, ValTy:$b)), + (ValTy (COPY_TO_REGCLASS (ADDiu ZERO, -1), DSPR)), + (ValTy ZERO)))>; + +class DSPSetCCPatInv<Instruction Cmp, Instruction Pick, ValueType ValTy, + CondCode CC> : + DSPPat<(ValTy (MipsSETCC_DSP ValTy:$a, ValTy:$b, CC)), + (ValTy (Pick (ValTy (Cmp ValTy:$a, ValTy:$b)), + (ValTy ZERO), + (ValTy (COPY_TO_REGCLASS (ADDiu ZERO, -1), DSPR))))>; + +class DSPSelectCCPat<Instruction Cmp, Instruction Pick, ValueType ValTy, + CondCode CC> : + DSPPat<(ValTy (MipsSELECT_CC_DSP ValTy:$a, ValTy:$b, ValTy:$c, ValTy:$d, CC)), + (ValTy (Pick (ValTy (Cmp ValTy:$a, ValTy:$b)), $c, $d))>; + +class DSPSelectCCPatInv<Instruction Cmp, Instruction Pick, ValueType ValTy, + CondCode CC> : + DSPPat<(ValTy (MipsSELECT_CC_DSP ValTy:$a, ValTy:$b, ValTy:$c, ValTy:$d, CC)), + (ValTy (Pick (ValTy (Cmp ValTy:$a, ValTy:$b)), $d, $c))>; + +def : DSPSetCCPat<PseudoCMP_EQ_PH, PseudoPICK_PH, v2i16, SETEQ>; +def : DSPSetCCPat<PseudoCMP_LT_PH, PseudoPICK_PH, v2i16, SETLT>; +def : DSPSetCCPat<PseudoCMP_LE_PH, PseudoPICK_PH, v2i16, SETLE>; +def : DSPSetCCPatInv<PseudoCMP_EQ_PH, PseudoPICK_PH, v2i16, SETNE>; +def : DSPSetCCPatInv<PseudoCMP_LT_PH, PseudoPICK_PH, v2i16, SETGE>; +def : DSPSetCCPatInv<PseudoCMP_LE_PH, PseudoPICK_PH, v2i16, SETGT>; +def : DSPSetCCPat<PseudoCMPU_EQ_QB, PseudoPICK_QB, v4i8, SETEQ>; +def : DSPSetCCPat<PseudoCMPU_LT_QB, PseudoPICK_QB, v4i8, SETULT>; +def : DSPSetCCPat<PseudoCMPU_LE_QB, PseudoPICK_QB, v4i8, SETULE>; +def : DSPSetCCPatInv<PseudoCMPU_EQ_QB, PseudoPICK_QB, v4i8, SETNE>; +def : DSPSetCCPatInv<PseudoCMPU_LT_QB, PseudoPICK_QB, v4i8, SETUGE>; +def : DSPSetCCPatInv<PseudoCMPU_LE_QB, PseudoPICK_QB, v4i8, SETUGT>; + +def : DSPSelectCCPat<PseudoCMP_EQ_PH, PseudoPICK_PH, v2i16, SETEQ>; +def : DSPSelectCCPat<PseudoCMP_LT_PH, PseudoPICK_PH, v2i16, SETLT>; +def : DSPSelectCCPat<PseudoCMP_LE_PH, PseudoPICK_PH, v2i16, SETLE>; +def : DSPSelectCCPatInv<PseudoCMP_EQ_PH, PseudoPICK_PH, v2i16, SETNE>; +def : DSPSelectCCPatInv<PseudoCMP_LT_PH, PseudoPICK_PH, v2i16, SETGE>; +def : DSPSelectCCPatInv<PseudoCMP_LE_PH, PseudoPICK_PH, v2i16, SETGT>; +def : DSPSelectCCPat<PseudoCMPU_EQ_QB, PseudoPICK_QB, v4i8, SETEQ>; +def : DSPSelectCCPat<PseudoCMPU_LT_QB, PseudoPICK_QB, v4i8, SETULT>; +def : DSPSelectCCPat<PseudoCMPU_LE_QB, PseudoPICK_QB, v4i8, SETULE>; +def : DSPSelectCCPatInv<PseudoCMPU_EQ_QB, PseudoPICK_QB, v4i8, SETNE>; +def : DSPSelectCCPatInv<PseudoCMPU_LT_QB, PseudoPICK_QB, v4i8, SETUGE>; +def : DSPSelectCCPatInv<PseudoCMPU_LE_QB, PseudoPICK_QB, v4i8, SETUGT>; + +// Extr patterns. +class EXTR_W_TY1_R2_Pat<SDPatternOperator OpNode, Instruction Instr> : + DSPPat<(i32 (OpNode GPR32:$rs, ACC64DSP:$ac)), + (Instr ACC64DSP:$ac, GPR32:$rs)>; + +class EXTR_W_TY1_R1_Pat<SDPatternOperator OpNode, Instruction Instr> : + DSPPat<(i32 (OpNode immZExt5:$shift, ACC64DSP:$ac)), + (Instr ACC64DSP:$ac, immZExt5:$shift)>; + +def : EXTR_W_TY1_R1_Pat<MipsEXTP, EXTP>; +def : EXTR_W_TY1_R2_Pat<MipsEXTP, EXTPV>; +def : EXTR_W_TY1_R1_Pat<MipsEXTPDP, EXTPDP>; +def : EXTR_W_TY1_R2_Pat<MipsEXTPDP, EXTPDPV>; +def : EXTR_W_TY1_R1_Pat<MipsEXTR_W, EXTR_W>; +def : EXTR_W_TY1_R2_Pat<MipsEXTR_W, EXTRV_W>; +def : EXTR_W_TY1_R1_Pat<MipsEXTR_R_W, EXTR_R_W>; +def : EXTR_W_TY1_R2_Pat<MipsEXTR_R_W, EXTRV_R_W>; +def : EXTR_W_TY1_R1_Pat<MipsEXTR_RS_W, EXTR_RS_W>; +def : EXTR_W_TY1_R2_Pat<MipsEXTR_RS_W, EXTRV_RS_W>; +def : EXTR_W_TY1_R1_Pat<MipsEXTR_S_H, EXTR_S_H>; +def : EXTR_W_TY1_R2_Pat<MipsEXTR_S_H, EXTRV_S_H>; + +// Indexed load patterns. +class IndexedLoadPat<SDPatternOperator LoadNode, Instruction Instr> : + DSPPat<(i32 (LoadNode (add i32:$base, i32:$index))), + (Instr i32:$base, i32:$index)>; + +let AddedComplexity = 20 in { + def : IndexedLoadPat<zextloadi8, LBUX>; + def : IndexedLoadPat<sextloadi16, LHX>; + def : IndexedLoadPat<load, LWX>; +} + +// Instruction alias. +let AdditionalPredicates = [NotInMicroMips] in { + def : DSPInstAlias<"wrdsp $rt", (WRDSP GPR32Opnd:$rt, 0x1F), 1>; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp b/contrib/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp new file mode 100644 index 0000000..8313d90 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp @@ -0,0 +1,887 @@ +//===-- MipsDelaySlotFiller.cpp - Mips Delay Slot Filler ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Simple pass to fill delay slots with useful instructions. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/MipsMCNaCl.h" +#include "Mips.h" +#include "MipsInstrInfo.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/CodeGen/MachineBranchProbabilityInfo.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/PseudoSourceValue.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegisterInfo.h" + +using namespace llvm; + +#define DEBUG_TYPE "delay-slot-filler" + +STATISTIC(FilledSlots, "Number of delay slots filled"); +STATISTIC(UsefulSlots, "Number of delay slots filled with instructions that" + " are not NOP."); + +static cl::opt<bool> DisableDelaySlotFiller( + "disable-mips-delay-filler", + cl::init(false), + cl::desc("Fill all delay slots with NOPs."), + cl::Hidden); + +static cl::opt<bool> DisableForwardSearch( + "disable-mips-df-forward-search", + cl::init(true), + cl::desc("Disallow MIPS delay filler to search forward."), + cl::Hidden); + +static cl::opt<bool> DisableSuccBBSearch( + "disable-mips-df-succbb-search", + cl::init(true), + cl::desc("Disallow MIPS delay filler to search successor basic blocks."), + cl::Hidden); + +static cl::opt<bool> DisableBackwardSearch( + "disable-mips-df-backward-search", + cl::init(false), + cl::desc("Disallow MIPS delay filler to search backward."), + cl::Hidden); + +namespace { + typedef MachineBasicBlock::iterator Iter; + typedef MachineBasicBlock::reverse_iterator ReverseIter; + typedef SmallDenseMap<MachineBasicBlock*, MachineInstr*, 2> BB2BrMap; + + class RegDefsUses { + public: + RegDefsUses(const TargetRegisterInfo &TRI); + void init(const MachineInstr &MI); + + /// This function sets all caller-saved registers in Defs. + void setCallerSaved(const MachineInstr &MI); + + /// This function sets all unallocatable registers in Defs. + void setUnallocatableRegs(const MachineFunction &MF); + + /// Set bits in Uses corresponding to MBB's live-out registers except for + /// the registers that are live-in to SuccBB. + void addLiveOut(const MachineBasicBlock &MBB, + const MachineBasicBlock &SuccBB); + + bool update(const MachineInstr &MI, unsigned Begin, unsigned End); + + private: + bool checkRegDefsUses(BitVector &NewDefs, BitVector &NewUses, unsigned Reg, + bool IsDef) const; + + /// Returns true if Reg or its alias is in RegSet. + bool isRegInSet(const BitVector &RegSet, unsigned Reg) const; + + const TargetRegisterInfo &TRI; + BitVector Defs, Uses; + }; + + /// Base class for inspecting loads and stores. + class InspectMemInstr { + public: + InspectMemInstr(bool ForbidMemInstr_) + : OrigSeenLoad(false), OrigSeenStore(false), SeenLoad(false), + SeenStore(false), ForbidMemInstr(ForbidMemInstr_) {} + + /// Return true if MI cannot be moved to delay slot. + bool hasHazard(const MachineInstr &MI); + + virtual ~InspectMemInstr() {} + + protected: + /// Flags indicating whether loads or stores have been seen. + bool OrigSeenLoad, OrigSeenStore, SeenLoad, SeenStore; + + /// Memory instructions are not allowed to move to delay slot if this flag + /// is true. + bool ForbidMemInstr; + + private: + virtual bool hasHazard_(const MachineInstr &MI) = 0; + }; + + /// This subclass rejects any memory instructions. + class NoMemInstr : public InspectMemInstr { + public: + NoMemInstr() : InspectMemInstr(true) {} + private: + bool hasHazard_(const MachineInstr &MI) override { return true; } + }; + + /// This subclass accepts loads from stacks and constant loads. + class LoadFromStackOrConst : public InspectMemInstr { + public: + LoadFromStackOrConst() : InspectMemInstr(false) {} + private: + bool hasHazard_(const MachineInstr &MI) override; + }; + + /// This subclass uses memory dependence information to determine whether a + /// memory instruction can be moved to a delay slot. + class MemDefsUses : public InspectMemInstr { + public: + MemDefsUses(const DataLayout &DL, const MachineFrameInfo *MFI); + + private: + typedef PointerUnion<const Value *, const PseudoSourceValue *> ValueType; + + bool hasHazard_(const MachineInstr &MI) override; + + /// Update Defs and Uses. Return true if there exist dependences that + /// disqualify the delay slot candidate between V and values in Uses and + /// Defs. + bool updateDefsUses(ValueType V, bool MayStore); + + /// Get the list of underlying objects of MI's memory operand. + bool getUnderlyingObjects(const MachineInstr &MI, + SmallVectorImpl<ValueType> &Objects) const; + + const MachineFrameInfo *MFI; + SmallPtrSet<ValueType, 4> Uses, Defs; + const DataLayout &DL; + + /// Flags indicating whether loads or stores with no underlying objects have + /// been seen. + bool SeenNoObjLoad, SeenNoObjStore; + }; + + class Filler : public MachineFunctionPass { + public: + Filler(TargetMachine &tm) + : MachineFunctionPass(ID), TM(tm) { } + + const char *getPassName() const override { + return "Mips Delay Slot Filler"; + } + + bool runOnMachineFunction(MachineFunction &F) override { + bool Changed = false; + for (MachineFunction::iterator FI = F.begin(), FE = F.end(); + FI != FE; ++FI) + Changed |= runOnMachineBasicBlock(*FI); + + // This pass invalidates liveness information when it reorders + // instructions to fill delay slot. Without this, -verify-machineinstrs + // will fail. + if (Changed) + F.getRegInfo().invalidateLiveness(); + + return Changed; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired<MachineBranchProbabilityInfo>(); + MachineFunctionPass::getAnalysisUsage(AU); + } + + private: + bool runOnMachineBasicBlock(MachineBasicBlock &MBB); + + Iter replaceWithCompactBranch(MachineBasicBlock &MBB, + Iter Branch, DebugLoc DL); + + Iter replaceWithCompactJump(MachineBasicBlock &MBB, + Iter Jump, DebugLoc DL); + + /// This function checks if it is valid to move Candidate to the delay slot + /// and returns true if it isn't. It also updates memory and register + /// dependence information. + bool delayHasHazard(const MachineInstr &Candidate, RegDefsUses &RegDU, + InspectMemInstr &IM) const; + + /// This function searches range [Begin, End) for an instruction that can be + /// moved to the delay slot. Returns true on success. + template<typename IterTy> + bool searchRange(MachineBasicBlock &MBB, IterTy Begin, IterTy End, + RegDefsUses &RegDU, InspectMemInstr &IM, Iter Slot, + IterTy &Filler) const; + + /// This function searches in the backward direction for an instruction that + /// can be moved to the delay slot. Returns true on success. + bool searchBackward(MachineBasicBlock &MBB, Iter Slot) const; + + /// This function searches MBB in the forward direction for an instruction + /// that can be moved to the delay slot. Returns true on success. + bool searchForward(MachineBasicBlock &MBB, Iter Slot) const; + + /// This function searches one of MBB's successor blocks for an instruction + /// that can be moved to the delay slot and inserts clones of the + /// instruction into the successor's predecessor blocks. + bool searchSuccBBs(MachineBasicBlock &MBB, Iter Slot) const; + + /// Pick a successor block of MBB. Return NULL if MBB doesn't have a + /// successor block that is not a landing pad. + MachineBasicBlock *selectSuccBB(MachineBasicBlock &B) const; + + /// This function analyzes MBB and returns an instruction with an unoccupied + /// slot that branches to Dst. + std::pair<MipsInstrInfo::BranchType, MachineInstr *> + getBranch(MachineBasicBlock &MBB, const MachineBasicBlock &Dst) const; + + /// Examine Pred and see if it is possible to insert an instruction into + /// one of its branches delay slot or its end. + bool examinePred(MachineBasicBlock &Pred, const MachineBasicBlock &Succ, + RegDefsUses &RegDU, bool &HasMultipleSuccs, + BB2BrMap &BrMap) const; + + bool terminateSearch(const MachineInstr &Candidate) const; + + TargetMachine &TM; + + static char ID; + }; + char Filler::ID = 0; +} // end of anonymous namespace + +static bool hasUnoccupiedSlot(const MachineInstr *MI) { + return MI->hasDelaySlot() && !MI->isBundledWithSucc(); +} + +/// This function inserts clones of Filler into predecessor blocks. +static void insertDelayFiller(Iter Filler, const BB2BrMap &BrMap) { + MachineFunction *MF = Filler->getParent()->getParent(); + + for (BB2BrMap::const_iterator I = BrMap.begin(); I != BrMap.end(); ++I) { + if (I->second) { + MIBundleBuilder(I->second).append(MF->CloneMachineInstr(&*Filler)); + ++UsefulSlots; + } else { + I->first->insert(I->first->end(), MF->CloneMachineInstr(&*Filler)); + } + } +} + +/// This function adds registers Filler defines to MBB's live-in register list. +static void addLiveInRegs(Iter Filler, MachineBasicBlock &MBB) { + for (unsigned I = 0, E = Filler->getNumOperands(); I != E; ++I) { + const MachineOperand &MO = Filler->getOperand(I); + unsigned R; + + if (!MO.isReg() || !MO.isDef() || !(R = MO.getReg())) + continue; + +#ifndef NDEBUG + const MachineFunction &MF = *MBB.getParent(); + assert(MF.getSubtarget().getRegisterInfo()->getAllocatableSet(MF).test(R) && + "Shouldn't move an instruction with unallocatable registers across " + "basic block boundaries."); +#endif + + if (!MBB.isLiveIn(R)) + MBB.addLiveIn(R); + } +} + +RegDefsUses::RegDefsUses(const TargetRegisterInfo &TRI) + : TRI(TRI), Defs(TRI.getNumRegs(), false), Uses(TRI.getNumRegs(), false) {} + +void RegDefsUses::init(const MachineInstr &MI) { + // Add all register operands which are explicit and non-variadic. + update(MI, 0, MI.getDesc().getNumOperands()); + + // If MI is a call, add RA to Defs to prevent users of RA from going into + // delay slot. + if (MI.isCall()) + Defs.set(Mips::RA); + + // Add all implicit register operands of branch instructions except + // register AT. + if (MI.isBranch()) { + update(MI, MI.getDesc().getNumOperands(), MI.getNumOperands()); + Defs.reset(Mips::AT); + } +} + +void RegDefsUses::setCallerSaved(const MachineInstr &MI) { + assert(MI.isCall()); + + // Add RA/RA_64 to Defs to prevent users of RA/RA_64 from going into + // the delay slot. The reason is that RA/RA_64 must not be changed + // in the delay slot so that the callee can return to the caller. + if (MI.definesRegister(Mips::RA) || MI.definesRegister(Mips::RA_64)) { + Defs.set(Mips::RA); + Defs.set(Mips::RA_64); + } + + // If MI is a call, add all caller-saved registers to Defs. + BitVector CallerSavedRegs(TRI.getNumRegs(), true); + + CallerSavedRegs.reset(Mips::ZERO); + CallerSavedRegs.reset(Mips::ZERO_64); + + for (const MCPhysReg *R = TRI.getCalleeSavedRegs(MI.getParent()->getParent()); + *R; ++R) + for (MCRegAliasIterator AI(*R, &TRI, true); AI.isValid(); ++AI) + CallerSavedRegs.reset(*AI); + + Defs |= CallerSavedRegs; +} + +void RegDefsUses::setUnallocatableRegs(const MachineFunction &MF) { + BitVector AllocSet = TRI.getAllocatableSet(MF); + + for (int R = AllocSet.find_first(); R != -1; R = AllocSet.find_next(R)) + for (MCRegAliasIterator AI(R, &TRI, false); AI.isValid(); ++AI) + AllocSet.set(*AI); + + AllocSet.set(Mips::ZERO); + AllocSet.set(Mips::ZERO_64); + + Defs |= AllocSet.flip(); +} + +void RegDefsUses::addLiveOut(const MachineBasicBlock &MBB, + const MachineBasicBlock &SuccBB) { + for (MachineBasicBlock::const_succ_iterator SI = MBB.succ_begin(), + SE = MBB.succ_end(); SI != SE; ++SI) + if (*SI != &SuccBB) + for (const auto &LI : (*SI)->liveins()) + Uses.set(LI.PhysReg); +} + +bool RegDefsUses::update(const MachineInstr &MI, unsigned Begin, unsigned End) { + BitVector NewDefs(TRI.getNumRegs()), NewUses(TRI.getNumRegs()); + bool HasHazard = false; + + for (unsigned I = Begin; I != End; ++I) { + const MachineOperand &MO = MI.getOperand(I); + + if (MO.isReg() && MO.getReg()) + HasHazard |= checkRegDefsUses(NewDefs, NewUses, MO.getReg(), MO.isDef()); + } + + Defs |= NewDefs; + Uses |= NewUses; + + return HasHazard; +} + +bool RegDefsUses::checkRegDefsUses(BitVector &NewDefs, BitVector &NewUses, + unsigned Reg, bool IsDef) const { + if (IsDef) { + NewDefs.set(Reg); + // check whether Reg has already been defined or used. + return (isRegInSet(Defs, Reg) || isRegInSet(Uses, Reg)); + } + + NewUses.set(Reg); + // check whether Reg has already been defined. + return isRegInSet(Defs, Reg); +} + +bool RegDefsUses::isRegInSet(const BitVector &RegSet, unsigned Reg) const { + // Check Reg and all aliased Registers. + for (MCRegAliasIterator AI(Reg, &TRI, true); AI.isValid(); ++AI) + if (RegSet.test(*AI)) + return true; + return false; +} + +bool InspectMemInstr::hasHazard(const MachineInstr &MI) { + if (!MI.mayStore() && !MI.mayLoad()) + return false; + + if (ForbidMemInstr) + return true; + + OrigSeenLoad = SeenLoad; + OrigSeenStore = SeenStore; + SeenLoad |= MI.mayLoad(); + SeenStore |= MI.mayStore(); + + // If MI is an ordered or volatile memory reference, disallow moving + // subsequent loads and stores to delay slot. + if (MI.hasOrderedMemoryRef() && (OrigSeenLoad || OrigSeenStore)) { + ForbidMemInstr = true; + return true; + } + + return hasHazard_(MI); +} + +bool LoadFromStackOrConst::hasHazard_(const MachineInstr &MI) { + if (MI.mayStore()) + return true; + + if (!MI.hasOneMemOperand() || !(*MI.memoperands_begin())->getPseudoValue()) + return true; + + if (const PseudoSourceValue *PSV = + (*MI.memoperands_begin())->getPseudoValue()) { + if (isa<FixedStackPseudoSourceValue>(PSV)) + return false; + return !PSV->isConstant(nullptr) && !PSV->isStack(); + } + + return true; +} + +MemDefsUses::MemDefsUses(const DataLayout &DL, const MachineFrameInfo *MFI_) + : InspectMemInstr(false), MFI(MFI_), DL(DL), SeenNoObjLoad(false), + SeenNoObjStore(false) {} + +bool MemDefsUses::hasHazard_(const MachineInstr &MI) { + bool HasHazard = false; + SmallVector<ValueType, 4> Objs; + + // Check underlying object list. + if (getUnderlyingObjects(MI, Objs)) { + for (SmallVectorImpl<ValueType>::const_iterator I = Objs.begin(); + I != Objs.end(); ++I) + HasHazard |= updateDefsUses(*I, MI.mayStore()); + + return HasHazard; + } + + // No underlying objects found. + HasHazard = MI.mayStore() && (OrigSeenLoad || OrigSeenStore); + HasHazard |= MI.mayLoad() || OrigSeenStore; + + SeenNoObjLoad |= MI.mayLoad(); + SeenNoObjStore |= MI.mayStore(); + + return HasHazard; +} + +bool MemDefsUses::updateDefsUses(ValueType V, bool MayStore) { + if (MayStore) + return !Defs.insert(V).second || Uses.count(V) || SeenNoObjStore || + SeenNoObjLoad; + + Uses.insert(V); + return Defs.count(V) || SeenNoObjStore; +} + +bool MemDefsUses:: +getUnderlyingObjects(const MachineInstr &MI, + SmallVectorImpl<ValueType> &Objects) const { + if (!MI.hasOneMemOperand() || + (!(*MI.memoperands_begin())->getValue() && + !(*MI.memoperands_begin())->getPseudoValue())) + return false; + + if (const PseudoSourceValue *PSV = + (*MI.memoperands_begin())->getPseudoValue()) { + if (!PSV->isAliased(MFI)) + return false; + Objects.push_back(PSV); + return true; + } + + const Value *V = (*MI.memoperands_begin())->getValue(); + + SmallVector<Value *, 4> Objs; + GetUnderlyingObjects(const_cast<Value *>(V), Objs, DL); + + for (SmallVectorImpl<Value *>::iterator I = Objs.begin(), E = Objs.end(); + I != E; ++I) { + if (!isIdentifiedObject(V)) + return false; + + Objects.push_back(*I); + } + + return true; +} + +// Replace Branch with the compact branch instruction. +Iter Filler::replaceWithCompactBranch(MachineBasicBlock &MBB, + Iter Branch, DebugLoc DL) { + const MipsInstrInfo *TII = + MBB.getParent()->getSubtarget<MipsSubtarget>().getInstrInfo(); + + unsigned NewOpcode = + (((unsigned) Branch->getOpcode()) == Mips::BEQ) ? Mips::BEQZC_MM + : Mips::BNEZC_MM; + + const MCInstrDesc &NewDesc = TII->get(NewOpcode); + MachineInstrBuilder MIB = BuildMI(MBB, Branch, DL, NewDesc); + + MIB.addReg(Branch->getOperand(0).getReg()); + MIB.addMBB(Branch->getOperand(2).getMBB()); + + Iter tmpIter = Branch; + Branch = std::prev(Branch); + MBB.erase(tmpIter); + + return Branch; +} + +// Replace Jumps with the compact jump instruction. +Iter Filler::replaceWithCompactJump(MachineBasicBlock &MBB, + Iter Jump, DebugLoc DL) { + const MipsInstrInfo *TII = + MBB.getParent()->getSubtarget<MipsSubtarget>().getInstrInfo(); + + const MCInstrDesc &NewDesc = TII->get(Mips::JRC16_MM); + MachineInstrBuilder MIB = BuildMI(MBB, Jump, DL, NewDesc); + + MIB.addReg(Jump->getOperand(0).getReg()); + + Iter tmpIter = Jump; + Jump = std::prev(Jump); + MBB.erase(tmpIter); + + return Jump; +} + +// For given opcode returns opcode of corresponding instruction with short +// delay slot. +static int getEquivalentCallShort(int Opcode) { + switch (Opcode) { + case Mips::BGEZAL: + return Mips::BGEZALS_MM; + case Mips::BLTZAL: + return Mips::BLTZALS_MM; + case Mips::JAL: + return Mips::JALS_MM; + case Mips::JALR: + return Mips::JALRS_MM; + case Mips::JALR16_MM: + return Mips::JALRS16_MM; + default: + llvm_unreachable("Unexpected call instruction for microMIPS."); + } +} + +/// runOnMachineBasicBlock - Fill in delay slots for the given basic block. +/// We assume there is only one delay slot per delayed instruction. +bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { + bool Changed = false; + const MipsSubtarget &STI = MBB.getParent()->getSubtarget<MipsSubtarget>(); + bool InMicroMipsMode = STI.inMicroMipsMode(); + const MipsInstrInfo *TII = STI.getInstrInfo(); + + for (Iter I = MBB.begin(); I != MBB.end(); ++I) { + if (!hasUnoccupiedSlot(&*I)) + continue; + + ++FilledSlots; + Changed = true; + + // Delay slot filling is disabled at -O0. + if (!DisableDelaySlotFiller && (TM.getOptLevel() != CodeGenOpt::None)) { + bool Filled = false; + + if (searchBackward(MBB, I)) { + Filled = true; + } else if (I->isTerminator()) { + if (searchSuccBBs(MBB, I)) { + Filled = true; + } + } else if (searchForward(MBB, I)) { + Filled = true; + } + + if (Filled) { + // Get instruction with delay slot. + MachineBasicBlock::instr_iterator DSI(I); + + if (InMicroMipsMode && TII->GetInstSizeInBytes(&*std::next(DSI)) == 2 && + DSI->isCall()) { + // If instruction in delay slot is 16b change opcode to + // corresponding instruction with short delay slot. + DSI->setDesc(TII->get(getEquivalentCallShort(DSI->getOpcode()))); + } + + continue; + } + } + + // If instruction is BEQ or BNE with one ZERO register, then instead of + // adding NOP replace this instruction with the corresponding compact + // branch instruction, i.e. BEQZC or BNEZC. + unsigned Opcode = I->getOpcode(); + if (InMicroMipsMode) { + switch (Opcode) { + case Mips::BEQ: + case Mips::BNE: + if (((unsigned) I->getOperand(1).getReg()) == Mips::ZERO) { + I = replaceWithCompactBranch(MBB, I, I->getDebugLoc()); + continue; + } + break; + case Mips::JR: + case Mips::PseudoReturn: + case Mips::PseudoIndirectBranch: + // For microMIPS the PseudoReturn and PseudoIndirectBranch are allways + // expanded to JR_MM, so they can be replaced with JRC16_MM. + I = replaceWithCompactJump(MBB, I, I->getDebugLoc()); + continue; + default: + break; + } + } + // Bundle the NOP to the instruction with the delay slot. + BuildMI(MBB, std::next(I), I->getDebugLoc(), TII->get(Mips::NOP)); + MIBundleBuilder(MBB, I, std::next(I, 2)); + } + + return Changed; +} + +/// createMipsDelaySlotFillerPass - Returns a pass that fills in delay +/// slots in Mips MachineFunctions +FunctionPass *llvm::createMipsDelaySlotFillerPass(MipsTargetMachine &tm) { + return new Filler(tm); +} + +template<typename IterTy> +bool Filler::searchRange(MachineBasicBlock &MBB, IterTy Begin, IterTy End, + RegDefsUses &RegDU, InspectMemInstr& IM, Iter Slot, + IterTy &Filler) const { + bool IsReverseIter = std::is_convertible<IterTy, ReverseIter>::value; + + for (IterTy I = Begin; I != End;) { + IterTy CurrI = I; + ++I; + + // skip debug value + if (CurrI->isDebugValue()) + continue; + + if (terminateSearch(*CurrI)) + break; + + assert((!CurrI->isCall() && !CurrI->isReturn() && !CurrI->isBranch()) && + "Cannot put calls, returns or branches in delay slot."); + + if (CurrI->isKill()) { + CurrI->eraseFromParent(); + + // This special case is needed for reverse iterators, because when we + // erase an instruction, the iterators are updated to point to the next + // instruction. + if (IsReverseIter && I != End) + I = CurrI; + continue; + } + + if (delayHasHazard(*CurrI, RegDU, IM)) + continue; + + const MipsSubtarget &STI = MBB.getParent()->getSubtarget<MipsSubtarget>(); + if (STI.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(CurrI->getOpcode(), &AddrIdx) && + baseRegNeedsLoadStoreMask(CurrI->getOperand(AddrIdx).getReg())) || + CurrI->modifiesRegister(Mips::SP, STI.getRegisterInfo())) + continue; + } + + bool InMicroMipsMode = STI.inMicroMipsMode(); + const MipsInstrInfo *TII = STI.getInstrInfo(); + unsigned Opcode = (*Slot).getOpcode(); + if (InMicroMipsMode && TII->GetInstSizeInBytes(&(*CurrI)) == 2 && + (Opcode == Mips::JR || Opcode == Mips::PseudoIndirectBranch || + Opcode == Mips::PseudoReturn)) + continue; + + Filler = CurrI; + return true; + } + + return false; +} + +bool Filler::searchBackward(MachineBasicBlock &MBB, Iter Slot) const { + if (DisableBackwardSearch) + return false; + + auto *Fn = MBB.getParent(); + RegDefsUses RegDU(*Fn->getSubtarget().getRegisterInfo()); + MemDefsUses MemDU(Fn->getDataLayout(), Fn->getFrameInfo()); + ReverseIter Filler; + + RegDU.init(*Slot); + + if (!searchRange(MBB, ReverseIter(Slot), MBB.rend(), RegDU, MemDU, Slot, + Filler)) + return false; + + MBB.splice(std::next(Slot), &MBB, std::next(Filler).base()); + MIBundleBuilder(MBB, Slot, std::next(Slot, 2)); + ++UsefulSlots; + return true; +} + +bool Filler::searchForward(MachineBasicBlock &MBB, Iter Slot) const { + // Can handle only calls. + if (DisableForwardSearch || !Slot->isCall()) + return false; + + RegDefsUses RegDU(*MBB.getParent()->getSubtarget().getRegisterInfo()); + NoMemInstr NM; + Iter Filler; + + RegDU.setCallerSaved(*Slot); + + if (!searchRange(MBB, std::next(Slot), MBB.end(), RegDU, NM, Slot, Filler)) + return false; + + MBB.splice(std::next(Slot), &MBB, Filler); + MIBundleBuilder(MBB, Slot, std::next(Slot, 2)); + ++UsefulSlots; + return true; +} + +bool Filler::searchSuccBBs(MachineBasicBlock &MBB, Iter Slot) const { + if (DisableSuccBBSearch) + return false; + + MachineBasicBlock *SuccBB = selectSuccBB(MBB); + + if (!SuccBB) + return false; + + RegDefsUses RegDU(*MBB.getParent()->getSubtarget().getRegisterInfo()); + bool HasMultipleSuccs = false; + BB2BrMap BrMap; + std::unique_ptr<InspectMemInstr> IM; + Iter Filler; + auto *Fn = MBB.getParent(); + + // Iterate over SuccBB's predecessor list. + for (MachineBasicBlock::pred_iterator PI = SuccBB->pred_begin(), + PE = SuccBB->pred_end(); PI != PE; ++PI) + if (!examinePred(**PI, *SuccBB, RegDU, HasMultipleSuccs, BrMap)) + return false; + + // Do not allow moving instructions which have unallocatable register operands + // across basic block boundaries. + RegDU.setUnallocatableRegs(*Fn); + + // Only allow moving loads from stack or constants if any of the SuccBB's + // predecessors have multiple successors. + if (HasMultipleSuccs) { + IM.reset(new LoadFromStackOrConst()); + } else { + const MachineFrameInfo *MFI = Fn->getFrameInfo(); + IM.reset(new MemDefsUses(Fn->getDataLayout(), MFI)); + } + + if (!searchRange(MBB, SuccBB->begin(), SuccBB->end(), RegDU, *IM, Slot, + Filler)) + return false; + + insertDelayFiller(Filler, BrMap); + addLiveInRegs(Filler, *SuccBB); + Filler->eraseFromParent(); + + return true; +} + +MachineBasicBlock *Filler::selectSuccBB(MachineBasicBlock &B) const { + if (B.succ_empty()) + return nullptr; + + // Select the successor with the larget edge weight. + auto &Prob = getAnalysis<MachineBranchProbabilityInfo>(); + MachineBasicBlock *S = *std::max_element( + B.succ_begin(), B.succ_end(), + [&](const MachineBasicBlock *Dst0, const MachineBasicBlock *Dst1) { + return Prob.getEdgeProbability(&B, Dst0) < + Prob.getEdgeProbability(&B, Dst1); + }); + return S->isEHPad() ? nullptr : S; +} + +std::pair<MipsInstrInfo::BranchType, MachineInstr *> +Filler::getBranch(MachineBasicBlock &MBB, const MachineBasicBlock &Dst) const { + const MipsInstrInfo *TII = + MBB.getParent()->getSubtarget<MipsSubtarget>().getInstrInfo(); + MachineBasicBlock *TrueBB = nullptr, *FalseBB = nullptr; + SmallVector<MachineInstr*, 2> BranchInstrs; + SmallVector<MachineOperand, 2> Cond; + + MipsInstrInfo::BranchType R = + TII->AnalyzeBranch(MBB, TrueBB, FalseBB, Cond, false, BranchInstrs); + + if ((R == MipsInstrInfo::BT_None) || (R == MipsInstrInfo::BT_NoBranch)) + return std::make_pair(R, nullptr); + + if (R != MipsInstrInfo::BT_CondUncond) { + if (!hasUnoccupiedSlot(BranchInstrs[0])) + return std::make_pair(MipsInstrInfo::BT_None, nullptr); + + assert(((R != MipsInstrInfo::BT_Uncond) || (TrueBB == &Dst))); + + return std::make_pair(R, BranchInstrs[0]); + } + + assert((TrueBB == &Dst) || (FalseBB == &Dst)); + + // Examine the conditional branch. See if its slot is occupied. + if (hasUnoccupiedSlot(BranchInstrs[0])) + return std::make_pair(MipsInstrInfo::BT_Cond, BranchInstrs[0]); + + // If that fails, try the unconditional branch. + if (hasUnoccupiedSlot(BranchInstrs[1]) && (FalseBB == &Dst)) + return std::make_pair(MipsInstrInfo::BT_Uncond, BranchInstrs[1]); + + return std::make_pair(MipsInstrInfo::BT_None, nullptr); +} + +bool Filler::examinePred(MachineBasicBlock &Pred, const MachineBasicBlock &Succ, + RegDefsUses &RegDU, bool &HasMultipleSuccs, + BB2BrMap &BrMap) const { + std::pair<MipsInstrInfo::BranchType, MachineInstr *> P = + getBranch(Pred, Succ); + + // Return if either getBranch wasn't able to analyze the branches or there + // were no branches with unoccupied slots. + if (P.first == MipsInstrInfo::BT_None) + return false; + + if ((P.first != MipsInstrInfo::BT_Uncond) && + (P.first != MipsInstrInfo::BT_NoBranch)) { + HasMultipleSuccs = true; + RegDU.addLiveOut(Pred, Succ); + } + + BrMap[&Pred] = P.second; + return true; +} + +bool Filler::delayHasHazard(const MachineInstr &Candidate, RegDefsUses &RegDU, + InspectMemInstr &IM) const { + assert(!Candidate.isKill() && + "KILL instructions should have been eliminated at this point."); + + bool HasHazard = Candidate.isImplicitDef(); + + HasHazard |= IM.hasHazard(Candidate); + HasHazard |= RegDU.update(Candidate, 0, Candidate.getNumOperands()); + + return HasHazard; +} + +bool Filler::terminateSearch(const MachineInstr &Candidate) const { + return (Candidate.isTerminator() || Candidate.isCall() || + Candidate.isPosition() || Candidate.isInlineAsm() || + Candidate.hasUnmodeledSideEffects()); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsEVAInstrFormats.td b/contrib/llvm/lib/Target/Mips/MipsEVAInstrFormats.td new file mode 100644 index 0000000..11e191a --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsEVAInstrFormats.td @@ -0,0 +1,84 @@ +//===- MipsEVAInstrFormats.td - Mips Instruction Formats ---*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes Mips32r6 instruction formats. +// +//===----------------------------------------------------------------------===// + +class MipsEVAInst : MipsInst<(outs), (ins), "", [], NoItinerary, FrmOther>, + PredicateControl, StdArch { + let DecoderNamespace = "Mips"; + let EncodingPredicates = [HasStdEnc]; +} + +//===----------------------------------------------------------------------===// +// +// Field Values +// +//===----------------------------------------------------------------------===// + +// Memory Load/Store EVA +def OPCODE6_LBE : OPCODE6<0b101100>; +def OPCODE6_LBuE : OPCODE6<0b101000>; +def OPCODE6_LHE : OPCODE6<0b101101>; +def OPCODE6_LHuE : OPCODE6<0b101001>; +def OPCODE6_LWE : OPCODE6<0b101111>; + +def OPCODE6_SBE : OPCODE6<0b011100>; +def OPCODE6_SHE : OPCODE6<0b011101>; +def OPCODE6_SWE : OPCODE6<0b011111>; + +// load/store left/right EVA +def OPCODE6_LWLE : OPCODE6<0b011001>; +def OPCODE6_LWRE : OPCODE6<0b011010>; +def OPCODE6_SWLE : OPCODE6<0b100001>; +def OPCODE6_SWRE : OPCODE6<0b100010>; + +// Load-linked EVA, Store-conditional EVA +def OPCODE6_LLE : OPCODE6<0b101110>; +def OPCODE6_SCE : OPCODE6<0b011110>; + +def OPCODE6_TLBINV : OPCODE6<0b000011>; +def OPCODE6_TLBINVF : OPCODE6<0b000100>; + +def OPCODE6_CACHEE : OPCODE6<0b011011>; +def OPCODE6_PREFE : OPCODE6<0b100011>; + +def OPGROUP_COP0 : OPGROUP<0b010000>; + +//===----------------------------------------------------------------------===// +// +// Encoding Formats +// +//===----------------------------------------------------------------------===// + +class SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6 Operation> : MipsEVAInst { + bits<21> addr; + bits<5> hint; + bits<5> base = addr{20-16}; + bits<9> offset = addr{8-0}; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL3.Value; + let Inst{25-21} = base; + let Inst{20-16} = hint; + let Inst{15-7} = offset; + let Inst{6} = 0; + let Inst{5-0} = Operation.Value; +} + +class TLB_FM<OPCODE6 Operation> : MipsEVAInst { + bits<32> Inst; + + let Inst{31-26} = OPGROUP_COP0.Value; + let Inst{25} = 1; // CO + let Inst{24-6} = 0; + let Inst{5-0} = Operation.Value; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsEVAInstrInfo.td b/contrib/llvm/lib/Target/Mips/MipsEVAInstrInfo.td new file mode 100644 index 0000000..36c9694 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsEVAInstrInfo.td @@ -0,0 +1,192 @@ +//===- MipsEVAInstrInfo.td - EVA ASE instructions -*- tablegen ------------*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes Mips EVA ASE instructions. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// +// Instruction encodings +// +//===----------------------------------------------------------------------===// + +// Memory Load/Store EVA encodings +class LBE_ENC : SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6_LBE>; +class LBuE_ENC : SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6_LBuE>; +class LHE_ENC : SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6_LHE>; +class LHuE_ENC : SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6_LHuE>; +class LWE_ENC : SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6_LWE>; + +class SBE_ENC : SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6_SBE>; +class SHE_ENC : SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6_SHE>; +class SWE_ENC : SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6_SWE>; + +// load/store left/right EVA encodings +class LWLE_ENC : SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6_LWLE>; +class LWRE_ENC : SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6_LWRE>; +class SWLE_ENC : SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6_SWLE>; +class SWRE_ENC : SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6_SWRE>; + +// Load-linked EVA, Store-conditional EVA encodings +class LLE_ENC : SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6_LLE>; +class SCE_ENC : SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6_SCE>; + +class TLBINV_ENC : TLB_FM<OPCODE6_TLBINV>; +class TLBINVF_ENC : TLB_FM<OPCODE6_TLBINVF>; + +class CACHEE_ENC : SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6_CACHEE>; +class PREFE_ENC : SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6_PREFE>; + +//===----------------------------------------------------------------------===// +// +// Instruction descriptions +// +//===----------------------------------------------------------------------===// + +// Memory Load/Store EVA descriptions +class LOAD_EVA_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$rt); + dag InOperandList = (ins mem_simm9:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + string DecoderMethod = "DecodeMemEVA"; + bit canFoldAsLoad = 1; + bit mayLoad = 1; +} + +class LBE_DESC : LOAD_EVA_DESC_BASE<"lbe", GPR32Opnd>; +class LBuE_DESC : LOAD_EVA_DESC_BASE<"lbue", GPR32Opnd>; +class LHE_DESC : LOAD_EVA_DESC_BASE<"lhe", GPR32Opnd>; +class LHuE_DESC : LOAD_EVA_DESC_BASE<"lhue", GPR32Opnd>; +class LWE_DESC : LOAD_EVA_DESC_BASE<"lwe", GPR32Opnd>; + +class STORE_EVA_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + SDPatternOperator OpNode = null_frag> { + dag OutOperandList = (outs); + dag InOperandList = (ins GPROpnd:$rt, mem_simm9:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + string DecoderMethod = "DecodeMemEVA"; + bit mayStore = 1; +} + +class SBE_DESC : STORE_EVA_DESC_BASE<"sbe", GPR32Opnd>; +class SHE_DESC : STORE_EVA_DESC_BASE<"she", GPR32Opnd>; +class SWE_DESC : STORE_EVA_DESC_BASE<"swe", GPR32Opnd>; + +// Load/Store Left/Right EVA descriptions +class LOAD_LEFT_RIGHT_EVA_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$rt); + dag InOperandList = (ins mem_simm9:$addr, GPROpnd:$src); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + string DecoderMethod = "DecodeMemEVA"; + string Constraints = "$src = $rt"; + bit canFoldAsLoad = 1; +} + +class LWLE_DESC : LOAD_LEFT_RIGHT_EVA_DESC_BASE<"lwle", GPR32Opnd>; +class LWRE_DESC : LOAD_LEFT_RIGHT_EVA_DESC_BASE<"lwre", GPR32Opnd>; + +class STORE_LEFT_RIGHT_EVA_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs); + dag InOperandList = (ins GPROpnd:$rt, mem_simm9:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + string DecoderMethod = "DecodeMemEVA"; +} + +class SWLE_DESC : LOAD_LEFT_RIGHT_EVA_DESC_BASE<"swle", GPR32Opnd>; +class SWRE_DESC : LOAD_LEFT_RIGHT_EVA_DESC_BASE<"swre", GPR32Opnd>; + +// Load-linked EVA, Store-conditional EVA descriptions +class LLE_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$rt); + dag InOperandList = (ins mem_simm9:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + bit mayLoad = 1; + string DecoderMethod = "DecodeMemEVA"; +} + +class LLE_DESC : LLE_DESC_BASE<"lle", GPR32Opnd>; + +class SCE_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$dst); + dag InOperandList = (ins GPROpnd:$rt, mem_simm9:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + bit mayStore = 1; + string Constraints = "$rt = $dst"; + string DecoderMethod = "DecodeMemEVA"; +} + +class SCE_DESC : SCE_DESC_BASE<"sce", GPR32Opnd>; + +class TLB_DESC_BASE<string instr_asm> { + dag OutOperandList = (outs); + dag InOperandList = (ins); + string AsmString = instr_asm; + list<dag> Pattern = []; +} + +class TLBINV_DESC : TLB_DESC_BASE<"tlbinv">; +class TLBINVF_DESC : TLB_DESC_BASE<"tlbinvf">; + +class CACHEE_DESC_BASE<string instr_asm, Operand MemOpnd> { + dag OutOperandList = (outs); + dag InOperandList = (ins MemOpnd:$addr, uimm5:$hint); + string AsmString = !strconcat(instr_asm, "\t$hint, $addr"); + list<dag> Pattern = []; + string DecoderMethod = "DecodeCacheeOp_CacheOpR6"; +} + +class CACHEE_DESC : CACHEE_DESC_BASE<"cachee", mem>; +class PREFE_DESC : CACHEE_DESC_BASE<"prefe", mem>; + +//===----------------------------------------------------------------------===// +// +// Instruction definitions +// +//===----------------------------------------------------------------------===// + +/// Load and Store EVA Instructions +def LBE : LBE_ENC, LBE_DESC, INSN_EVA; +def LBuE : LBuE_ENC, LBuE_DESC, INSN_EVA; +def LHE : LHE_ENC, LHE_DESC, INSN_EVA; +def LHuE : LHuE_ENC, LHuE_DESC, INSN_EVA; +let AdditionalPredicates = [NotInMicroMips] in { +def LWE : LWE_ENC, LWE_DESC, INSN_EVA; +} +def SBE : SBE_ENC, SBE_DESC, INSN_EVA; +def SHE : SHE_ENC, SHE_DESC, INSN_EVA; +let AdditionalPredicates = [NotInMicroMips] in { +def SWE : SWE_ENC, SWE_DESC, INSN_EVA; +} + +/// load/store left/right EVA +let AdditionalPredicates = [NotInMicroMips] in { +def LWLE : LWLE_ENC, LWLE_DESC, INSN_EVA_NOT_32R6_64R6; +def LWRE : LWRE_ENC, LWRE_DESC, INSN_EVA_NOT_32R6_64R6; +def SWLE : SWLE_ENC, SWLE_DESC, INSN_EVA_NOT_32R6_64R6; +def SWRE : SWRE_ENC, SWRE_DESC, INSN_EVA_NOT_32R6_64R6; +} + +/// Load-linked EVA, Store-conditional EVA +let AdditionalPredicates = [NotInMicroMips] in { +def LLE : LLE_ENC, LLE_DESC, INSN_EVA; +def SCE : SCE_ENC, SCE_DESC, INSN_EVA; +} + +def TLBINV : TLBINV_ENC, TLBINV_DESC, INSN_EVA; +def TLBINVF : TLBINVF_ENC, TLBINVF_DESC, INSN_EVA; + +def CACHEE : CACHEE_ENC, CACHEE_DESC, INSN_EVA; +def PREFE : PREFE_ENC, PREFE_DESC, INSN_EVA; diff --git a/contrib/llvm/lib/Target/Mips/MipsFastISel.cpp b/contrib/llvm/lib/Target/Mips/MipsFastISel.cpp new file mode 100644 index 0000000..e9eaf81 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsFastISel.cpp @@ -0,0 +1,1885 @@ +//===-- MipsastISel.cpp - Mips FastISel implementation +//---------------------===// + +#include "MipsCCState.h" +#include "MipsInstrInfo.h" +#include "MipsISelLowering.h" +#include "MipsMachineFunction.h" +#include "MipsRegisterInfo.h" +#include "MipsSubtarget.h" +#include "MipsTargetMachine.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/CodeGen/FastISel.h" +#include "llvm/CodeGen/FunctionLoweringInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/GetElementPtrTypeIterator.h" +#include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Target/TargetInstrInfo.h" + +using namespace llvm; + +namespace { + +class MipsFastISel final : public FastISel { + + // All possible address modes. + class Address { + public: + typedef enum { RegBase, FrameIndexBase } BaseKind; + + private: + BaseKind Kind; + union { + unsigned Reg; + int FI; + } Base; + + int64_t Offset; + + const GlobalValue *GV; + + public: + // Innocuous defaults for our address. + Address() : Kind(RegBase), Offset(0), GV(0) { Base.Reg = 0; } + void setKind(BaseKind K) { Kind = K; } + BaseKind getKind() const { return Kind; } + bool isRegBase() const { return Kind == RegBase; } + bool isFIBase() const { return Kind == FrameIndexBase; } + void setReg(unsigned Reg) { + assert(isRegBase() && "Invalid base register access!"); + Base.Reg = Reg; + } + unsigned getReg() const { + assert(isRegBase() && "Invalid base register access!"); + return Base.Reg; + } + void setFI(unsigned FI) { + assert(isFIBase() && "Invalid base frame index access!"); + Base.FI = FI; + } + unsigned getFI() const { + assert(isFIBase() && "Invalid base frame index access!"); + return Base.FI; + } + + void setOffset(int64_t Offset_) { Offset = Offset_; } + int64_t getOffset() const { return Offset; } + void setGlobalValue(const GlobalValue *G) { GV = G; } + const GlobalValue *getGlobalValue() { return GV; } + }; + + /// Subtarget - Keep a pointer to the MipsSubtarget around so that we can + /// make the right decision when generating code for different targets. + const TargetMachine &TM; + const MipsSubtarget *Subtarget; + const TargetInstrInfo &TII; + const TargetLowering &TLI; + MipsFunctionInfo *MFI; + + // Convenience variables to avoid some queries. + LLVMContext *Context; + + bool fastLowerCall(CallLoweringInfo &CLI) override; + bool fastLowerIntrinsicCall(const IntrinsicInst *II) override; + + bool TargetSupported; + bool UnsupportedFPMode; // To allow fast-isel to proceed and just not handle + // floating point but not reject doing fast-isel in other + // situations + +private: + // Selection routines. + bool selectLogicalOp(const Instruction *I); + bool selectLoad(const Instruction *I); + bool selectStore(const Instruction *I); + bool selectBranch(const Instruction *I); + bool selectSelect(const Instruction *I); + bool selectCmp(const Instruction *I); + bool selectFPExt(const Instruction *I); + bool selectFPTrunc(const Instruction *I); + bool selectFPToInt(const Instruction *I, bool IsSigned); + bool selectRet(const Instruction *I); + bool selectTrunc(const Instruction *I); + bool selectIntExt(const Instruction *I); + bool selectShift(const Instruction *I); + bool selectDivRem(const Instruction *I, unsigned ISDOpcode); + + // Utility helper routines. + bool isTypeLegal(Type *Ty, MVT &VT); + bool isTypeSupported(Type *Ty, MVT &VT); + bool isLoadTypeLegal(Type *Ty, MVT &VT); + bool computeAddress(const Value *Obj, Address &Addr); + bool computeCallAddress(const Value *V, Address &Addr); + void simplifyAddress(Address &Addr); + + // Emit helper routines. + bool emitCmp(unsigned DestReg, const CmpInst *CI); + bool emitLoad(MVT VT, unsigned &ResultReg, Address &Addr, + unsigned Alignment = 0); + bool emitStore(MVT VT, unsigned SrcReg, Address Addr, + MachineMemOperand *MMO = nullptr); + bool emitStore(MVT VT, unsigned SrcReg, Address &Addr, + unsigned Alignment = 0); + unsigned emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, bool isZExt); + bool emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg, + + bool IsZExt); + bool emitIntZExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg); + + bool emitIntSExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg); + bool emitIntSExt32r1(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg); + bool emitIntSExt32r2(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg); + + unsigned getRegEnsuringSimpleIntegerWidening(const Value *, bool IsUnsigned); + + unsigned emitLogicalOp(unsigned ISDOpc, MVT RetVT, const Value *LHS, + const Value *RHS); + + unsigned materializeFP(const ConstantFP *CFP, MVT VT); + unsigned materializeGV(const GlobalValue *GV, MVT VT); + unsigned materializeInt(const Constant *C, MVT VT); + unsigned materialize32BitInt(int64_t Imm, const TargetRegisterClass *RC); + unsigned materializeExternalCallSym(MCSymbol *Syn); + + MachineInstrBuilder emitInst(unsigned Opc) { + return BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)); + } + MachineInstrBuilder emitInst(unsigned Opc, unsigned DstReg) { + return BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), + DstReg); + } + MachineInstrBuilder emitInstStore(unsigned Opc, unsigned SrcReg, + unsigned MemReg, int64_t MemOffset) { + return emitInst(Opc).addReg(SrcReg).addReg(MemReg).addImm(MemOffset); + } + MachineInstrBuilder emitInstLoad(unsigned Opc, unsigned DstReg, + unsigned MemReg, int64_t MemOffset) { + return emitInst(Opc, DstReg).addReg(MemReg).addImm(MemOffset); + } + + unsigned fastEmitInst_rr(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill, + unsigned Op1, bool Op1IsKill); + + // for some reason, this default is not generated by tablegen + // so we explicitly generate it here. + // + unsigned fastEmitInst_riir(uint64_t inst, const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill, uint64_t imm1, + uint64_t imm2, unsigned Op3, bool Op3IsKill) { + return 0; + } + + // Call handling routines. +private: + CCAssignFn *CCAssignFnForCall(CallingConv::ID CC) const; + bool processCallArgs(CallLoweringInfo &CLI, SmallVectorImpl<MVT> &ArgVTs, + unsigned &NumBytes); + bool finishCall(CallLoweringInfo &CLI, MVT RetVT, unsigned NumBytes); + +public: + // Backend specific FastISel code. + explicit MipsFastISel(FunctionLoweringInfo &funcInfo, + const TargetLibraryInfo *libInfo) + : FastISel(funcInfo, libInfo), TM(funcInfo.MF->getTarget()), + Subtarget(&funcInfo.MF->getSubtarget<MipsSubtarget>()), + TII(*Subtarget->getInstrInfo()), TLI(*Subtarget->getTargetLowering()) { + MFI = funcInfo.MF->getInfo<MipsFunctionInfo>(); + Context = &funcInfo.Fn->getContext(); + bool ISASupported = !Subtarget->hasMips32r6() && Subtarget->hasMips32(); + TargetSupported = + ISASupported && (TM.getRelocationModel() == Reloc::PIC_) && + (static_cast<const MipsTargetMachine &>(TM).getABI().IsO32()); + UnsupportedFPMode = Subtarget->isFP64bit(); + } + + unsigned fastMaterializeAlloca(const AllocaInst *AI) override; + unsigned fastMaterializeConstant(const Constant *C) override; + bool fastSelectInstruction(const Instruction *I) override; + +#include "MipsGenFastISel.inc" +}; +} // end anonymous namespace. + +static bool CC_Mips(unsigned ValNo, MVT ValVT, MVT LocVT, + CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, + CCState &State) LLVM_ATTRIBUTE_UNUSED; + +static bool CC_MipsO32_FP32(unsigned ValNo, MVT ValVT, MVT LocVT, + CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags, CCState &State) { + llvm_unreachable("should not be called"); +} + +static bool CC_MipsO32_FP64(unsigned ValNo, MVT ValVT, MVT LocVT, + CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags, CCState &State) { + llvm_unreachable("should not be called"); +} + +#include "MipsGenCallingConv.inc" + +CCAssignFn *MipsFastISel::CCAssignFnForCall(CallingConv::ID CC) const { + return CC_MipsO32; +} + +unsigned MipsFastISel::emitLogicalOp(unsigned ISDOpc, MVT RetVT, + const Value *LHS, const Value *RHS) { + // Canonicalize immediates to the RHS first. + if (isa<ConstantInt>(LHS) && !isa<ConstantInt>(RHS)) + std::swap(LHS, RHS); + + unsigned Opc; + switch (ISDOpc) { + case ISD::AND: + Opc = Mips::AND; + break; + case ISD::OR: + Opc = Mips::OR; + break; + case ISD::XOR: + Opc = Mips::XOR; + break; + default: + llvm_unreachable("unexpected opcode"); + } + + unsigned LHSReg = getRegForValue(LHS); + if (!LHSReg) + return 0; + + unsigned RHSReg; + if (const auto *C = dyn_cast<ConstantInt>(RHS)) + RHSReg = materializeInt(C, MVT::i32); + else + RHSReg = getRegForValue(RHS); + if (!RHSReg) + return 0; + + unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); + if (!ResultReg) + return 0; + + emitInst(Opc, ResultReg).addReg(LHSReg).addReg(RHSReg); + return ResultReg; +} + +unsigned MipsFastISel::fastMaterializeAlloca(const AllocaInst *AI) { + if (!TargetSupported) + return 0; + + assert(TLI.getValueType(DL, AI->getType(), true) == MVT::i32 && + "Alloca should always return a pointer."); + + DenseMap<const AllocaInst *, int>::iterator SI = + FuncInfo.StaticAllocaMap.find(AI); + + if (SI != FuncInfo.StaticAllocaMap.end()) { + unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::LEA_ADDiu), + ResultReg) + .addFrameIndex(SI->second) + .addImm(0); + return ResultReg; + } + + return 0; +} + +unsigned MipsFastISel::materializeInt(const Constant *C, MVT VT) { + if (VT != MVT::i32 && VT != MVT::i16 && VT != MVT::i8 && VT != MVT::i1) + return 0; + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + const ConstantInt *CI = cast<ConstantInt>(C); + return materialize32BitInt(CI->getZExtValue(), RC); +} + +unsigned MipsFastISel::materialize32BitInt(int64_t Imm, + const TargetRegisterClass *RC) { + unsigned ResultReg = createResultReg(RC); + + if (isInt<16>(Imm)) { + unsigned Opc = Mips::ADDiu; + emitInst(Opc, ResultReg).addReg(Mips::ZERO).addImm(Imm); + return ResultReg; + } else if (isUInt<16>(Imm)) { + emitInst(Mips::ORi, ResultReg).addReg(Mips::ZERO).addImm(Imm); + return ResultReg; + } + unsigned Lo = Imm & 0xFFFF; + unsigned Hi = (Imm >> 16) & 0xFFFF; + if (Lo) { + // Both Lo and Hi have nonzero bits. + unsigned TmpReg = createResultReg(RC); + emitInst(Mips::LUi, TmpReg).addImm(Hi); + emitInst(Mips::ORi, ResultReg).addReg(TmpReg).addImm(Lo); + } else { + emitInst(Mips::LUi, ResultReg).addImm(Hi); + } + return ResultReg; +} + +unsigned MipsFastISel::materializeFP(const ConstantFP *CFP, MVT VT) { + if (UnsupportedFPMode) + return 0; + int64_t Imm = CFP->getValueAPF().bitcastToAPInt().getZExtValue(); + if (VT == MVT::f32) { + const TargetRegisterClass *RC = &Mips::FGR32RegClass; + unsigned DestReg = createResultReg(RC); + unsigned TempReg = materialize32BitInt(Imm, &Mips::GPR32RegClass); + emitInst(Mips::MTC1, DestReg).addReg(TempReg); + return DestReg; + } else if (VT == MVT::f64) { + const TargetRegisterClass *RC = &Mips::AFGR64RegClass; + unsigned DestReg = createResultReg(RC); + unsigned TempReg1 = materialize32BitInt(Imm >> 32, &Mips::GPR32RegClass); + unsigned TempReg2 = + materialize32BitInt(Imm & 0xFFFFFFFF, &Mips::GPR32RegClass); + emitInst(Mips::BuildPairF64, DestReg).addReg(TempReg2).addReg(TempReg1); + return DestReg; + } + return 0; +} + +unsigned MipsFastISel::materializeGV(const GlobalValue *GV, MVT VT) { + // For now 32-bit only. + if (VT != MVT::i32) + return 0; + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + unsigned DestReg = createResultReg(RC); + const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV); + bool IsThreadLocal = GVar && GVar->isThreadLocal(); + // TLS not supported at this time. + if (IsThreadLocal) + return 0; + emitInst(Mips::LW, DestReg) + .addReg(MFI->getGlobalBaseReg()) + .addGlobalAddress(GV, 0, MipsII::MO_GOT); + if ((GV->hasInternalLinkage() || + (GV->hasLocalLinkage() && !isa<Function>(GV)))) { + unsigned TempReg = createResultReg(RC); + emitInst(Mips::ADDiu, TempReg) + .addReg(DestReg) + .addGlobalAddress(GV, 0, MipsII::MO_ABS_LO); + DestReg = TempReg; + } + return DestReg; +} + +unsigned MipsFastISel::materializeExternalCallSym(MCSymbol *Sym) { + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + unsigned DestReg = createResultReg(RC); + emitInst(Mips::LW, DestReg) + .addReg(MFI->getGlobalBaseReg()) + .addSym(Sym, MipsII::MO_GOT); + return DestReg; +} + +// Materialize a constant into a register, and return the register +// number (or zero if we failed to handle it). +unsigned MipsFastISel::fastMaterializeConstant(const Constant *C) { + if (!TargetSupported) + return 0; + + EVT CEVT = TLI.getValueType(DL, C->getType(), true); + + // Only handle simple types. + if (!CEVT.isSimple()) + return 0; + MVT VT = CEVT.getSimpleVT(); + + if (const ConstantFP *CFP = dyn_cast<ConstantFP>(C)) + return (UnsupportedFPMode) ? 0 : materializeFP(CFP, VT); + else if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) + return materializeGV(GV, VT); + else if (isa<ConstantInt>(C)) + return materializeInt(C, VT); + + return 0; +} + +bool MipsFastISel::computeAddress(const Value *Obj, Address &Addr) { + + const User *U = nullptr; + unsigned Opcode = Instruction::UserOp1; + if (const Instruction *I = dyn_cast<Instruction>(Obj)) { + // Don't walk into other basic blocks unless the object is an alloca from + // another block, otherwise it may not have a virtual register assigned. + if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) || + FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) { + Opcode = I->getOpcode(); + U = I; + } + } else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(Obj)) { + Opcode = C->getOpcode(); + U = C; + } + switch (Opcode) { + default: + break; + case Instruction::BitCast: { + // Look through bitcasts. + return computeAddress(U->getOperand(0), Addr); + } + case Instruction::GetElementPtr: { + Address SavedAddr = Addr; + uint64_t TmpOffset = Addr.getOffset(); + // Iterate through the GEP folding the constants into offsets where + // we can. + gep_type_iterator GTI = gep_type_begin(U); + for (User::const_op_iterator i = U->op_begin() + 1, e = U->op_end(); i != e; + ++i, ++GTI) { + const Value *Op = *i; + if (StructType *STy = dyn_cast<StructType>(*GTI)) { + const StructLayout *SL = DL.getStructLayout(STy); + unsigned Idx = cast<ConstantInt>(Op)->getZExtValue(); + TmpOffset += SL->getElementOffset(Idx); + } else { + uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType()); + for (;;) { + if (const ConstantInt *CI = dyn_cast<ConstantInt>(Op)) { + // Constant-offset addressing. + TmpOffset += CI->getSExtValue() * S; + break; + } + if (canFoldAddIntoGEP(U, Op)) { + // A compatible add with a constant operand. Fold the constant. + ConstantInt *CI = + cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1)); + TmpOffset += CI->getSExtValue() * S; + // Iterate on the other operand. + Op = cast<AddOperator>(Op)->getOperand(0); + continue; + } + // Unsupported + goto unsupported_gep; + } + } + } + // Try to grab the base operand now. + Addr.setOffset(TmpOffset); + if (computeAddress(U->getOperand(0), Addr)) + return true; + // We failed, restore everything and try the other options. + Addr = SavedAddr; + unsupported_gep: + break; + } + case Instruction::Alloca: { + const AllocaInst *AI = cast<AllocaInst>(Obj); + DenseMap<const AllocaInst *, int>::iterator SI = + FuncInfo.StaticAllocaMap.find(AI); + if (SI != FuncInfo.StaticAllocaMap.end()) { + Addr.setKind(Address::FrameIndexBase); + Addr.setFI(SI->second); + return true; + } + break; + } + } + Addr.setReg(getRegForValue(Obj)); + return Addr.getReg() != 0; +} + +bool MipsFastISel::computeCallAddress(const Value *V, Address &Addr) { + const User *U = nullptr; + unsigned Opcode = Instruction::UserOp1; + + if (const auto *I = dyn_cast<Instruction>(V)) { + // Check if the value is defined in the same basic block. This information + // is crucial to know whether or not folding an operand is valid. + if (I->getParent() == FuncInfo.MBB->getBasicBlock()) { + Opcode = I->getOpcode(); + U = I; + } + } else if (const auto *C = dyn_cast<ConstantExpr>(V)) { + Opcode = C->getOpcode(); + U = C; + } + + switch (Opcode) { + default: + break; + case Instruction::BitCast: + // Look past bitcasts if its operand is in the same BB. + return computeCallAddress(U->getOperand(0), Addr); + break; + case Instruction::IntToPtr: + // Look past no-op inttoptrs if its operand is in the same BB. + if (TLI.getValueType(DL, U->getOperand(0)->getType()) == + TLI.getPointerTy(DL)) + return computeCallAddress(U->getOperand(0), Addr); + break; + case Instruction::PtrToInt: + // Look past no-op ptrtoints if its operand is in the same BB. + if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL)) + return computeCallAddress(U->getOperand(0), Addr); + break; + } + + if (const GlobalValue *GV = dyn_cast<GlobalValue>(V)) { + Addr.setGlobalValue(GV); + return true; + } + + // If all else fails, try to materialize the value in a register. + if (!Addr.getGlobalValue()) { + Addr.setReg(getRegForValue(V)); + return Addr.getReg() != 0; + } + + return false; +} + +bool MipsFastISel::isTypeLegal(Type *Ty, MVT &VT) { + EVT evt = TLI.getValueType(DL, Ty, true); + // Only handle simple types. + if (evt == MVT::Other || !evt.isSimple()) + return false; + VT = evt.getSimpleVT(); + + // Handle all legal types, i.e. a register that will directly hold this + // value. + return TLI.isTypeLegal(VT); +} + +bool MipsFastISel::isTypeSupported(Type *Ty, MVT &VT) { + if (Ty->isVectorTy()) + return false; + + if (isTypeLegal(Ty, VT)) + return true; + + // If this is a type than can be sign or zero-extended to a basic operation + // go ahead and accept it now. + if (VT == MVT::i1 || VT == MVT::i8 || VT == MVT::i16) + return true; + + return false; +} + +bool MipsFastISel::isLoadTypeLegal(Type *Ty, MVT &VT) { + if (isTypeLegal(Ty, VT)) + return true; + // We will extend this in a later patch: + // If this is a type than can be sign or zero-extended to a basic operation + // go ahead and accept it now. + if (VT == MVT::i8 || VT == MVT::i16) + return true; + return false; +} +// Because of how EmitCmp is called with fast-isel, you can +// end up with redundant "andi" instructions after the sequences emitted below. +// We should try and solve this issue in the future. +// +bool MipsFastISel::emitCmp(unsigned ResultReg, const CmpInst *CI) { + const Value *Left = CI->getOperand(0), *Right = CI->getOperand(1); + bool IsUnsigned = CI->isUnsigned(); + unsigned LeftReg = getRegEnsuringSimpleIntegerWidening(Left, IsUnsigned); + if (LeftReg == 0) + return false; + unsigned RightReg = getRegEnsuringSimpleIntegerWidening(Right, IsUnsigned); + if (RightReg == 0) + return false; + CmpInst::Predicate P = CI->getPredicate(); + + switch (P) { + default: + return false; + case CmpInst::ICMP_EQ: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::XOR, TempReg).addReg(LeftReg).addReg(RightReg); + emitInst(Mips::SLTiu, ResultReg).addReg(TempReg).addImm(1); + break; + } + case CmpInst::ICMP_NE: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::XOR, TempReg).addReg(LeftReg).addReg(RightReg); + emitInst(Mips::SLTu, ResultReg).addReg(Mips::ZERO).addReg(TempReg); + break; + } + case CmpInst::ICMP_UGT: { + emitInst(Mips::SLTu, ResultReg).addReg(RightReg).addReg(LeftReg); + break; + } + case CmpInst::ICMP_ULT: { + emitInst(Mips::SLTu, ResultReg).addReg(LeftReg).addReg(RightReg); + break; + } + case CmpInst::ICMP_UGE: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::SLTu, TempReg).addReg(LeftReg).addReg(RightReg); + emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1); + break; + } + case CmpInst::ICMP_ULE: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::SLTu, TempReg).addReg(RightReg).addReg(LeftReg); + emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1); + break; + } + case CmpInst::ICMP_SGT: { + emitInst(Mips::SLT, ResultReg).addReg(RightReg).addReg(LeftReg); + break; + } + case CmpInst::ICMP_SLT: { + emitInst(Mips::SLT, ResultReg).addReg(LeftReg).addReg(RightReg); + break; + } + case CmpInst::ICMP_SGE: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::SLT, TempReg).addReg(LeftReg).addReg(RightReg); + emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1); + break; + } + case CmpInst::ICMP_SLE: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::SLT, TempReg).addReg(RightReg).addReg(LeftReg); + emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1); + break; + } + case CmpInst::FCMP_OEQ: + case CmpInst::FCMP_UNE: + case CmpInst::FCMP_OLT: + case CmpInst::FCMP_OLE: + case CmpInst::FCMP_OGT: + case CmpInst::FCMP_OGE: { + if (UnsupportedFPMode) + return false; + bool IsFloat = Left->getType()->isFloatTy(); + bool IsDouble = Left->getType()->isDoubleTy(); + if (!IsFloat && !IsDouble) + return false; + unsigned Opc, CondMovOpc; + switch (P) { + case CmpInst::FCMP_OEQ: + Opc = IsFloat ? Mips::C_EQ_S : Mips::C_EQ_D32; + CondMovOpc = Mips::MOVT_I; + break; + case CmpInst::FCMP_UNE: + Opc = IsFloat ? Mips::C_EQ_S : Mips::C_EQ_D32; + CondMovOpc = Mips::MOVF_I; + break; + case CmpInst::FCMP_OLT: + Opc = IsFloat ? Mips::C_OLT_S : Mips::C_OLT_D32; + CondMovOpc = Mips::MOVT_I; + break; + case CmpInst::FCMP_OLE: + Opc = IsFloat ? Mips::C_OLE_S : Mips::C_OLE_D32; + CondMovOpc = Mips::MOVT_I; + break; + case CmpInst::FCMP_OGT: + Opc = IsFloat ? Mips::C_ULE_S : Mips::C_ULE_D32; + CondMovOpc = Mips::MOVF_I; + break; + case CmpInst::FCMP_OGE: + Opc = IsFloat ? Mips::C_ULT_S : Mips::C_ULT_D32; + CondMovOpc = Mips::MOVF_I; + break; + default: + llvm_unreachable("Only switching of a subset of CCs."); + } + unsigned RegWithZero = createResultReg(&Mips::GPR32RegClass); + unsigned RegWithOne = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::ADDiu, RegWithZero).addReg(Mips::ZERO).addImm(0); + emitInst(Mips::ADDiu, RegWithOne).addReg(Mips::ZERO).addImm(1); + emitInst(Opc).addReg(LeftReg).addReg(RightReg).addReg( + Mips::FCC0, RegState::ImplicitDefine); + MachineInstrBuilder MI = emitInst(CondMovOpc, ResultReg) + .addReg(RegWithOne) + .addReg(Mips::FCC0) + .addReg(RegWithZero, RegState::Implicit); + MI->tieOperands(0, 3); + break; + } + } + return true; +} +bool MipsFastISel::emitLoad(MVT VT, unsigned &ResultReg, Address &Addr, + unsigned Alignment) { + // + // more cases will be handled here in following patches. + // + unsigned Opc; + switch (VT.SimpleTy) { + case MVT::i32: { + ResultReg = createResultReg(&Mips::GPR32RegClass); + Opc = Mips::LW; + break; + } + case MVT::i16: { + ResultReg = createResultReg(&Mips::GPR32RegClass); + Opc = Mips::LHu; + break; + } + case MVT::i8: { + ResultReg = createResultReg(&Mips::GPR32RegClass); + Opc = Mips::LBu; + break; + } + case MVT::f32: { + if (UnsupportedFPMode) + return false; + ResultReg = createResultReg(&Mips::FGR32RegClass); + Opc = Mips::LWC1; + break; + } + case MVT::f64: { + if (UnsupportedFPMode) + return false; + ResultReg = createResultReg(&Mips::AFGR64RegClass); + Opc = Mips::LDC1; + break; + } + default: + return false; + } + if (Addr.isRegBase()) { + simplifyAddress(Addr); + emitInstLoad(Opc, ResultReg, Addr.getReg(), Addr.getOffset()); + return true; + } + if (Addr.isFIBase()) { + unsigned FI = Addr.getFI(); + unsigned Align = 4; + unsigned Offset = Addr.getOffset(); + MachineFrameInfo &MFI = *MF->getFrameInfo(); + MachineMemOperand *MMO = MF->getMachineMemOperand( + MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOLoad, + MFI.getObjectSize(FI), Align); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) + .addFrameIndex(FI) + .addImm(Offset) + .addMemOperand(MMO); + return true; + } + return false; +} + +bool MipsFastISel::emitStore(MVT VT, unsigned SrcReg, Address &Addr, + unsigned Alignment) { + // + // more cases will be handled here in following patches. + // + unsigned Opc; + switch (VT.SimpleTy) { + case MVT::i8: + Opc = Mips::SB; + break; + case MVT::i16: + Opc = Mips::SH; + break; + case MVT::i32: + Opc = Mips::SW; + break; + case MVT::f32: + if (UnsupportedFPMode) + return false; + Opc = Mips::SWC1; + break; + case MVT::f64: + if (UnsupportedFPMode) + return false; + Opc = Mips::SDC1; + break; + default: + return false; + } + if (Addr.isRegBase()) { + simplifyAddress(Addr); + emitInstStore(Opc, SrcReg, Addr.getReg(), Addr.getOffset()); + return true; + } + if (Addr.isFIBase()) { + unsigned FI = Addr.getFI(); + unsigned Align = 4; + unsigned Offset = Addr.getOffset(); + MachineFrameInfo &MFI = *MF->getFrameInfo(); + MachineMemOperand *MMO = MF->getMachineMemOperand( + MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOLoad, + MFI.getObjectSize(FI), Align); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)) + .addReg(SrcReg) + .addFrameIndex(FI) + .addImm(Offset) + .addMemOperand(MMO); + return true; + } + return false; +} + +bool MipsFastISel::selectLogicalOp(const Instruction *I) { + MVT VT; + if (!isTypeSupported(I->getType(), VT)) + return false; + + unsigned ResultReg; + switch (I->getOpcode()) { + default: + llvm_unreachable("Unexpected instruction."); + case Instruction::And: + ResultReg = emitLogicalOp(ISD::AND, VT, I->getOperand(0), I->getOperand(1)); + break; + case Instruction::Or: + ResultReg = emitLogicalOp(ISD::OR, VT, I->getOperand(0), I->getOperand(1)); + break; + case Instruction::Xor: + ResultReg = emitLogicalOp(ISD::XOR, VT, I->getOperand(0), I->getOperand(1)); + break; + } + + if (!ResultReg) + return false; + + updateValueMap(I, ResultReg); + return true; +} + +bool MipsFastISel::selectLoad(const Instruction *I) { + // Atomic loads need special handling. + if (cast<LoadInst>(I)->isAtomic()) + return false; + + // Verify we have a legal type before going any further. + MVT VT; + if (!isLoadTypeLegal(I->getType(), VT)) + return false; + + // See if we can handle this address. + Address Addr; + if (!computeAddress(I->getOperand(0), Addr)) + return false; + + unsigned ResultReg; + if (!emitLoad(VT, ResultReg, Addr, cast<LoadInst>(I)->getAlignment())) + return false; + updateValueMap(I, ResultReg); + return true; +} + +bool MipsFastISel::selectStore(const Instruction *I) { + Value *Op0 = I->getOperand(0); + unsigned SrcReg = 0; + + // Atomic stores need special handling. + if (cast<StoreInst>(I)->isAtomic()) + return false; + + // Verify we have a legal type before going any further. + MVT VT; + if (!isLoadTypeLegal(I->getOperand(0)->getType(), VT)) + return false; + + // Get the value to be stored into a register. + SrcReg = getRegForValue(Op0); + if (SrcReg == 0) + return false; + + // See if we can handle this address. + Address Addr; + if (!computeAddress(I->getOperand(1), Addr)) + return false; + + if (!emitStore(VT, SrcReg, Addr, cast<StoreInst>(I)->getAlignment())) + return false; + return true; +} + +// +// This can cause a redundant sltiu to be generated. +// FIXME: try and eliminate this in a future patch. +// +bool MipsFastISel::selectBranch(const Instruction *I) { + const BranchInst *BI = cast<BranchInst>(I); + MachineBasicBlock *BrBB = FuncInfo.MBB; + // + // TBB is the basic block for the case where the comparison is true. + // FBB is the basic block for the case where the comparison is false. + // if (cond) goto TBB + // goto FBB + // TBB: + // + MachineBasicBlock *TBB = FuncInfo.MBBMap[BI->getSuccessor(0)]; + MachineBasicBlock *FBB = FuncInfo.MBBMap[BI->getSuccessor(1)]; + BI->getCondition(); + // For now, just try the simplest case where it's fed by a compare. + if (const CmpInst *CI = dyn_cast<CmpInst>(BI->getCondition())) { + unsigned CondReg = createResultReg(&Mips::GPR32RegClass); + if (!emitCmp(CondReg, CI)) + return false; + BuildMI(*BrBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::BGTZ)) + .addReg(CondReg) + .addMBB(TBB); + finishCondBranch(BI->getParent(), TBB, FBB); + return true; + } + return false; +} + +bool MipsFastISel::selectCmp(const Instruction *I) { + const CmpInst *CI = cast<CmpInst>(I); + unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); + if (!emitCmp(ResultReg, CI)) + return false; + updateValueMap(I, ResultReg); + return true; +} + +// Attempt to fast-select a floating-point extend instruction. +bool MipsFastISel::selectFPExt(const Instruction *I) { + if (UnsupportedFPMode) + return false; + Value *Src = I->getOperand(0); + EVT SrcVT = TLI.getValueType(DL, Src->getType(), true); + EVT DestVT = TLI.getValueType(DL, I->getType(), true); + + if (SrcVT != MVT::f32 || DestVT != MVT::f64) + return false; + + unsigned SrcReg = + getRegForValue(Src); // his must be a 32 bit floating point register class + // maybe we should handle this differently + if (!SrcReg) + return false; + + unsigned DestReg = createResultReg(&Mips::AFGR64RegClass); + emitInst(Mips::CVT_D32_S, DestReg).addReg(SrcReg); + updateValueMap(I, DestReg); + return true; +} + +bool MipsFastISel::selectSelect(const Instruction *I) { + assert(isa<SelectInst>(I) && "Expected a select instruction."); + + MVT VT; + if (!isTypeSupported(I->getType(), VT)) + return false; + + unsigned CondMovOpc; + const TargetRegisterClass *RC; + + if (VT.isInteger() && !VT.isVector() && VT.getSizeInBits() <= 32) { + CondMovOpc = Mips::MOVN_I_I; + RC = &Mips::GPR32RegClass; + } else if (VT == MVT::f32) { + CondMovOpc = Mips::MOVN_I_S; + RC = &Mips::FGR32RegClass; + } else if (VT == MVT::f64) { + CondMovOpc = Mips::MOVN_I_D32; + RC = &Mips::AFGR64RegClass; + } else + return false; + + const SelectInst *SI = cast<SelectInst>(I); + const Value *Cond = SI->getCondition(); + unsigned Src1Reg = getRegForValue(SI->getTrueValue()); + unsigned Src2Reg = getRegForValue(SI->getFalseValue()); + unsigned CondReg = getRegForValue(Cond); + + if (!Src1Reg || !Src2Reg || !CondReg) + return false; + + unsigned ZExtCondReg = createResultReg(&Mips::GPR32RegClass); + if (!ZExtCondReg) + return false; + + if (!emitIntExt(MVT::i1, CondReg, MVT::i32, ZExtCondReg, true)) + return false; + + unsigned ResultReg = createResultReg(RC); + unsigned TempReg = createResultReg(RC); + + if (!ResultReg || !TempReg) + return false; + + emitInst(TargetOpcode::COPY, TempReg).addReg(Src2Reg); + emitInst(CondMovOpc, ResultReg) + .addReg(Src1Reg).addReg(ZExtCondReg).addReg(TempReg); + updateValueMap(I, ResultReg); + return true; +} + +// Attempt to fast-select a floating-point truncate instruction. +bool MipsFastISel::selectFPTrunc(const Instruction *I) { + if (UnsupportedFPMode) + return false; + Value *Src = I->getOperand(0); + EVT SrcVT = TLI.getValueType(DL, Src->getType(), true); + EVT DestVT = TLI.getValueType(DL, I->getType(), true); + + if (SrcVT != MVT::f64 || DestVT != MVT::f32) + return false; + + unsigned SrcReg = getRegForValue(Src); + if (!SrcReg) + return false; + + unsigned DestReg = createResultReg(&Mips::FGR32RegClass); + if (!DestReg) + return false; + + emitInst(Mips::CVT_S_D32, DestReg).addReg(SrcReg); + updateValueMap(I, DestReg); + return true; +} + +// Attempt to fast-select a floating-point-to-integer conversion. +bool MipsFastISel::selectFPToInt(const Instruction *I, bool IsSigned) { + if (UnsupportedFPMode) + return false; + MVT DstVT, SrcVT; + if (!IsSigned) + return false; // We don't handle this case yet. There is no native + // instruction for this but it can be synthesized. + Type *DstTy = I->getType(); + if (!isTypeLegal(DstTy, DstVT)) + return false; + + if (DstVT != MVT::i32) + return false; + + Value *Src = I->getOperand(0); + Type *SrcTy = Src->getType(); + if (!isTypeLegal(SrcTy, SrcVT)) + return false; + + if (SrcVT != MVT::f32 && SrcVT != MVT::f64) + return false; + + unsigned SrcReg = getRegForValue(Src); + if (SrcReg == 0) + return false; + + // Determine the opcode for the conversion, which takes place + // entirely within FPRs. + unsigned DestReg = createResultReg(&Mips::GPR32RegClass); + unsigned TempReg = createResultReg(&Mips::FGR32RegClass); + unsigned Opc = (SrcVT == MVT::f32) ? Mips::TRUNC_W_S : Mips::TRUNC_W_D32; + + // Generate the convert. + emitInst(Opc, TempReg).addReg(SrcReg); + emitInst(Mips::MFC1, DestReg).addReg(TempReg); + + updateValueMap(I, DestReg); + return true; +} + +bool MipsFastISel::processCallArgs(CallLoweringInfo &CLI, + SmallVectorImpl<MVT> &OutVTs, + unsigned &NumBytes) { + CallingConv::ID CC = CLI.CallConv; + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CC, false, *FuncInfo.MF, ArgLocs, *Context); + CCInfo.AnalyzeCallOperands(OutVTs, CLI.OutFlags, CCAssignFnForCall(CC)); + // Get a count of how many bytes are to be pushed on the stack. + NumBytes = CCInfo.getNextStackOffset(); + // This is the minimum argument area used for A0-A3. + if (NumBytes < 16) + NumBytes = 16; + + emitInst(Mips::ADJCALLSTACKDOWN).addImm(16); + // Process the args. + MVT firstMVT; + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + const Value *ArgVal = CLI.OutVals[VA.getValNo()]; + MVT ArgVT = OutVTs[VA.getValNo()]; + + if (i == 0) { + firstMVT = ArgVT; + if (ArgVT == MVT::f32) { + VA.convertToReg(Mips::F12); + } else if (ArgVT == MVT::f64) { + VA.convertToReg(Mips::D6); + } + } else if (i == 1) { + if ((firstMVT == MVT::f32) || (firstMVT == MVT::f64)) { + if (ArgVT == MVT::f32) { + VA.convertToReg(Mips::F14); + } else if (ArgVT == MVT::f64) { + VA.convertToReg(Mips::D7); + } + } + } + if (((ArgVT == MVT::i32) || (ArgVT == MVT::f32) || (ArgVT == MVT::i16) || + (ArgVT == MVT::i8)) && + VA.isMemLoc()) { + switch (VA.getLocMemOffset()) { + case 0: + VA.convertToReg(Mips::A0); + break; + case 4: + VA.convertToReg(Mips::A1); + break; + case 8: + VA.convertToReg(Mips::A2); + break; + case 12: + VA.convertToReg(Mips::A3); + break; + default: + break; + } + } + unsigned ArgReg = getRegForValue(ArgVal); + if (!ArgReg) + return false; + + // Handle arg promotion: SExt, ZExt, AExt. + switch (VA.getLocInfo()) { + case CCValAssign::Full: + break; + case CCValAssign::AExt: + case CCValAssign::SExt: { + MVT DestVT = VA.getLocVT(); + MVT SrcVT = ArgVT; + ArgReg = emitIntExt(SrcVT, ArgReg, DestVT, /*isZExt=*/false); + if (!ArgReg) + return false; + break; + } + case CCValAssign::ZExt: { + MVT DestVT = VA.getLocVT(); + MVT SrcVT = ArgVT; + ArgReg = emitIntExt(SrcVT, ArgReg, DestVT, /*isZExt=*/true); + if (!ArgReg) + return false; + break; + } + default: + llvm_unreachable("Unknown arg promotion!"); + } + + // Now copy/store arg to correct locations. + if (VA.isRegLoc() && !VA.needsCustom()) { + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + TII.get(TargetOpcode::COPY), VA.getLocReg()).addReg(ArgReg); + CLI.OutRegs.push_back(VA.getLocReg()); + } else if (VA.needsCustom()) { + llvm_unreachable("Mips does not use custom args."); + return false; + } else { + // + // FIXME: This path will currently return false. It was copied + // from the AArch64 port and should be essentially fine for Mips too. + // The work to finish up this path will be done in a follow-on patch. + // + assert(VA.isMemLoc() && "Assuming store on stack."); + // Don't emit stores for undef values. + if (isa<UndefValue>(ArgVal)) + continue; + + // Need to store on the stack. + // FIXME: This alignment is incorrect but this path is disabled + // for now (will return false). We need to determine the right alignment + // based on the normal alignment for the underlying machine type. + // + unsigned ArgSize = RoundUpToAlignment(ArgVT.getSizeInBits(), 4); + + unsigned BEAlign = 0; + if (ArgSize < 8 && !Subtarget->isLittle()) + BEAlign = 8 - ArgSize; + + Address Addr; + Addr.setKind(Address::RegBase); + Addr.setReg(Mips::SP); + Addr.setOffset(VA.getLocMemOffset() + BEAlign); + + unsigned Alignment = DL.getABITypeAlignment(ArgVal->getType()); + MachineMemOperand *MMO = FuncInfo.MF->getMachineMemOperand( + MachinePointerInfo::getStack(*FuncInfo.MF, Addr.getOffset()), + MachineMemOperand::MOStore, ArgVT.getStoreSize(), Alignment); + (void)(MMO); + // if (!emitStore(ArgVT, ArgReg, Addr, MMO)) + return false; // can't store on the stack yet. + } + } + + return true; +} + +bool MipsFastISel::finishCall(CallLoweringInfo &CLI, MVT RetVT, + unsigned NumBytes) { + CallingConv::ID CC = CLI.CallConv; + emitInst(Mips::ADJCALLSTACKUP).addImm(16); + if (RetVT != MVT::isVoid) { + SmallVector<CCValAssign, 16> RVLocs; + CCState CCInfo(CC, false, *FuncInfo.MF, RVLocs, *Context); + CCInfo.AnalyzeCallResult(RetVT, RetCC_Mips); + + // Only handle a single return value. + if (RVLocs.size() != 1) + return false; + // Copy all of the result registers out of their specified physreg. + MVT CopyVT = RVLocs[0].getValVT(); + // Special handling for extended integers. + if (RetVT == MVT::i1 || RetVT == MVT::i8 || RetVT == MVT::i16) + CopyVT = MVT::i32; + + unsigned ResultReg = createResultReg(TLI.getRegClassFor(CopyVT)); + if (!ResultReg) + return false; + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + TII.get(TargetOpcode::COPY), + ResultReg).addReg(RVLocs[0].getLocReg()); + CLI.InRegs.push_back(RVLocs[0].getLocReg()); + + CLI.ResultReg = ResultReg; + CLI.NumResultRegs = 1; + } + return true; +} + +bool MipsFastISel::fastLowerCall(CallLoweringInfo &CLI) { + if (!TargetSupported) + return false; + + CallingConv::ID CC = CLI.CallConv; + bool IsTailCall = CLI.IsTailCall; + bool IsVarArg = CLI.IsVarArg; + const Value *Callee = CLI.Callee; + MCSymbol *Symbol = CLI.Symbol; + + // Do not handle FastCC. + if (CC == CallingConv::Fast) + return false; + + // Allow SelectionDAG isel to handle tail calls. + if (IsTailCall) + return false; + + // Let SDISel handle vararg functions. + if (IsVarArg) + return false; + + // FIXME: Only handle *simple* calls for now. + MVT RetVT; + if (CLI.RetTy->isVoidTy()) + RetVT = MVT::isVoid; + else if (!isTypeSupported(CLI.RetTy, RetVT)) + return false; + + for (auto Flag : CLI.OutFlags) + if (Flag.isInReg() || Flag.isSRet() || Flag.isNest() || Flag.isByVal()) + return false; + + // Set up the argument vectors. + SmallVector<MVT, 16> OutVTs; + OutVTs.reserve(CLI.OutVals.size()); + + for (auto *Val : CLI.OutVals) { + MVT VT; + if (!isTypeLegal(Val->getType(), VT) && + !(VT == MVT::i1 || VT == MVT::i8 || VT == MVT::i16)) + return false; + + // We don't handle vector parameters yet. + if (VT.isVector() || VT.getSizeInBits() > 64) + return false; + + OutVTs.push_back(VT); + } + + Address Addr; + if (!computeCallAddress(Callee, Addr)) + return false; + + // Handle the arguments now that we've gotten them. + unsigned NumBytes; + if (!processCallArgs(CLI, OutVTs, NumBytes)) + return false; + + if (!Addr.getGlobalValue()) + return false; + + // Issue the call. + unsigned DestAddress; + if (Symbol) + DestAddress = materializeExternalCallSym(Symbol); + else + DestAddress = materializeGV(Addr.getGlobalValue(), MVT::i32); + emitInst(TargetOpcode::COPY, Mips::T9).addReg(DestAddress); + MachineInstrBuilder MIB = + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::JALR), + Mips::RA).addReg(Mips::T9); + + // Add implicit physical register uses to the call. + for (auto Reg : CLI.OutRegs) + MIB.addReg(Reg, RegState::Implicit); + + // Add a register mask with the call-preserved registers. + // Proper defs for return values will be added by setPhysRegsDeadExcept(). + MIB.addRegMask(TRI.getCallPreservedMask(*FuncInfo.MF, CC)); + + CLI.Call = MIB; + + // Finish off the call including any return values. + return finishCall(CLI, RetVT, NumBytes); +} + +bool MipsFastISel::fastLowerIntrinsicCall(const IntrinsicInst *II) { + if (!TargetSupported) + return false; + + switch (II->getIntrinsicID()) { + default: + return false; + case Intrinsic::bswap: { + Type *RetTy = II->getCalledFunction()->getReturnType(); + + MVT VT; + if (!isTypeSupported(RetTy, VT)) + return false; + + unsigned SrcReg = getRegForValue(II->getOperand(0)); + if (SrcReg == 0) + return false; + unsigned DestReg = createResultReg(&Mips::GPR32RegClass); + if (DestReg == 0) + return false; + if (VT == MVT::i16) { + if (Subtarget->hasMips32r2()) { + emitInst(Mips::WSBH, DestReg).addReg(SrcReg); + updateValueMap(II, DestReg); + return true; + } else { + unsigned TempReg[3]; + for (int i = 0; i < 3; i++) { + TempReg[i] = createResultReg(&Mips::GPR32RegClass); + if (TempReg[i] == 0) + return false; + } + emitInst(Mips::SLL, TempReg[0]).addReg(SrcReg).addImm(8); + emitInst(Mips::SRL, TempReg[1]).addReg(SrcReg).addImm(8); + emitInst(Mips::OR, TempReg[2]).addReg(TempReg[0]).addReg(TempReg[1]); + emitInst(Mips::ANDi, DestReg).addReg(TempReg[2]).addImm(0xFFFF); + updateValueMap(II, DestReg); + return true; + } + } else if (VT == MVT::i32) { + if (Subtarget->hasMips32r2()) { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::WSBH, TempReg).addReg(SrcReg); + emitInst(Mips::ROTR, DestReg).addReg(TempReg).addImm(16); + updateValueMap(II, DestReg); + return true; + } else { + unsigned TempReg[8]; + for (int i = 0; i < 8; i++) { + TempReg[i] = createResultReg(&Mips::GPR32RegClass); + if (TempReg[i] == 0) + return false; + } + + emitInst(Mips::SRL, TempReg[0]).addReg(SrcReg).addImm(8); + emitInst(Mips::SRL, TempReg[1]).addReg(SrcReg).addImm(24); + emitInst(Mips::ANDi, TempReg[2]).addReg(TempReg[0]).addImm(0xFF00); + emitInst(Mips::OR, TempReg[3]).addReg(TempReg[1]).addReg(TempReg[2]); + + emitInst(Mips::ANDi, TempReg[4]).addReg(SrcReg).addImm(0xFF00); + emitInst(Mips::SLL, TempReg[5]).addReg(TempReg[4]).addImm(8); + + emitInst(Mips::SLL, TempReg[6]).addReg(SrcReg).addImm(24); + emitInst(Mips::OR, TempReg[7]).addReg(TempReg[3]).addReg(TempReg[5]); + emitInst(Mips::OR, DestReg).addReg(TempReg[6]).addReg(TempReg[7]); + updateValueMap(II, DestReg); + return true; + } + } + return false; + } + case Intrinsic::memcpy: + case Intrinsic::memmove: { + const auto *MTI = cast<MemTransferInst>(II); + // Don't handle volatile. + if (MTI->isVolatile()) + return false; + if (!MTI->getLength()->getType()->isIntegerTy(32)) + return false; + const char *IntrMemName = isa<MemCpyInst>(II) ? "memcpy" : "memmove"; + return lowerCallTo(II, IntrMemName, II->getNumArgOperands() - 2); + } + case Intrinsic::memset: { + const MemSetInst *MSI = cast<MemSetInst>(II); + // Don't handle volatile. + if (MSI->isVolatile()) + return false; + if (!MSI->getLength()->getType()->isIntegerTy(32)) + return false; + return lowerCallTo(II, "memset", II->getNumArgOperands() - 2); + } + } + return false; +} + +bool MipsFastISel::selectRet(const Instruction *I) { + const Function &F = *I->getParent()->getParent(); + const ReturnInst *Ret = cast<ReturnInst>(I); + + if (!FuncInfo.CanLowerReturn) + return false; + + // Build a list of return value registers. + SmallVector<unsigned, 4> RetRegs; + + if (Ret->getNumOperands() > 0) { + CallingConv::ID CC = F.getCallingConv(); + + // Do not handle FastCC. + if (CC == CallingConv::Fast) + return false; + + SmallVector<ISD::OutputArg, 4> Outs; + GetReturnInfo(F.getReturnType(), F.getAttributes(), Outs, TLI, DL); + + // Analyze operands of the call, assigning locations to each operand. + SmallVector<CCValAssign, 16> ValLocs; + MipsCCState CCInfo(CC, F.isVarArg(), *FuncInfo.MF, ValLocs, + I->getContext()); + CCAssignFn *RetCC = RetCC_Mips; + CCInfo.AnalyzeReturn(Outs, RetCC); + + // Only handle a single return value for now. + if (ValLocs.size() != 1) + return false; + + CCValAssign &VA = ValLocs[0]; + const Value *RV = Ret->getOperand(0); + + // Don't bother handling odd stuff for now. + if ((VA.getLocInfo() != CCValAssign::Full) && + (VA.getLocInfo() != CCValAssign::BCvt)) + return false; + + // Only handle register returns for now. + if (!VA.isRegLoc()) + return false; + + unsigned Reg = getRegForValue(RV); + if (Reg == 0) + return false; + + unsigned SrcReg = Reg + VA.getValNo(); + unsigned DestReg = VA.getLocReg(); + // Avoid a cross-class copy. This is very unlikely. + if (!MRI.getRegClass(SrcReg)->contains(DestReg)) + return false; + + EVT RVEVT = TLI.getValueType(DL, RV->getType()); + if (!RVEVT.isSimple()) + return false; + + if (RVEVT.isVector()) + return false; + + MVT RVVT = RVEVT.getSimpleVT(); + if (RVVT == MVT::f128) + return false; + + MVT DestVT = VA.getValVT(); + // Special handling for extended integers. + if (RVVT != DestVT) { + if (RVVT != MVT::i1 && RVVT != MVT::i8 && RVVT != MVT::i16) + return false; + + if (Outs[0].Flags.isZExt() || Outs[0].Flags.isSExt()) { + bool IsZExt = Outs[0].Flags.isZExt(); + SrcReg = emitIntExt(RVVT, SrcReg, DestVT, IsZExt); + if (SrcReg == 0) + return false; + } + } + + // Make the copy. + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + TII.get(TargetOpcode::COPY), DestReg).addReg(SrcReg); + + // Add register to return instruction. + RetRegs.push_back(VA.getLocReg()); + } + MachineInstrBuilder MIB = emitInst(Mips::RetRA); + for (unsigned i = 0, e = RetRegs.size(); i != e; ++i) + MIB.addReg(RetRegs[i], RegState::Implicit); + return true; +} + +bool MipsFastISel::selectTrunc(const Instruction *I) { + // The high bits for a type smaller than the register size are assumed to be + // undefined. + Value *Op = I->getOperand(0); + + EVT SrcVT, DestVT; + SrcVT = TLI.getValueType(DL, Op->getType(), true); + DestVT = TLI.getValueType(DL, I->getType(), true); + + if (SrcVT != MVT::i32 && SrcVT != MVT::i16 && SrcVT != MVT::i8) + return false; + if (DestVT != MVT::i16 && DestVT != MVT::i8 && DestVT != MVT::i1) + return false; + + unsigned SrcReg = getRegForValue(Op); + if (!SrcReg) + return false; + + // Because the high bits are undefined, a truncate doesn't generate + // any code. + updateValueMap(I, SrcReg); + return true; +} +bool MipsFastISel::selectIntExt(const Instruction *I) { + Type *DestTy = I->getType(); + Value *Src = I->getOperand(0); + Type *SrcTy = Src->getType(); + + bool isZExt = isa<ZExtInst>(I); + unsigned SrcReg = getRegForValue(Src); + if (!SrcReg) + return false; + + EVT SrcEVT, DestEVT; + SrcEVT = TLI.getValueType(DL, SrcTy, true); + DestEVT = TLI.getValueType(DL, DestTy, true); + if (!SrcEVT.isSimple()) + return false; + if (!DestEVT.isSimple()) + return false; + + MVT SrcVT = SrcEVT.getSimpleVT(); + MVT DestVT = DestEVT.getSimpleVT(); + unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); + + if (!emitIntExt(SrcVT, SrcReg, DestVT, ResultReg, isZExt)) + return false; + updateValueMap(I, ResultReg); + return true; +} +bool MipsFastISel::emitIntSExt32r1(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg) { + unsigned ShiftAmt; + switch (SrcVT.SimpleTy) { + default: + return false; + case MVT::i8: + ShiftAmt = 24; + break; + case MVT::i16: + ShiftAmt = 16; + break; + } + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::SLL, TempReg).addReg(SrcReg).addImm(ShiftAmt); + emitInst(Mips::SRA, DestReg).addReg(TempReg).addImm(ShiftAmt); + return true; +} + +bool MipsFastISel::emitIntSExt32r2(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg) { + switch (SrcVT.SimpleTy) { + default: + return false; + case MVT::i8: + emitInst(Mips::SEB, DestReg).addReg(SrcReg); + break; + case MVT::i16: + emitInst(Mips::SEH, DestReg).addReg(SrcReg); + break; + } + return true; +} + +bool MipsFastISel::emitIntSExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg) { + if ((DestVT != MVT::i32) && (DestVT != MVT::i16)) + return false; + if (Subtarget->hasMips32r2()) + return emitIntSExt32r2(SrcVT, SrcReg, DestVT, DestReg); + return emitIntSExt32r1(SrcVT, SrcReg, DestVT, DestReg); +} + +bool MipsFastISel::emitIntZExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg) { + int64_t Imm; + + switch (SrcVT.SimpleTy) { + default: + return false; + case MVT::i1: + Imm = 1; + break; + case MVT::i8: + Imm = 0xff; + break; + case MVT::i16: + Imm = 0xffff; + break; + } + + emitInst(Mips::ANDi, DestReg).addReg(SrcReg).addImm(Imm); + return true; +} + +bool MipsFastISel::emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg, bool IsZExt) { + // FastISel does not have plumbing to deal with extensions where the SrcVT or + // DestVT are odd things, so test to make sure that they are both types we can + // handle (i1/i8/i16/i32 for SrcVT and i8/i16/i32/i64 for DestVT), otherwise + // bail out to SelectionDAG. + if (((DestVT != MVT::i8) && (DestVT != MVT::i16) && (DestVT != MVT::i32)) || + ((SrcVT != MVT::i1) && (SrcVT != MVT::i8) && (SrcVT != MVT::i16))) + return false; + if (IsZExt) + return emitIntZExt(SrcVT, SrcReg, DestVT, DestReg); + return emitIntSExt(SrcVT, SrcReg, DestVT, DestReg); +} + +unsigned MipsFastISel::emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, + bool isZExt) { + unsigned DestReg = createResultReg(&Mips::GPR32RegClass); + bool Success = emitIntExt(SrcVT, SrcReg, DestVT, DestReg, isZExt); + return Success ? DestReg : 0; +} + +bool MipsFastISel::selectDivRem(const Instruction *I, unsigned ISDOpcode) { + EVT DestEVT = TLI.getValueType(DL, I->getType(), true); + if (!DestEVT.isSimple()) + return false; + + MVT DestVT = DestEVT.getSimpleVT(); + if (DestVT != MVT::i32) + return false; + + unsigned DivOpc; + switch (ISDOpcode) { + default: + return false; + case ISD::SDIV: + case ISD::SREM: + DivOpc = Mips::SDIV; + break; + case ISD::UDIV: + case ISD::UREM: + DivOpc = Mips::UDIV; + break; + } + + unsigned Src0Reg = getRegForValue(I->getOperand(0)); + unsigned Src1Reg = getRegForValue(I->getOperand(1)); + if (!Src0Reg || !Src1Reg) + return false; + + emitInst(DivOpc).addReg(Src0Reg).addReg(Src1Reg); + emitInst(Mips::TEQ).addReg(Src1Reg).addReg(Mips::ZERO).addImm(7); + + unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); + if (!ResultReg) + return false; + + unsigned MFOpc = (ISDOpcode == ISD::SREM || ISDOpcode == ISD::UREM) + ? Mips::MFHI + : Mips::MFLO; + emitInst(MFOpc, ResultReg); + + updateValueMap(I, ResultReg); + return true; +} + +bool MipsFastISel::selectShift(const Instruction *I) { + MVT RetVT; + + if (!isTypeSupported(I->getType(), RetVT)) + return false; + + unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); + if (!ResultReg) + return false; + + unsigned Opcode = I->getOpcode(); + const Value *Op0 = I->getOperand(0); + unsigned Op0Reg = getRegForValue(Op0); + if (!Op0Reg) + return false; + + // If AShr or LShr, then we need to make sure the operand0 is sign extended. + if (Opcode == Instruction::AShr || Opcode == Instruction::LShr) { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + if (!TempReg) + return false; + + MVT Op0MVT = TLI.getValueType(DL, Op0->getType(), true).getSimpleVT(); + bool IsZExt = Opcode == Instruction::LShr; + if (!emitIntExt(Op0MVT, Op0Reg, MVT::i32, TempReg, IsZExt)) + return false; + + Op0Reg = TempReg; + } + + if (const auto *C = dyn_cast<ConstantInt>(I->getOperand(1))) { + uint64_t ShiftVal = C->getZExtValue(); + + switch (Opcode) { + default: + llvm_unreachable("Unexpected instruction."); + case Instruction::Shl: + Opcode = Mips::SLL; + break; + case Instruction::AShr: + Opcode = Mips::SRA; + break; + case Instruction::LShr: + Opcode = Mips::SRL; + break; + } + + emitInst(Opcode, ResultReg).addReg(Op0Reg).addImm(ShiftVal); + updateValueMap(I, ResultReg); + return true; + } + + unsigned Op1Reg = getRegForValue(I->getOperand(1)); + if (!Op1Reg) + return false; + + switch (Opcode) { + default: + llvm_unreachable("Unexpected instruction."); + case Instruction::Shl: + Opcode = Mips::SLLV; + break; + case Instruction::AShr: + Opcode = Mips::SRAV; + break; + case Instruction::LShr: + Opcode = Mips::SRLV; + break; + } + + emitInst(Opcode, ResultReg).addReg(Op0Reg).addReg(Op1Reg); + updateValueMap(I, ResultReg); + return true; +} + +bool MipsFastISel::fastSelectInstruction(const Instruction *I) { + if (!TargetSupported) + return false; + switch (I->getOpcode()) { + default: + break; + case Instruction::Load: + return selectLoad(I); + case Instruction::Store: + return selectStore(I); + case Instruction::SDiv: + if (!selectBinaryOp(I, ISD::SDIV)) + return selectDivRem(I, ISD::SDIV); + return true; + case Instruction::UDiv: + if (!selectBinaryOp(I, ISD::UDIV)) + return selectDivRem(I, ISD::UDIV); + return true; + case Instruction::SRem: + if (!selectBinaryOp(I, ISD::SREM)) + return selectDivRem(I, ISD::SREM); + return true; + case Instruction::URem: + if (!selectBinaryOp(I, ISD::UREM)) + return selectDivRem(I, ISD::UREM); + return true; + case Instruction::Shl: + case Instruction::LShr: + case Instruction::AShr: + return selectShift(I); + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: + return selectLogicalOp(I); + case Instruction::Br: + return selectBranch(I); + case Instruction::Ret: + return selectRet(I); + case Instruction::Trunc: + return selectTrunc(I); + case Instruction::ZExt: + case Instruction::SExt: + return selectIntExt(I); + case Instruction::FPTrunc: + return selectFPTrunc(I); + case Instruction::FPExt: + return selectFPExt(I); + case Instruction::FPToSI: + return selectFPToInt(I, /*isSigned*/ true); + case Instruction::FPToUI: + return selectFPToInt(I, /*isSigned*/ false); + case Instruction::ICmp: + case Instruction::FCmp: + return selectCmp(I); + case Instruction::Select: + return selectSelect(I); + } + return false; +} + +unsigned MipsFastISel::getRegEnsuringSimpleIntegerWidening(const Value *V, + bool IsUnsigned) { + unsigned VReg = getRegForValue(V); + if (VReg == 0) + return 0; + MVT VMVT = TLI.getValueType(DL, V->getType(), true).getSimpleVT(); + if ((VMVT == MVT::i8) || (VMVT == MVT::i16)) { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + if (!emitIntExt(VMVT, VReg, MVT::i32, TempReg, IsUnsigned)) + return 0; + VReg = TempReg; + } + return VReg; +} + +void MipsFastISel::simplifyAddress(Address &Addr) { + if (!isInt<16>(Addr.getOffset())) { + unsigned TempReg = + materialize32BitInt(Addr.getOffset(), &Mips::GPR32RegClass); + unsigned DestReg = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::ADDu, DestReg).addReg(TempReg).addReg(Addr.getReg()); + Addr.setReg(DestReg); + Addr.setOffset(0); + } +} + +unsigned MipsFastISel::fastEmitInst_rr(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill, + unsigned Op1, bool Op1IsKill) { + // We treat the MUL instruction in a special way because it clobbers + // the HI0 & LO0 registers. The TableGen definition of this instruction can + // mark these registers only as implicitly defined. As a result, the + // register allocator runs out of registers when this instruction is + // followed by another instruction that defines the same registers too. + // We can fix this by explicitly marking those registers as dead. + if (MachineInstOpcode == Mips::MUL) { + unsigned ResultReg = createResultReg(RC); + const MCInstrDesc &II = TII.get(MachineInstOpcode); + Op0 = constrainOperandRegClass(II, Op0, II.getNumDefs()); + Op1 = constrainOperandRegClass(II, Op1, II.getNumDefs() + 1); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II, ResultReg) + .addReg(Op0, getKillRegState(Op0IsKill)) + .addReg(Op1, getKillRegState(Op1IsKill)) + .addReg(Mips::HI0, RegState::ImplicitDefine | RegState::Dead) + .addReg(Mips::LO0, RegState::ImplicitDefine | RegState::Dead); + return ResultReg; + } + + return FastISel::fastEmitInst_rr(MachineInstOpcode, RC, Op0, Op0IsKill, Op1, + Op1IsKill); +} + +namespace llvm { +FastISel *Mips::createFastISel(FunctionLoweringInfo &funcInfo, + const TargetLibraryInfo *libInfo) { + return new MipsFastISel(funcInfo, libInfo); +} +} diff --git a/contrib/llvm/lib/Target/Mips/MipsFrameLowering.cpp b/contrib/llvm/lib/Target/Mips/MipsFrameLowering.cpp new file mode 100644 index 0000000..a74c8ab --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsFrameLowering.cpp @@ -0,0 +1,161 @@ +//===-- MipsFrameLowering.cpp - Mips Frame Information --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips implementation of TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#include "MipsFrameLowering.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsInstrInfo.h" +#include "MipsMachineFunction.h" +#include "MipsTargetMachine.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetOptions.h" + +using namespace llvm; + + +//===----------------------------------------------------------------------===// +// +// Stack Frame Processing methods +// +----------------------------+ +// +// The stack is allocated decrementing the stack pointer on +// the first instruction of a function prologue. Once decremented, +// all stack references are done thought a positive offset +// from the stack/frame pointer, so the stack is considering +// to grow up! Otherwise terrible hacks would have to be made +// to get this stack ABI compliant :) +// +// The stack frame required by the ABI (after call): +// Offset +// +// 0 ---------- +// 4 Args to pass +// . saved $GP (used in PIC) +// . Alloca allocations +// . Local Area +// . CPU "Callee Saved" Registers +// . saved FP +// . saved RA +// . FPU "Callee Saved" Registers +// StackSize ----------- +// +// Offset - offset from sp after stack allocation on function prologue +// +// The sp is the stack pointer subtracted/added from the stack size +// at the Prologue/Epilogue +// +// References to the previous stack (to obtain arguments) are done +// with offsets that exceeds the stack size: (stacksize+(4*(num_arg-1)) +// +// Examples: +// - reference to the actual stack frame +// for any local area var there is smt like : FI >= 0, StackOffset: 4 +// sw REGX, 4(SP) +// +// - reference to previous stack frame +// suppose there's a load to the 5th arguments : FI < 0, StackOffset: 16. +// The emitted instruction will be something like: +// lw REGX, 16+StackSize(SP) +// +// Since the total stack size is unknown on LowerFormalArguments, all +// stack references (ObjectOffset) created to reference the function +// arguments, are negative numbers. This way, on eliminateFrameIndex it's +// possible to detect those references and the offsets are adjusted to +// their real location. +// +//===----------------------------------------------------------------------===// + +const MipsFrameLowering *MipsFrameLowering::create(const MipsSubtarget &ST) { + if (ST.inMips16Mode()) + return llvm::createMips16FrameLowering(ST); + + return llvm::createMipsSEFrameLowering(ST); +} + +// hasFP - Return true if the specified function should have a dedicated frame +// pointer register. This is true if the function has variable sized allocas, +// if it needs dynamic stack realignment, if frame pointer elimination is +// disabled, or if the frame address is taken. +bool MipsFrameLowering::hasFP(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + const TargetRegisterInfo *TRI = STI.getRegisterInfo(); + + return MF.getTarget().Options.DisableFramePointerElim(MF) || + MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken() || + TRI->needsStackRealignment(MF); +} + +bool MipsFrameLowering::hasBP(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + const TargetRegisterInfo *TRI = STI.getRegisterInfo(); + + return MFI->hasVarSizedObjects() && TRI->needsStackRealignment(MF); +} + +uint64_t MipsFrameLowering::estimateStackSize(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); + + int64_t Offset = 0; + + // Iterate over fixed sized objects. + for (int I = MFI->getObjectIndexBegin(); I != 0; ++I) + Offset = std::max(Offset, -MFI->getObjectOffset(I)); + + // Conservatively assume all callee-saved registers will be saved. + for (const MCPhysReg *R = TRI.getCalleeSavedRegs(&MF); *R; ++R) { + unsigned Size = TRI.getMinimalPhysRegClass(*R)->getSize(); + Offset = RoundUpToAlignment(Offset + Size, Size); + } + + unsigned MaxAlign = MFI->getMaxAlignment(); + + // Check that MaxAlign is not zero if there is a stack object that is not a + // callee-saved spill. + assert(!MFI->getObjectIndexEnd() || MaxAlign); + + // Iterate over other objects. + for (unsigned I = 0, E = MFI->getObjectIndexEnd(); I != E; ++I) + Offset = RoundUpToAlignment(Offset + MFI->getObjectSize(I), MaxAlign); + + // Call frame. + if (MFI->adjustsStack() && hasReservedCallFrame(MF)) + Offset = RoundUpToAlignment(Offset + MFI->getMaxCallFrameSize(), + std::max(MaxAlign, getStackAlignment())); + + return RoundUpToAlignment(Offset, getStackAlignment()); +} + +// Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions +void MipsFrameLowering:: +eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + unsigned SP = STI.getABI().IsN64() ? Mips::SP_64 : Mips::SP; + + if (!hasReservedCallFrame(MF)) { + int64_t Amount = I->getOperand(0).getImm(); + if (I->getOpcode() == Mips::ADJCALLSTACKDOWN) + Amount = -Amount; + + STI.getInstrInfo()->adjustStackPtr(SP, Amount, MBB, I); + } + + MBB.erase(I); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsFrameLowering.h b/contrib/llvm/lib/Target/Mips/MipsFrameLowering.h new file mode 100644 index 0000000..5eabd58 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsFrameLowering.h @@ -0,0 +1,54 @@ +//===-- MipsFrameLowering.h - Define frame lowering for Mips ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSFRAMELOWERING_H +#define LLVM_LIB_TARGET_MIPS_MIPSFRAMELOWERING_H + +#include "Mips.h" +#include "llvm/Target/TargetFrameLowering.h" + +namespace llvm { + class MipsSubtarget; + +class MipsFrameLowering : public TargetFrameLowering { +protected: + const MipsSubtarget &STI; + +public: + explicit MipsFrameLowering(const MipsSubtarget &sti, unsigned Alignment) + : TargetFrameLowering(StackGrowsDown, Alignment, 0, Alignment), STI(sti) {} + + static const MipsFrameLowering *create(const MipsSubtarget &ST); + + bool hasFP(const MachineFunction &MF) const override; + + bool hasBP(const MachineFunction &MF) const; + + bool isFPCloseToIncomingSP() const override { return false; } + + void + eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const override; + +protected: + uint64_t estimateStackSize(const MachineFunction &MF) const; +}; + +/// Create MipsFrameLowering objects. +const MipsFrameLowering *createMips16FrameLowering(const MipsSubtarget &ST); +const MipsFrameLowering *createMipsSEFrameLowering(const MipsSubtarget &ST); + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp new file mode 100644 index 0000000..0650239 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp @@ -0,0 +1,249 @@ +//===-- MipsISelDAGToDAG.cpp - A Dag to Dag Inst Selector for Mips --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an instruction selector for the MIPS target. +// +//===----------------------------------------------------------------------===// + +#include "MipsISelDAGToDAG.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/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +using namespace llvm; + +#define DEBUG_TYPE "mips-isel" + +//===----------------------------------------------------------------------===// +// Instruction Selector Implementation +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MipsDAGToDAGISel - MIPS specific code to select MIPS machine +// instructions for SelectionDAG operations. +//===----------------------------------------------------------------------===// + +bool MipsDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &static_cast<const MipsSubtarget &>(MF.getSubtarget()); + bool Ret = SelectionDAGISel::runOnMachineFunction(MF); + + processFunctionAfterISel(MF); + + return Ret; +} + +/// getGlobalBaseReg - Output the instructions required to put the +/// GOT address into a register. +SDNode *MipsDAGToDAGISel::getGlobalBaseReg() { + unsigned GlobalBaseReg = MF->getInfo<MipsFunctionInfo>()->getGlobalBaseReg(); + return CurDAG->getRegister(GlobalBaseReg, getTargetLowering()->getPointerTy( + CurDAG->getDataLayout())) + .getNode(); +} + +/// ComplexPattern used on MipsInstrInfo +/// Used on Mips Load/Store instructions +bool MipsDAGToDAGISel::selectAddrRegImm(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectAddrRegReg(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectAddrDefault(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectIntAddr(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectIntAddrMM(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectIntAddrLSL2MM(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + llvm_unreachable("Unimplemented function."); + 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."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm, + unsigned MinSizeInBits) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimm1(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimm2(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimm3(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimm4(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimm5(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimm6(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimm8(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatSimm5(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimmPow2(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimmInvPow2(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatMaskL(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatMaskR(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +/// Select instructions not customized! Used for +/// expanded, promoted and normal instructions +SDNode* MipsDAGToDAGISel::Select(SDNode *Node) { + unsigned Opcode = Node->getOpcode(); + + // Dump information about the Node being selected + DEBUG(errs() << "Selecting: "; Node->dump(CurDAG); errs() << "\n"); + + // If we have a custom node, we already have selected! + if (Node->isMachineOpcode()) { + DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); + Node->setNodeId(-1); + return nullptr; + } + + // See if subclasses can handle this node. + std::pair<bool, SDNode*> Ret = selectNode(Node); + + if (Ret.first) + return Ret.second; + + switch(Opcode) { + default: break; + + // Get target GOT address. + case ISD::GLOBAL_OFFSET_TABLE: + return getGlobalBaseReg(); + +#ifndef NDEBUG + case ISD::LOAD: + case ISD::STORE: + assert((Subtarget->systemSupportsUnalignedAccess() || + cast<MemSDNode>(Node)->getMemoryVT().getSizeInBits() / 8 <= + cast<MemSDNode>(Node)->getAlignment()) && + "Unexpected unaligned loads/stores."); + break; +#endif + } + + // Select the default instruction + SDNode *ResNode = SelectCode(Node); + + DEBUG(errs() << "=> "); + if (ResNode == nullptr || ResNode == Node) + DEBUG(Node->dump(CurDAG)); + else + DEBUG(ResNode->dump(CurDAG)); + DEBUG(errs() << "\n"); + return ResNode; +} + +bool MipsDAGToDAGISel:: +SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, + std::vector<SDValue> &OutOps) { + // All memory constraints can at least accept raw pointers. + switch(ConstraintID) { + default: + llvm_unreachable("Unexpected asm memory constraint"); + case InlineAsm::Constraint_i: + case InlineAsm::Constraint_m: + case InlineAsm::Constraint_R: + case InlineAsm::Constraint_ZC: + OutOps.push_back(Op); + return false; + } + return true; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.h b/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.h new file mode 100644 index 0000000..1426d0f --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.h @@ -0,0 +1,134 @@ +//===---- MipsISelDAGToDAG.h - A Dag to Dag Inst Selector for Mips --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an instruction selector for the MIPS target. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSISELDAGTODAG_H +#define LLVM_LIB_TARGET_MIPS_MIPSISELDAGTODAG_H + +#include "Mips.h" +#include "MipsSubtarget.h" +#include "MipsTargetMachine.h" +#include "llvm/CodeGen/SelectionDAGISel.h" + +//===----------------------------------------------------------------------===// +// Instruction Selector Implementation +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MipsDAGToDAGISel - MIPS specific code to select MIPS machine +// instructions for SelectionDAG operations. +//===----------------------------------------------------------------------===// +namespace llvm { + +class MipsDAGToDAGISel : public SelectionDAGISel { +public: + explicit MipsDAGToDAGISel(MipsTargetMachine &TM) + : SelectionDAGISel(TM), Subtarget(nullptr) {} + + // Pass Name + const char *getPassName() const override { + return "MIPS DAG->DAG Pattern Instruction Selection"; + } + + bool runOnMachineFunction(MachineFunction &MF) override; + +protected: + SDNode *getGlobalBaseReg(); + + /// Keep a pointer to the MipsSubtarget around so that we can make the right + /// decision when generating code for different targets. + const MipsSubtarget *Subtarget; + +private: + // Include the pieces autogenerated from the target description. + #include "MipsGenDAGISel.inc" + + // Complex Pattern. + /// (reg + imm). + virtual bool selectAddrRegImm(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + // Complex Pattern. + /// (reg + reg). + virtual bool selectAddrRegReg(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + /// Fall back on this function if all else fails. + virtual bool selectAddrDefault(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + /// Match integer address pattern. + virtual bool selectIntAddr(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + virtual bool selectIntAddrMM(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + virtual bool selectIntAddrLSL2MM(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); + + /// \brief Select constant vector splats. + virtual bool selectVSplat(SDNode *N, APInt &Imm, + unsigned MinSizeInBits) const; + /// \brief Select constant vector splats whose value fits in a uimm1. + virtual bool selectVSplatUimm1(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm2. + virtual bool selectVSplatUimm2(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm3. + virtual bool selectVSplatUimm3(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm4. + virtual bool selectVSplatUimm4(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm5. + virtual bool selectVSplatUimm5(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm6. + virtual bool selectVSplatUimm6(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm8. + virtual bool selectVSplatUimm8(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a simm5. + virtual bool selectVSplatSimm5(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value is a power of 2. + virtual bool selectVSplatUimmPow2(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value is the inverse of a + /// power of 2. + virtual bool selectVSplatUimmInvPow2(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value is a run of set bits + /// ending at the most significant bit + virtual bool selectVSplatMaskL(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value is a run of set bits + /// starting at bit zero. + virtual bool selectVSplatMaskR(SDValue N, SDValue &Imm) const; + + SDNode *Select(SDNode *N) override; + + virtual std::pair<bool, SDNode*> selectNode(SDNode *Node) = 0; + + // getImm - Return a target constant with the specified value. + inline SDValue getImm(const SDNode *Node, uint64_t Imm) { + return CurDAG->getTargetConstant(Imm, SDLoc(Node), Node->getValueType(0)); + } + + virtual void processFunctionAfterISel(MachineFunction &MF) = 0; + + bool SelectInlineAsmMemoryOperand(const SDValue &Op, + unsigned ConstraintID, + std::vector<SDValue> &OutOps) override; +}; +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp b/contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp new file mode 100644 index 0000000..6756c17 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp @@ -0,0 +1,3977 @@ +//===-- MipsISelLowering.cpp - Mips DAG Lowering Implementation -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interfaces that Mips uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// +#include "MipsISelLowering.h" +#include "InstPrinter/MipsInstPrinter.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsCCState.h" +#include "MipsMachineFunction.h" +#include "MipsSubtarget.h" +#include "MipsTargetMachine.h" +#include "MipsTargetObjectFile.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/FunctionLoweringInfo.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/IR/CallingConv.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include <cctype> + +using namespace llvm; + +#define DEBUG_TYPE "mips-lower" + +STATISTIC(NumTailCalls, "Number of tail calls"); + +static cl::opt<bool> +LargeGOT("mxgot", cl::Hidden, + cl::desc("MIPS: Enable GOT larger than 64k."), cl::init(false)); + +static cl::opt<bool> +NoZeroDivCheck("mno-check-zero-division", cl::Hidden, + cl::desc("MIPS: Don't trap on integer division by zero."), + cl::init(false)); + +static const MCPhysReg Mips64DPRegs[8] = { + Mips::D12_64, Mips::D13_64, Mips::D14_64, Mips::D15_64, + Mips::D16_64, Mips::D17_64, Mips::D18_64, Mips::D19_64 +}; + +// If I is a shifted mask, set the size (Size) and the first bit of the +// mask (Pos), and return true. +// For example, if I is 0x003ff800, (Pos, Size) = (11, 11). +static bool isShiftedMask(uint64_t I, uint64_t &Pos, uint64_t &Size) { + if (!isShiftedMask_64(I)) + return false; + + Size = countPopulation(I); + Pos = countTrailingZeros(I); + return true; +} + +SDValue MipsTargetLowering::getGlobalReg(SelectionDAG &DAG, EVT Ty) const { + MipsFunctionInfo *FI = DAG.getMachineFunction().getInfo<MipsFunctionInfo>(); + return DAG.getRegister(FI->getGlobalBaseReg(), Ty); +} + +SDValue MipsTargetLowering::getTargetNode(GlobalAddressSDNode *N, EVT Ty, + SelectionDAG &DAG, + unsigned Flag) const { + return DAG.getTargetGlobalAddress(N->getGlobal(), SDLoc(N), Ty, 0, Flag); +} + +SDValue MipsTargetLowering::getTargetNode(ExternalSymbolSDNode *N, EVT Ty, + SelectionDAG &DAG, + unsigned Flag) const { + return DAG.getTargetExternalSymbol(N->getSymbol(), Ty, Flag); +} + +SDValue MipsTargetLowering::getTargetNode(BlockAddressSDNode *N, EVT Ty, + SelectionDAG &DAG, + unsigned Flag) const { + return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, 0, Flag); +} + +SDValue MipsTargetLowering::getTargetNode(JumpTableSDNode *N, EVT Ty, + SelectionDAG &DAG, + unsigned Flag) const { + return DAG.getTargetJumpTable(N->getIndex(), Ty, Flag); +} + +SDValue MipsTargetLowering::getTargetNode(ConstantPoolSDNode *N, EVT Ty, + SelectionDAG &DAG, + unsigned Flag) const { + return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlignment(), + N->getOffset(), Flag); +} + +const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const { + switch ((MipsISD::NodeType)Opcode) { + case MipsISD::FIRST_NUMBER: break; + case MipsISD::JmpLink: return "MipsISD::JmpLink"; + case MipsISD::TailCall: return "MipsISD::TailCall"; + case MipsISD::Hi: return "MipsISD::Hi"; + case MipsISD::Lo: return "MipsISD::Lo"; + case MipsISD::GPRel: return "MipsISD::GPRel"; + case MipsISD::ThreadPointer: return "MipsISD::ThreadPointer"; + case MipsISD::Ret: return "MipsISD::Ret"; + case MipsISD::ERet: return "MipsISD::ERet"; + case MipsISD::EH_RETURN: return "MipsISD::EH_RETURN"; + case MipsISD::FPBrcond: return "MipsISD::FPBrcond"; + case MipsISD::FPCmp: return "MipsISD::FPCmp"; + case MipsISD::CMovFP_T: return "MipsISD::CMovFP_T"; + case MipsISD::CMovFP_F: return "MipsISD::CMovFP_F"; + case MipsISD::TruncIntFP: return "MipsISD::TruncIntFP"; + case MipsISD::MFHI: return "MipsISD::MFHI"; + case MipsISD::MFLO: return "MipsISD::MFLO"; + case MipsISD::MTLOHI: return "MipsISD::MTLOHI"; + case MipsISD::Mult: return "MipsISD::Mult"; + case MipsISD::Multu: return "MipsISD::Multu"; + case MipsISD::MAdd: return "MipsISD::MAdd"; + case MipsISD::MAddu: return "MipsISD::MAddu"; + case MipsISD::MSub: return "MipsISD::MSub"; + case MipsISD::MSubu: return "MipsISD::MSubu"; + case MipsISD::DivRem: return "MipsISD::DivRem"; + case MipsISD::DivRemU: return "MipsISD::DivRemU"; + case MipsISD::DivRem16: return "MipsISD::DivRem16"; + case MipsISD::DivRemU16: return "MipsISD::DivRemU16"; + case MipsISD::BuildPairF64: return "MipsISD::BuildPairF64"; + case MipsISD::ExtractElementF64: return "MipsISD::ExtractElementF64"; + case MipsISD::Wrapper: return "MipsISD::Wrapper"; + case MipsISD::DynAlloc: return "MipsISD::DynAlloc"; + case MipsISD::Sync: return "MipsISD::Sync"; + case MipsISD::Ext: return "MipsISD::Ext"; + case MipsISD::Ins: return "MipsISD::Ins"; + case MipsISD::LWL: return "MipsISD::LWL"; + case MipsISD::LWR: return "MipsISD::LWR"; + case MipsISD::SWL: return "MipsISD::SWL"; + case MipsISD::SWR: return "MipsISD::SWR"; + case MipsISD::LDL: return "MipsISD::LDL"; + case MipsISD::LDR: return "MipsISD::LDR"; + case MipsISD::SDL: return "MipsISD::SDL"; + case MipsISD::SDR: return "MipsISD::SDR"; + case MipsISD::EXTP: return "MipsISD::EXTP"; + case MipsISD::EXTPDP: return "MipsISD::EXTPDP"; + case MipsISD::EXTR_S_H: return "MipsISD::EXTR_S_H"; + case MipsISD::EXTR_W: return "MipsISD::EXTR_W"; + case MipsISD::EXTR_R_W: return "MipsISD::EXTR_R_W"; + case MipsISD::EXTR_RS_W: return "MipsISD::EXTR_RS_W"; + case MipsISD::SHILO: return "MipsISD::SHILO"; + case MipsISD::MTHLIP: return "MipsISD::MTHLIP"; + case MipsISD::MULSAQ_S_W_PH: return "MipsISD::MULSAQ_S_W_PH"; + case MipsISD::MAQ_S_W_PHL: return "MipsISD::MAQ_S_W_PHL"; + case MipsISD::MAQ_S_W_PHR: return "MipsISD::MAQ_S_W_PHR"; + case MipsISD::MAQ_SA_W_PHL: return "MipsISD::MAQ_SA_W_PHL"; + case MipsISD::MAQ_SA_W_PHR: return "MipsISD::MAQ_SA_W_PHR"; + case MipsISD::DPAU_H_QBL: return "MipsISD::DPAU_H_QBL"; + case MipsISD::DPAU_H_QBR: return "MipsISD::DPAU_H_QBR"; + case MipsISD::DPSU_H_QBL: return "MipsISD::DPSU_H_QBL"; + case MipsISD::DPSU_H_QBR: return "MipsISD::DPSU_H_QBR"; + case MipsISD::DPAQ_S_W_PH: return "MipsISD::DPAQ_S_W_PH"; + case MipsISD::DPSQ_S_W_PH: return "MipsISD::DPSQ_S_W_PH"; + case MipsISD::DPAQ_SA_L_W: return "MipsISD::DPAQ_SA_L_W"; + case MipsISD::DPSQ_SA_L_W: return "MipsISD::DPSQ_SA_L_W"; + case MipsISD::DPA_W_PH: return "MipsISD::DPA_W_PH"; + case MipsISD::DPS_W_PH: return "MipsISD::DPS_W_PH"; + case MipsISD::DPAQX_S_W_PH: return "MipsISD::DPAQX_S_W_PH"; + case MipsISD::DPAQX_SA_W_PH: return "MipsISD::DPAQX_SA_W_PH"; + case MipsISD::DPAX_W_PH: return "MipsISD::DPAX_W_PH"; + case MipsISD::DPSX_W_PH: return "MipsISD::DPSX_W_PH"; + case MipsISD::DPSQX_S_W_PH: return "MipsISD::DPSQX_S_W_PH"; + case MipsISD::DPSQX_SA_W_PH: return "MipsISD::DPSQX_SA_W_PH"; + case MipsISD::MULSA_W_PH: return "MipsISD::MULSA_W_PH"; + case MipsISD::MULT: return "MipsISD::MULT"; + case MipsISD::MULTU: return "MipsISD::MULTU"; + case MipsISD::MADD_DSP: return "MipsISD::MADD_DSP"; + case MipsISD::MADDU_DSP: return "MipsISD::MADDU_DSP"; + case MipsISD::MSUB_DSP: return "MipsISD::MSUB_DSP"; + case MipsISD::MSUBU_DSP: return "MipsISD::MSUBU_DSP"; + case MipsISD::SHLL_DSP: return "MipsISD::SHLL_DSP"; + case MipsISD::SHRA_DSP: return "MipsISD::SHRA_DSP"; + case MipsISD::SHRL_DSP: return "MipsISD::SHRL_DSP"; + case MipsISD::SETCC_DSP: return "MipsISD::SETCC_DSP"; + case MipsISD::SELECT_CC_DSP: return "MipsISD::SELECT_CC_DSP"; + case MipsISD::VALL_ZERO: return "MipsISD::VALL_ZERO"; + case MipsISD::VANY_ZERO: return "MipsISD::VANY_ZERO"; + case MipsISD::VALL_NONZERO: return "MipsISD::VALL_NONZERO"; + case MipsISD::VANY_NONZERO: return "MipsISD::VANY_NONZERO"; + case MipsISD::VCEQ: return "MipsISD::VCEQ"; + case MipsISD::VCLE_S: return "MipsISD::VCLE_S"; + case MipsISD::VCLE_U: return "MipsISD::VCLE_U"; + case MipsISD::VCLT_S: return "MipsISD::VCLT_S"; + case MipsISD::VCLT_U: return "MipsISD::VCLT_U"; + case MipsISD::VSMAX: return "MipsISD::VSMAX"; + case MipsISD::VSMIN: return "MipsISD::VSMIN"; + case MipsISD::VUMAX: return "MipsISD::VUMAX"; + case MipsISD::VUMIN: return "MipsISD::VUMIN"; + case MipsISD::VEXTRACT_SEXT_ELT: return "MipsISD::VEXTRACT_SEXT_ELT"; + case MipsISD::VEXTRACT_ZEXT_ELT: return "MipsISD::VEXTRACT_ZEXT_ELT"; + case MipsISD::VNOR: return "MipsISD::VNOR"; + case MipsISD::VSHF: return "MipsISD::VSHF"; + case MipsISD::SHF: return "MipsISD::SHF"; + case MipsISD::ILVEV: return "MipsISD::ILVEV"; + case MipsISD::ILVOD: return "MipsISD::ILVOD"; + case MipsISD::ILVL: return "MipsISD::ILVL"; + case MipsISD::ILVR: return "MipsISD::ILVR"; + case MipsISD::PCKEV: return "MipsISD::PCKEV"; + case MipsISD::PCKOD: return "MipsISD::PCKOD"; + case MipsISD::INSVE: return "MipsISD::INSVE"; + } + return nullptr; +} + +MipsTargetLowering::MipsTargetLowering(const MipsTargetMachine &TM, + const MipsSubtarget &STI) + : TargetLowering(TM), Subtarget(STI), ABI(TM.getABI()) { + // Mips does not have i1 type, so use i32 for + // setcc operations results (slt, sgt, ...). + setBooleanContents(ZeroOrOneBooleanContent); + setBooleanVectorContents(ZeroOrNegativeOneBooleanContent); + // The cmp.cond.fmt instruction in MIPS32r6/MIPS64r6 uses 0 and -1 like MSA + // does. Integer booleans still use 0 and 1. + if (Subtarget.hasMips32r6()) + setBooleanContents(ZeroOrOneBooleanContent, + ZeroOrNegativeOneBooleanContent); + + // Load extented operations for i1 types must be promoted + for (MVT VT : MVT::integer_valuetypes()) { + setLoadExtAction(ISD::EXTLOAD, VT, MVT::i1, Promote); + setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i1, Promote); + setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote); + } + + // MIPS doesn't have extending float->double load/store. Set LoadExtAction + // for f32, f16 + for (MVT VT : MVT::fp_valuetypes()) { + setLoadExtAction(ISD::EXTLOAD, VT, MVT::f32, Expand); + setLoadExtAction(ISD::EXTLOAD, VT, MVT::f16, Expand); + } + + // Set LoadExtAction for f16 vectors to Expand + for (MVT VT : MVT::fp_vector_valuetypes()) { + MVT F16VT = MVT::getVectorVT(MVT::f16, VT.getVectorNumElements()); + if (F16VT.isValid()) + setLoadExtAction(ISD::EXTLOAD, VT, F16VT, Expand); + } + + setTruncStoreAction(MVT::f32, MVT::f16, Expand); + setTruncStoreAction(MVT::f64, MVT::f16, Expand); + + setTruncStoreAction(MVT::f64, MVT::f32, Expand); + + // Used by legalize types to correctly generate the setcc result. + // Without this, every float setcc comes with a AND/OR with the result, + // we don't want this, since the fpcmp result goes to a flag register, + // which is used implicitly by brcond and select operations. + AddPromotedToType(ISD::SETCC, MVT::i1, MVT::i32); + + // Mips Custom Operations + setOperationAction(ISD::BR_JT, MVT::Other, Custom); + setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); + setOperationAction(ISD::BlockAddress, MVT::i32, Custom); + setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom); + setOperationAction(ISD::JumpTable, MVT::i32, Custom); + setOperationAction(ISD::ConstantPool, MVT::i32, Custom); + setOperationAction(ISD::SELECT, MVT::f32, Custom); + setOperationAction(ISD::SELECT, MVT::f64, Custom); + setOperationAction(ISD::SELECT, MVT::i32, Custom); + setOperationAction(ISD::SELECT_CC, MVT::f32, Custom); + setOperationAction(ISD::SELECT_CC, MVT::f64, Custom); + setOperationAction(ISD::SETCC, MVT::f32, Custom); + setOperationAction(ISD::SETCC, MVT::f64, Custom); + setOperationAction(ISD::BRCOND, MVT::Other, Custom); + setOperationAction(ISD::FCOPYSIGN, MVT::f32, Custom); + setOperationAction(ISD::FCOPYSIGN, MVT::f64, Custom); + setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); + + if (Subtarget.isGP64bit()) { + setOperationAction(ISD::GlobalAddress, MVT::i64, Custom); + setOperationAction(ISD::BlockAddress, MVT::i64, Custom); + setOperationAction(ISD::GlobalTLSAddress, MVT::i64, Custom); + setOperationAction(ISD::JumpTable, MVT::i64, Custom); + setOperationAction(ISD::ConstantPool, MVT::i64, Custom); + setOperationAction(ISD::SELECT, MVT::i64, Custom); + setOperationAction(ISD::LOAD, MVT::i64, Custom); + setOperationAction(ISD::STORE, MVT::i64, Custom); + setOperationAction(ISD::FP_TO_SINT, MVT::i64, Custom); + setOperationAction(ISD::SHL_PARTS, MVT::i64, Custom); + setOperationAction(ISD::SRA_PARTS, MVT::i64, Custom); + setOperationAction(ISD::SRL_PARTS, MVT::i64, Custom); + } + + if (!Subtarget.isGP64bit()) { + setOperationAction(ISD::SHL_PARTS, MVT::i32, Custom); + setOperationAction(ISD::SRA_PARTS, MVT::i32, Custom); + setOperationAction(ISD::SRL_PARTS, MVT::i32, Custom); + } + + setOperationAction(ISD::ADD, MVT::i32, Custom); + if (Subtarget.isGP64bit()) + setOperationAction(ISD::ADD, MVT::i64, Custom); + + setOperationAction(ISD::SDIV, MVT::i32, Expand); + setOperationAction(ISD::SREM, MVT::i32, Expand); + setOperationAction(ISD::UDIV, MVT::i32, Expand); + setOperationAction(ISD::UREM, MVT::i32, Expand); + setOperationAction(ISD::SDIV, MVT::i64, Expand); + setOperationAction(ISD::SREM, MVT::i64, Expand); + setOperationAction(ISD::UDIV, MVT::i64, Expand); + setOperationAction(ISD::UREM, MVT::i64, Expand); + + // Operations not directly supported by Mips. + setOperationAction(ISD::BR_CC, MVT::f32, Expand); + setOperationAction(ISD::BR_CC, MVT::f64, Expand); + setOperationAction(ISD::BR_CC, MVT::i32, Expand); + setOperationAction(ISD::BR_CC, MVT::i64, Expand); + setOperationAction(ISD::SELECT_CC, MVT::i32, Expand); + setOperationAction(ISD::SELECT_CC, MVT::i64, Expand); + setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand); + setOperationAction(ISD::UINT_TO_FP, MVT::i64, Expand); + setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand); + setOperationAction(ISD::FP_TO_UINT, MVT::i64, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + 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); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i64, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i64, Expand); + setOperationAction(ISD::ROTL, MVT::i32, Expand); + setOperationAction(ISD::ROTL, MVT::i64, Expand); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Expand); + + if (!Subtarget.hasMips32r2()) + setOperationAction(ISD::ROTR, MVT::i32, Expand); + + if (!Subtarget.hasMips64r2()) + setOperationAction(ISD::ROTR, MVT::i64, Expand); + + setOperationAction(ISD::FSIN, MVT::f32, Expand); + setOperationAction(ISD::FSIN, MVT::f64, Expand); + setOperationAction(ISD::FCOS, MVT::f32, Expand); + setOperationAction(ISD::FCOS, MVT::f64, Expand); + setOperationAction(ISD::FSINCOS, MVT::f32, Expand); + setOperationAction(ISD::FSINCOS, MVT::f64, Expand); + setOperationAction(ISD::FPOWI, MVT::f32, Expand); + setOperationAction(ISD::FPOW, MVT::f32, Expand); + setOperationAction(ISD::FPOW, MVT::f64, Expand); + setOperationAction(ISD::FLOG, MVT::f32, Expand); + setOperationAction(ISD::FLOG2, MVT::f32, Expand); + setOperationAction(ISD::FLOG10, MVT::f32, Expand); + setOperationAction(ISD::FEXP, MVT::f32, Expand); + setOperationAction(ISD::FMA, MVT::f32, Expand); + setOperationAction(ISD::FMA, MVT::f64, Expand); + setOperationAction(ISD::FREM, MVT::f32, Expand); + setOperationAction(ISD::FREM, MVT::f64, Expand); + + // Lower f16 conversion operations into library calls + setOperationAction(ISD::FP16_TO_FP, MVT::f32, Expand); + setOperationAction(ISD::FP_TO_FP16, MVT::f32, Expand); + setOperationAction(ISD::FP16_TO_FP, MVT::f64, Expand); + setOperationAction(ISD::FP_TO_FP16, MVT::f64, Expand); + + setOperationAction(ISD::EH_RETURN, MVT::Other, Custom); + + setOperationAction(ISD::VASTART, MVT::Other, Custom); + setOperationAction(ISD::VAARG, MVT::Other, Custom); + setOperationAction(ISD::VACOPY, MVT::Other, Expand); + setOperationAction(ISD::VAEND, MVT::Other, Expand); + + // Use the default for now + setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); + setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); + + if (!Subtarget.isGP64bit()) { + setOperationAction(ISD::ATOMIC_LOAD, MVT::i64, Expand); + setOperationAction(ISD::ATOMIC_STORE, MVT::i64, Expand); + } + + setInsertFencesForAtomic(true); + + if (!Subtarget.hasMips32r2()) { + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); + } + + // MIPS16 lacks MIPS32's clz and clo instructions. + if (!Subtarget.hasMips32() || Subtarget.inMips16Mode()) + setOperationAction(ISD::CTLZ, MVT::i32, Expand); + if (!Subtarget.hasMips64()) + setOperationAction(ISD::CTLZ, MVT::i64, Expand); + + if (!Subtarget.hasMips32r2()) + setOperationAction(ISD::BSWAP, MVT::i32, Expand); + if (!Subtarget.hasMips64r2()) + setOperationAction(ISD::BSWAP, MVT::i64, Expand); + + if (Subtarget.isGP64bit()) { + setLoadExtAction(ISD::SEXTLOAD, MVT::i64, MVT::i32, Custom); + setLoadExtAction(ISD::ZEXTLOAD, MVT::i64, MVT::i32, Custom); + setLoadExtAction(ISD::EXTLOAD, MVT::i64, MVT::i32, Custom); + setTruncStoreAction(MVT::i64, MVT::i32, Custom); + } + + setOperationAction(ISD::TRAP, MVT::Other, Legal); + + setTargetDAGCombine(ISD::SDIVREM); + setTargetDAGCombine(ISD::UDIVREM); + setTargetDAGCombine(ISD::SELECT); + setTargetDAGCombine(ISD::AND); + setTargetDAGCombine(ISD::OR); + setTargetDAGCombine(ISD::ADD); + + setMinFunctionAlignment(Subtarget.isGP64bit() ? 3 : 2); + + // The arguments on the stack are defined in terms of 4-byte slots on O32 + // and 8-byte slots on N32/N64. + setMinStackArgumentAlignment((ABI.IsN32() || ABI.IsN64()) ? 8 : 4); + + setStackPointerRegisterToSaveRestore(ABI.IsN64() ? Mips::SP_64 : Mips::SP); + + MaxStoresPerMemcpy = 16; + + isMicroMips = Subtarget.inMicroMipsMode(); +} + +const MipsTargetLowering *MipsTargetLowering::create(const MipsTargetMachine &TM, + const MipsSubtarget &STI) { + if (STI.inMips16Mode()) + return llvm::createMips16TargetLowering(TM, STI); + + return llvm::createMipsSETargetLowering(TM, STI); +} + +// Create a fast isel object. +FastISel * +MipsTargetLowering::createFastISel(FunctionLoweringInfo &funcInfo, + const TargetLibraryInfo *libInfo) const { + if (!funcInfo.MF->getTarget().Options.EnableFastISel) + return TargetLowering::createFastISel(funcInfo, libInfo); + return Mips::createFastISel(funcInfo, libInfo); +} + +EVT MipsTargetLowering::getSetCCResultType(const DataLayout &, LLVMContext &, + EVT VT) const { + if (!VT.isVector()) + return MVT::i32; + return VT.changeVectorElementTypeToInteger(); +} + +static SDValue performDivRemCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget &Subtarget) { + if (DCI.isBeforeLegalizeOps()) + return SDValue(); + + EVT Ty = N->getValueType(0); + unsigned LO = (Ty == MVT::i32) ? Mips::LO0 : Mips::LO0_64; + unsigned HI = (Ty == MVT::i32) ? Mips::HI0 : Mips::HI0_64; + unsigned Opc = N->getOpcode() == ISD::SDIVREM ? MipsISD::DivRem16 : + MipsISD::DivRemU16; + SDLoc DL(N); + + SDValue DivRem = DAG.getNode(Opc, DL, MVT::Glue, + N->getOperand(0), N->getOperand(1)); + SDValue InChain = DAG.getEntryNode(); + SDValue InGlue = DivRem; + + // insert MFLO + if (N->hasAnyUseOfValue(0)) { + SDValue CopyFromLo = DAG.getCopyFromReg(InChain, DL, LO, Ty, + InGlue); + DAG.ReplaceAllUsesOfValueWith(SDValue(N, 0), CopyFromLo); + InChain = CopyFromLo.getValue(1); + InGlue = CopyFromLo.getValue(2); + } + + // insert MFHI + if (N->hasAnyUseOfValue(1)) { + SDValue CopyFromHi = DAG.getCopyFromReg(InChain, DL, + HI, Ty, InGlue); + DAG.ReplaceAllUsesOfValueWith(SDValue(N, 1), CopyFromHi); + } + + return SDValue(); +} + +static Mips::CondCode condCodeToFCC(ISD::CondCode CC) { + switch (CC) { + default: llvm_unreachable("Unknown fp condition code!"); + case ISD::SETEQ: + case ISD::SETOEQ: return Mips::FCOND_OEQ; + case ISD::SETUNE: return Mips::FCOND_UNE; + case ISD::SETLT: + case ISD::SETOLT: return Mips::FCOND_OLT; + case ISD::SETGT: + case ISD::SETOGT: return Mips::FCOND_OGT; + case ISD::SETLE: + case ISD::SETOLE: return Mips::FCOND_OLE; + case ISD::SETGE: + case ISD::SETOGE: return Mips::FCOND_OGE; + case ISD::SETULT: return Mips::FCOND_ULT; + case ISD::SETULE: return Mips::FCOND_ULE; + case ISD::SETUGT: return Mips::FCOND_UGT; + case ISD::SETUGE: return Mips::FCOND_UGE; + case ISD::SETUO: return Mips::FCOND_UN; + case ISD::SETO: return Mips::FCOND_OR; + case ISD::SETNE: + case ISD::SETONE: return Mips::FCOND_ONE; + case ISD::SETUEQ: return Mips::FCOND_UEQ; + } +} + + +/// This function returns true if the floating point conditional branches and +/// conditional moves which use condition code CC should be inverted. +static bool invertFPCondCodeUser(Mips::CondCode CC) { + if (CC >= Mips::FCOND_F && CC <= Mips::FCOND_NGT) + return false; + + assert((CC >= Mips::FCOND_T && CC <= Mips::FCOND_GT) && + "Illegal Condition Code"); + + return true; +} + +// Creates and returns an FPCmp node from a setcc node. +// Returns Op if setcc is not a floating point comparison. +static SDValue createFPCmp(SelectionDAG &DAG, const SDValue &Op) { + // must be a SETCC node + if (Op.getOpcode() != ISD::SETCC) + return Op; + + SDValue LHS = Op.getOperand(0); + + if (!LHS.getValueType().isFloatingPoint()) + return Op; + + SDValue RHS = Op.getOperand(1); + SDLoc DL(Op); + + // Assume the 3rd operand is a CondCodeSDNode. Add code to check the type of + // node if necessary. + ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get(); + + return DAG.getNode(MipsISD::FPCmp, DL, MVT::Glue, LHS, RHS, + DAG.getConstant(condCodeToFCC(CC), DL, MVT::i32)); +} + +// Creates and returns a CMovFPT/F node. +static SDValue createCMovFP(SelectionDAG &DAG, SDValue Cond, SDValue True, + SDValue False, SDLoc DL) { + ConstantSDNode *CC = cast<ConstantSDNode>(Cond.getOperand(2)); + bool invert = invertFPCondCodeUser((Mips::CondCode)CC->getSExtValue()); + SDValue FCC0 = DAG.getRegister(Mips::FCC0, MVT::i32); + + return DAG.getNode((invert ? MipsISD::CMovFP_F : MipsISD::CMovFP_T), DL, + True.getValueType(), True, FCC0, False, Cond); +} + +static SDValue performSELECTCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget &Subtarget) { + if (DCI.isBeforeLegalizeOps()) + return SDValue(); + + SDValue SetCC = N->getOperand(0); + + if ((SetCC.getOpcode() != ISD::SETCC) || + !SetCC.getOperand(0).getValueType().isInteger()) + return SDValue(); + + SDValue False = N->getOperand(2); + EVT FalseTy = False.getValueType(); + + if (!FalseTy.isInteger()) + return SDValue(); + + ConstantSDNode *FalseC = dyn_cast<ConstantSDNode>(False); + + // 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); + + if (!FalseC->getZExtValue()) { + ISD::CondCode CC = cast<CondCodeSDNode>(SetCC.getOperand(2))->get(); + SDValue True = N->getOperand(1); + + SetCC = DAG.getSetCC(DL, SetCC.getValueType(), SetCC.getOperand(0), + SetCC.getOperand(1), ISD::getSetCCInverse(CC, true)); + + return DAG.getNode(ISD::SELECT, DL, FalseTy, SetCC, False, True); + } + + // If both operands are integer constants there's a possibility that we + // can do some interesting optimizations. + SDValue True = N->getOperand(1); + ConstantSDNode *TrueC = dyn_cast<ConstantSDNode>(True); + + if (!TrueC || !True.getValueType().isInteger()) + return SDValue(); + + // We'll also ignore MVT::i64 operands as this optimizations proves + // to be ineffective because of the required sign extensions as the result + // of a SETCC operator is always MVT::i32 for non-vector types. + if (True.getValueType() == MVT::i64) + return SDValue(); + + int64_t Diff = TrueC->getSExtValue() - FalseC->getSExtValue(); + + // 1) (a < x) ? y : y-1 + // slti $reg1, a, x + // addiu $reg2, $reg1, y-1 + if (Diff == 1) + return DAG.getNode(ISD::ADD, DL, SetCC.getValueType(), SetCC, False); + + // 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); + } + + // Couldn't optimize. + return SDValue(); +} + +static SDValue performCMovFPCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget &Subtarget) { + if (DCI.isBeforeLegalizeOps()) + return SDValue(); + + SDValue ValueIfTrue = N->getOperand(0), ValueIfFalse = N->getOperand(2); + + ConstantSDNode *FalseC = dyn_cast<ConstantSDNode>(ValueIfFalse); + if (!FalseC || FalseC->getZExtValue()) + return SDValue(); + + // Since RHS (False) is 0, we swap the order of the True/False operands + // (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 + unsigned Opc = (N->getOpcode() == MipsISD::CMovFP_T) ? MipsISD::CMovFP_F : + MipsISD::CMovFP_T; + + SDValue FCC = N->getOperand(1), Glue = N->getOperand(3); + return DAG.getNode(Opc, SDLoc(N), ValueIfFalse.getValueType(), + ValueIfFalse, FCC, ValueIfTrue, Glue); +} + +static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget &Subtarget) { + // Pattern match EXT. + // $dst = and ((sra or srl) $src , pos), (2**size - 1) + // => ext $dst, $src, size, pos + if (DCI.isBeforeLegalizeOps() || !Subtarget.hasExtractInsert()) + return SDValue(); + + SDValue ShiftRight = N->getOperand(0), Mask = N->getOperand(1); + unsigned ShiftRightOpc = ShiftRight.getOpcode(); + + // Op's first operand must be a shift right. + if (ShiftRightOpc != ISD::SRA && ShiftRightOpc != ISD::SRL) + return SDValue(); + + // The second operand of the shift must be an immediate. + ConstantSDNode *CN; + if (!(CN = dyn_cast<ConstantSDNode>(ShiftRight.getOperand(1)))) + return SDValue(); + + uint64_t Pos = CN->getZExtValue(); + uint64_t SMPos, SMSize; + + // Op's second operand must be a shifted mask. + if (!(CN = dyn_cast<ConstantSDNode>(Mask)) || + !isShiftedMask(CN->getZExtValue(), SMPos, SMSize)) + return SDValue(); + + // Return if the shifted mask does not start at bit 0 or the sum of its size + // and Pos exceeds the word's size. + EVT ValTy = N->getValueType(0); + if (SMPos != 0 || Pos + SMSize > ValTy.getSizeInBits()) + return SDValue(); + + SDLoc DL(N); + return DAG.getNode(MipsISD::Ext, DL, ValTy, + ShiftRight.getOperand(0), + DAG.getConstant(Pos, DL, MVT::i32), + DAG.getConstant(SMSize, DL, MVT::i32)); +} + +static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget &Subtarget) { + // Pattern match INS. + // $dst = or (and $src1 , mask0), (and (shl $src, pos), mask1), + // where mask1 = (2**size - 1) << pos, mask0 = ~mask1 + // => ins $dst, $src, size, pos, $src1 + if (DCI.isBeforeLegalizeOps() || !Subtarget.hasExtractInsert()) + return SDValue(); + + SDValue And0 = N->getOperand(0), And1 = N->getOperand(1); + uint64_t SMPos0, SMSize0, SMPos1, SMSize1; + ConstantSDNode *CN; + + // See if Op's first operand matches (and $src1 , mask0). + if (And0.getOpcode() != ISD::AND) + return SDValue(); + + if (!(CN = dyn_cast<ConstantSDNode>(And0.getOperand(1))) || + !isShiftedMask(~CN->getSExtValue(), SMPos0, SMSize0)) + return SDValue(); + + // See if Op's second operand matches (and (shl $src, pos), mask1). + if (And1.getOpcode() != ISD::AND) + return SDValue(); + + if (!(CN = dyn_cast<ConstantSDNode>(And1.getOperand(1))) || + !isShiftedMask(CN->getZExtValue(), SMPos1, SMSize1)) + return SDValue(); + + // The shift masks must have the same position and size. + if (SMPos0 != SMPos1 || SMSize0 != SMSize1) + return SDValue(); + + SDValue Shl = And1.getOperand(0); + if (Shl.getOpcode() != ISD::SHL) + return SDValue(); + + if (!(CN = dyn_cast<ConstantSDNode>(Shl.getOperand(1)))) + return SDValue(); + + unsigned Shamt = CN->getZExtValue(); + + // Return if the shift amount and the first bit position of mask are not the + // same. + EVT ValTy = N->getValueType(0); + if ((Shamt != SMPos0) || (SMPos0 + SMSize0 > ValTy.getSizeInBits())) + return SDValue(); + + SDLoc DL(N); + return DAG.getNode(MipsISD::Ins, DL, ValTy, Shl.getOperand(0), + DAG.getConstant(SMPos0, DL, MVT::i32), + DAG.getConstant(SMSize0, DL, MVT::i32), + And0.getOperand(0)); +} + +static SDValue performADDCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget &Subtarget) { + // (add v0, (add v1, abs_lo(tjt))) => (add (add v0, v1), abs_lo(tjt)) + + if (DCI.isBeforeLegalizeOps()) + return SDValue(); + + SDValue Add = N->getOperand(1); + + if (Add.getOpcode() != ISD::ADD) + return SDValue(); + + SDValue Lo = Add.getOperand(1); + + if ((Lo.getOpcode() != MipsISD::Lo) || + (Lo.getOperand(0).getOpcode() != ISD::TargetJumpTable)) + return SDValue(); + + EVT ValTy = N->getValueType(0); + SDLoc DL(N); + + SDValue Add1 = DAG.getNode(ISD::ADD, DL, ValTy, N->getOperand(0), + Add.getOperand(0)); + return DAG.getNode(ISD::ADD, DL, ValTy, Add1, Lo); +} + +SDValue MipsTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) + const { + SelectionDAG &DAG = DCI.DAG; + unsigned Opc = N->getOpcode(); + + switch (Opc) { + default: break; + case ISD::SDIVREM: + case ISD::UDIVREM: + return performDivRemCombine(N, DAG, DCI, Subtarget); + case ISD::SELECT: + return performSELECTCombine(N, DAG, DCI, Subtarget); + case MipsISD::CMovFP_F: + case MipsISD::CMovFP_T: + return performCMovFPCombine(N, DAG, DCI, Subtarget); + case ISD::AND: + return performANDCombine(N, DAG, DCI, Subtarget); + case ISD::OR: + return performORCombine(N, DAG, DCI, Subtarget); + case ISD::ADD: + return performADDCombine(N, DAG, DCI, Subtarget); + } + + return SDValue(); +} + +bool MipsTargetLowering::isCheapToSpeculateCttz() const { + return Subtarget.hasMips32(); +} + +bool MipsTargetLowering::isCheapToSpeculateCtlz() const { + return Subtarget.hasMips32(); +} + +void +MipsTargetLowering::LowerOperationWrapper(SDNode *N, + SmallVectorImpl<SDValue> &Results, + SelectionDAG &DAG) const { + SDValue Res = LowerOperation(SDValue(N, 0), DAG); + + for (unsigned I = 0, E = Res->getNumValues(); I != E; ++I) + Results.push_back(Res.getValue(I)); +} + +void +MipsTargetLowering::ReplaceNodeResults(SDNode *N, + SmallVectorImpl<SDValue> &Results, + SelectionDAG &DAG) const { + return LowerOperationWrapper(N, Results, DAG); +} + +SDValue MipsTargetLowering:: +LowerOperation(SDValue Op, SelectionDAG &DAG) const +{ + switch (Op.getOpcode()) + { + case ISD::BR_JT: return lowerBR_JT(Op, DAG); + case ISD::BRCOND: return lowerBRCOND(Op, DAG); + case ISD::ConstantPool: return lowerConstantPool(Op, DAG); + case ISD::GlobalAddress: return lowerGlobalAddress(Op, DAG); + case ISD::BlockAddress: return lowerBlockAddress(Op, DAG); + case ISD::GlobalTLSAddress: return lowerGlobalTLSAddress(Op, DAG); + case ISD::JumpTable: return lowerJumpTable(Op, DAG); + case ISD::SELECT: return lowerSELECT(Op, DAG); + case ISD::SELECT_CC: return lowerSELECT_CC(Op, DAG); + case ISD::SETCC: return lowerSETCC(Op, DAG); + case ISD::VASTART: return lowerVASTART(Op, DAG); + case ISD::VAARG: return lowerVAARG(Op, DAG); + case ISD::FCOPYSIGN: return lowerFCOPYSIGN(Op, DAG); + case ISD::FRAMEADDR: return lowerFRAMEADDR(Op, DAG); + case ISD::RETURNADDR: return lowerRETURNADDR(Op, DAG); + case ISD::EH_RETURN: return lowerEH_RETURN(Op, DAG); + case ISD::ATOMIC_FENCE: return lowerATOMIC_FENCE(Op, DAG); + case ISD::SHL_PARTS: return lowerShiftLeftParts(Op, DAG); + case ISD::SRA_PARTS: return lowerShiftRightParts(Op, DAG, true); + case ISD::SRL_PARTS: return lowerShiftRightParts(Op, DAG, false); + case ISD::LOAD: return lowerLOAD(Op, DAG); + case ISD::STORE: return lowerSTORE(Op, DAG); + case ISD::ADD: return lowerADD(Op, DAG); + case ISD::FP_TO_SINT: return lowerFP_TO_SINT(Op, DAG); + } + return SDValue(); +} + +//===----------------------------------------------------------------------===// +// Lower helper functions +//===----------------------------------------------------------------------===// + +// addLiveIn - This helper function adds the specified physical register to the +// MachineFunction as a live in value. It also creates a corresponding +// virtual register for it. +static unsigned +addLiveIn(MachineFunction &MF, unsigned PReg, const TargetRegisterClass *RC) +{ + unsigned VReg = MF.getRegInfo().createVirtualRegister(RC); + MF.getRegInfo().addLiveIn(PReg, VReg); + return VReg; +} + +static MachineBasicBlock *insertDivByZeroTrap(MachineInstr *MI, + MachineBasicBlock &MBB, + const TargetInstrInfo &TII, + bool Is64Bit) { + if (NoZeroDivCheck) + return &MBB; + + // Insert instruction "teq $divisor_reg, $zero, 7". + MachineBasicBlock::iterator I(MI); + MachineInstrBuilder MIB; + MachineOperand &Divisor = MI->getOperand(2); + MIB = BuildMI(MBB, std::next(I), MI->getDebugLoc(), TII.get(Mips::TEQ)) + .addReg(Divisor.getReg(), getKillRegState(Divisor.isKill())) + .addReg(Mips::ZERO).addImm(7); + + // Use the 32-bit sub-register if this is a 64-bit division. + if (Is64Bit) + MIB->getOperand(0).setSubReg(Mips::sub_32); + + // Clear Divisor's kill flag. + Divisor.setIsKill(false); + + // We would normally delete the original instruction here but in this case + // we only needed to inject an additional instruction rather than replace it. + + return &MBB; +} + +MachineBasicBlock * +MipsTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const { + switch (MI->getOpcode()) { + default: + llvm_unreachable("Unexpected instr type to insert"); + case Mips::ATOMIC_LOAD_ADD_I8: + return emitAtomicBinaryPartword(MI, BB, 1, Mips::ADDu); + case Mips::ATOMIC_LOAD_ADD_I16: + return emitAtomicBinaryPartword(MI, BB, 2, Mips::ADDu); + case Mips::ATOMIC_LOAD_ADD_I32: + return emitAtomicBinary(MI, BB, 4, Mips::ADDu); + case Mips::ATOMIC_LOAD_ADD_I64: + return emitAtomicBinary(MI, BB, 8, Mips::DADDu); + + case Mips::ATOMIC_LOAD_AND_I8: + return emitAtomicBinaryPartword(MI, BB, 1, Mips::AND); + case Mips::ATOMIC_LOAD_AND_I16: + return emitAtomicBinaryPartword(MI, BB, 2, Mips::AND); + case Mips::ATOMIC_LOAD_AND_I32: + return emitAtomicBinary(MI, BB, 4, Mips::AND); + case Mips::ATOMIC_LOAD_AND_I64: + return emitAtomicBinary(MI, BB, 8, Mips::AND64); + + case Mips::ATOMIC_LOAD_OR_I8: + return emitAtomicBinaryPartword(MI, BB, 1, Mips::OR); + case Mips::ATOMIC_LOAD_OR_I16: + return emitAtomicBinaryPartword(MI, BB, 2, Mips::OR); + case Mips::ATOMIC_LOAD_OR_I32: + return emitAtomicBinary(MI, BB, 4, Mips::OR); + case Mips::ATOMIC_LOAD_OR_I64: + return emitAtomicBinary(MI, BB, 8, Mips::OR64); + + case Mips::ATOMIC_LOAD_XOR_I8: + return emitAtomicBinaryPartword(MI, BB, 1, Mips::XOR); + case Mips::ATOMIC_LOAD_XOR_I16: + return emitAtomicBinaryPartword(MI, BB, 2, Mips::XOR); + case Mips::ATOMIC_LOAD_XOR_I32: + return emitAtomicBinary(MI, BB, 4, Mips::XOR); + case Mips::ATOMIC_LOAD_XOR_I64: + return emitAtomicBinary(MI, BB, 8, Mips::XOR64); + + case Mips::ATOMIC_LOAD_NAND_I8: + return emitAtomicBinaryPartword(MI, BB, 1, 0, true); + case Mips::ATOMIC_LOAD_NAND_I16: + return emitAtomicBinaryPartword(MI, BB, 2, 0, true); + case Mips::ATOMIC_LOAD_NAND_I32: + return emitAtomicBinary(MI, BB, 4, 0, true); + case Mips::ATOMIC_LOAD_NAND_I64: + return emitAtomicBinary(MI, BB, 8, 0, true); + + case Mips::ATOMIC_LOAD_SUB_I8: + return emitAtomicBinaryPartword(MI, BB, 1, Mips::SUBu); + case Mips::ATOMIC_LOAD_SUB_I16: + return emitAtomicBinaryPartword(MI, BB, 2, Mips::SUBu); + case Mips::ATOMIC_LOAD_SUB_I32: + return emitAtomicBinary(MI, BB, 4, Mips::SUBu); + case Mips::ATOMIC_LOAD_SUB_I64: + return emitAtomicBinary(MI, BB, 8, Mips::DSUBu); + + case Mips::ATOMIC_SWAP_I8: + return emitAtomicBinaryPartword(MI, BB, 1, 0); + case Mips::ATOMIC_SWAP_I16: + return emitAtomicBinaryPartword(MI, BB, 2, 0); + case Mips::ATOMIC_SWAP_I32: + return emitAtomicBinary(MI, BB, 4, 0); + case Mips::ATOMIC_SWAP_I64: + return emitAtomicBinary(MI, BB, 8, 0); + + case Mips::ATOMIC_CMP_SWAP_I8: + return emitAtomicCmpSwapPartword(MI, BB, 1); + case Mips::ATOMIC_CMP_SWAP_I16: + return emitAtomicCmpSwapPartword(MI, BB, 2); + case Mips::ATOMIC_CMP_SWAP_I32: + return emitAtomicCmpSwap(MI, BB, 4); + case Mips::ATOMIC_CMP_SWAP_I64: + return emitAtomicCmpSwap(MI, BB, 8); + case Mips::PseudoSDIV: + case Mips::PseudoUDIV: + case Mips::DIV: + case Mips::DIVU: + case Mips::MOD: + case Mips::MODU: + return insertDivByZeroTrap(MI, *BB, *Subtarget.getInstrInfo(), false); + case Mips::PseudoDSDIV: + case Mips::PseudoDUDIV: + case Mips::DDIV: + case Mips::DDIVU: + case Mips::DMOD: + case Mips::DMODU: + return insertDivByZeroTrap(MI, *BB, *Subtarget.getInstrInfo(), true); + case Mips::SEL_D: + return emitSEL_D(MI, BB); + + case Mips::PseudoSELECT_I: + case Mips::PseudoSELECT_I64: + case Mips::PseudoSELECT_S: + case Mips::PseudoSELECT_D32: + case Mips::PseudoSELECT_D64: + return emitPseudoSELECT(MI, BB, false, Mips::BNE); + case Mips::PseudoSELECTFP_F_I: + case Mips::PseudoSELECTFP_F_I64: + case Mips::PseudoSELECTFP_F_S: + case Mips::PseudoSELECTFP_F_D32: + case Mips::PseudoSELECTFP_F_D64: + return emitPseudoSELECT(MI, BB, true, Mips::BC1F); + case Mips::PseudoSELECTFP_T_I: + case Mips::PseudoSELECTFP_T_I64: + case Mips::PseudoSELECTFP_T_S: + case Mips::PseudoSELECTFP_T_D32: + case Mips::PseudoSELECTFP_T_D64: + return emitPseudoSELECT(MI, BB, true, Mips::BC1T); + } +} + +// This function also handles Mips::ATOMIC_SWAP_I32 (when BinOpcode == 0), and +// Mips::ATOMIC_LOAD_NAND_I32 (when Nand == true) +MachineBasicBlock * +MipsTargetLowering::emitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB, + unsigned Size, unsigned BinOpcode, + bool Nand) const { + assert((Size == 4 || Size == 8) && "Unsupported size for EmitAtomicBinary."); + + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::getIntegerVT(Size * 8)); + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + DebugLoc DL = MI->getDebugLoc(); + unsigned LL, SC, AND, NOR, ZERO, BEQ; + + if (Size == 4) { + if (isMicroMips) { + LL = Mips::LL_MM; + SC = Mips::SC_MM; + } else { + LL = Subtarget.hasMips32r6() ? Mips::LL_R6 : Mips::LL; + SC = Subtarget.hasMips32r6() ? Mips::SC_R6 : Mips::SC; + } + AND = Mips::AND; + NOR = Mips::NOR; + ZERO = Mips::ZERO; + BEQ = Mips::BEQ; + } else { + LL = Subtarget.hasMips64r6() ? Mips::LLD_R6 : Mips::LLD; + SC = Subtarget.hasMips64r6() ? Mips::SCD_R6 : Mips::SCD; + AND = Mips::AND64; + NOR = Mips::NOR64; + ZERO = Mips::ZERO_64; + BEQ = Mips::BEQ64; + } + + unsigned OldVal = MI->getOperand(0).getReg(); + unsigned Ptr = MI->getOperand(1).getReg(); + unsigned Incr = MI->getOperand(2).getReg(); + + unsigned StoreVal = RegInfo.createVirtualRegister(RC); + unsigned AndRes = RegInfo.createVirtualRegister(RC); + unsigned Success = RegInfo.createVirtualRegister(RC); + + // insert new blocks after the current block + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineBasicBlock *loopMBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineFunction::iterator It = ++BB->getIterator(); + MF->insert(It, loopMBB); + MF->insert(It, exitMBB); + + // Transfer the remainder of BB and its successor edges to exitMBB. + exitMBB->splice(exitMBB->begin(), BB, + std::next(MachineBasicBlock::iterator(MI)), BB->end()); + exitMBB->transferSuccessorsAndUpdatePHIs(BB); + + // thisMBB: + // ... + // fallthrough --> loopMBB + BB->addSuccessor(loopMBB); + loopMBB->addSuccessor(loopMBB); + loopMBB->addSuccessor(exitMBB); + + // loopMBB: + // ll oldval, 0(ptr) + // <binop> storeval, oldval, incr + // sc success, storeval, 0(ptr) + // beq success, $0, loopMBB + BB = loopMBB; + BuildMI(BB, DL, TII->get(LL), OldVal).addReg(Ptr).addImm(0); + if (Nand) { + // and andres, oldval, incr + // nor storeval, $0, andres + BuildMI(BB, DL, TII->get(AND), AndRes).addReg(OldVal).addReg(Incr); + BuildMI(BB, DL, TII->get(NOR), StoreVal).addReg(ZERO).addReg(AndRes); + } else if (BinOpcode) { + // <binop> storeval, oldval, incr + BuildMI(BB, DL, TII->get(BinOpcode), StoreVal).addReg(OldVal).addReg(Incr); + } else { + StoreVal = Incr; + } + BuildMI(BB, DL, TII->get(SC), Success).addReg(StoreVal).addReg(Ptr).addImm(0); + BuildMI(BB, DL, TII->get(BEQ)).addReg(Success).addReg(ZERO).addMBB(loopMBB); + + MI->eraseFromParent(); // The instruction is gone now. + + return exitMBB; +} + +MachineBasicBlock *MipsTargetLowering::emitSignExtendToI32InReg( + MachineInstr *MI, MachineBasicBlock *BB, unsigned Size, unsigned DstReg, + unsigned SrcReg) const { + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + DebugLoc DL = MI->getDebugLoc(); + + if (Subtarget.hasMips32r2() && Size == 1) { + BuildMI(BB, DL, TII->get(Mips::SEB), DstReg).addReg(SrcReg); + return BB; + } + + if (Subtarget.hasMips32r2() && Size == 2) { + BuildMI(BB, DL, TII->get(Mips::SEH), DstReg).addReg(SrcReg); + return BB; + } + + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + unsigned ScrReg = RegInfo.createVirtualRegister(RC); + + assert(Size < 32); + int64_t ShiftImm = 32 - (Size * 8); + + BuildMI(BB, DL, TII->get(Mips::SLL), ScrReg).addReg(SrcReg).addImm(ShiftImm); + BuildMI(BB, DL, TII->get(Mips::SRA), DstReg).addReg(ScrReg).addImm(ShiftImm); + + return BB; +} + +MachineBasicBlock *MipsTargetLowering::emitAtomicBinaryPartword( + MachineInstr *MI, MachineBasicBlock *BB, unsigned Size, unsigned BinOpcode, + bool Nand) const { + assert((Size == 1 || Size == 2) && + "Unsupported size for EmitAtomicBinaryPartial."); + + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + DebugLoc DL = MI->getDebugLoc(); + + unsigned Dest = MI->getOperand(0).getReg(); + unsigned Ptr = MI->getOperand(1).getReg(); + unsigned Incr = MI->getOperand(2).getReg(); + + unsigned AlignedAddr = RegInfo.createVirtualRegister(RC); + unsigned ShiftAmt = RegInfo.createVirtualRegister(RC); + unsigned Mask = RegInfo.createVirtualRegister(RC); + unsigned Mask2 = RegInfo.createVirtualRegister(RC); + unsigned NewVal = RegInfo.createVirtualRegister(RC); + unsigned OldVal = RegInfo.createVirtualRegister(RC); + unsigned Incr2 = RegInfo.createVirtualRegister(RC); + unsigned MaskLSB2 = RegInfo.createVirtualRegister(RC); + unsigned PtrLSB2 = RegInfo.createVirtualRegister(RC); + unsigned MaskUpper = RegInfo.createVirtualRegister(RC); + unsigned AndRes = RegInfo.createVirtualRegister(RC); + unsigned BinOpRes = RegInfo.createVirtualRegister(RC); + unsigned MaskedOldVal0 = RegInfo.createVirtualRegister(RC); + unsigned StoreVal = RegInfo.createVirtualRegister(RC); + unsigned MaskedOldVal1 = RegInfo.createVirtualRegister(RC); + unsigned SrlRes = RegInfo.createVirtualRegister(RC); + unsigned Success = RegInfo.createVirtualRegister(RC); + + // insert new blocks after the current block + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineBasicBlock *loopMBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineFunction::iterator It = ++BB->getIterator(); + MF->insert(It, loopMBB); + MF->insert(It, sinkMBB); + MF->insert(It, exitMBB); + + // Transfer the remainder of BB and its successor edges to exitMBB. + exitMBB->splice(exitMBB->begin(), BB, + std::next(MachineBasicBlock::iterator(MI)), BB->end()); + exitMBB->transferSuccessorsAndUpdatePHIs(BB); + + BB->addSuccessor(loopMBB); + loopMBB->addSuccessor(loopMBB); + loopMBB->addSuccessor(sinkMBB); + sinkMBB->addSuccessor(exitMBB); + + // thisMBB: + // addiu masklsb2,$0,-4 # 0xfffffffc + // and alignedaddr,ptr,masklsb2 + // andi ptrlsb2,ptr,3 + // sll shiftamt,ptrlsb2,3 + // ori maskupper,$0,255 # 0xff + // sll mask,maskupper,shiftamt + // nor mask2,$0,mask + // sll incr2,incr,shiftamt + + int64_t MaskImm = (Size == 1) ? 255 : 65535; + BuildMI(BB, DL, TII->get(Mips::ADDiu), MaskLSB2) + .addReg(Mips::ZERO).addImm(-4); + BuildMI(BB, DL, TII->get(Mips::AND), AlignedAddr) + .addReg(Ptr).addReg(MaskLSB2); + BuildMI(BB, DL, TII->get(Mips::ANDi), PtrLSB2).addReg(Ptr).addImm(3); + if (Subtarget.isLittle()) { + BuildMI(BB, DL, TII->get(Mips::SLL), ShiftAmt).addReg(PtrLSB2).addImm(3); + } else { + unsigned Off = RegInfo.createVirtualRegister(RC); + BuildMI(BB, DL, TII->get(Mips::XORi), Off) + .addReg(PtrLSB2).addImm((Size == 1) ? 3 : 2); + BuildMI(BB, DL, TII->get(Mips::SLL), ShiftAmt).addReg(Off).addImm(3); + } + BuildMI(BB, DL, TII->get(Mips::ORi), MaskUpper) + .addReg(Mips::ZERO).addImm(MaskImm); + BuildMI(BB, DL, TII->get(Mips::SLLV), Mask) + .addReg(MaskUpper).addReg(ShiftAmt); + BuildMI(BB, DL, TII->get(Mips::NOR), Mask2).addReg(Mips::ZERO).addReg(Mask); + BuildMI(BB, DL, TII->get(Mips::SLLV), Incr2).addReg(Incr).addReg(ShiftAmt); + + // atomic.load.binop + // loopMBB: + // ll oldval,0(alignedaddr) + // binop binopres,oldval,incr2 + // and newval,binopres,mask + // and maskedoldval0,oldval,mask2 + // or storeval,maskedoldval0,newval + // sc success,storeval,0(alignedaddr) + // beq success,$0,loopMBB + + // atomic.swap + // loopMBB: + // ll oldval,0(alignedaddr) + // and newval,incr2,mask + // and maskedoldval0,oldval,mask2 + // or storeval,maskedoldval0,newval + // sc success,storeval,0(alignedaddr) + // beq success,$0,loopMBB + + BB = loopMBB; + unsigned LL = isMicroMips ? Mips::LL_MM : Mips::LL; + BuildMI(BB, DL, TII->get(LL), OldVal).addReg(AlignedAddr).addImm(0); + if (Nand) { + // and andres, oldval, incr2 + // nor binopres, $0, andres + // and newval, binopres, mask + BuildMI(BB, DL, TII->get(Mips::AND), AndRes).addReg(OldVal).addReg(Incr2); + BuildMI(BB, DL, TII->get(Mips::NOR), BinOpRes) + .addReg(Mips::ZERO).addReg(AndRes); + BuildMI(BB, DL, TII->get(Mips::AND), NewVal).addReg(BinOpRes).addReg(Mask); + } else if (BinOpcode) { + // <binop> binopres, oldval, incr2 + // and newval, binopres, mask + BuildMI(BB, DL, TII->get(BinOpcode), BinOpRes).addReg(OldVal).addReg(Incr2); + BuildMI(BB, DL, TII->get(Mips::AND), NewVal).addReg(BinOpRes).addReg(Mask); + } else { // atomic.swap + // and newval, incr2, mask + BuildMI(BB, DL, TII->get(Mips::AND), NewVal).addReg(Incr2).addReg(Mask); + } + + BuildMI(BB, DL, TII->get(Mips::AND), MaskedOldVal0) + .addReg(OldVal).addReg(Mask2); + BuildMI(BB, DL, TII->get(Mips::OR), StoreVal) + .addReg(MaskedOldVal0).addReg(NewVal); + unsigned SC = isMicroMips ? Mips::SC_MM : Mips::SC; + BuildMI(BB, DL, TII->get(SC), Success) + .addReg(StoreVal).addReg(AlignedAddr).addImm(0); + BuildMI(BB, DL, TII->get(Mips::BEQ)) + .addReg(Success).addReg(Mips::ZERO).addMBB(loopMBB); + + // sinkMBB: + // and maskedoldval1,oldval,mask + // srl srlres,maskedoldval1,shiftamt + // sign_extend dest,srlres + BB = sinkMBB; + + BuildMI(BB, DL, TII->get(Mips::AND), MaskedOldVal1) + .addReg(OldVal).addReg(Mask); + BuildMI(BB, DL, TII->get(Mips::SRLV), SrlRes) + .addReg(MaskedOldVal1).addReg(ShiftAmt); + BB = emitSignExtendToI32InReg(MI, BB, Size, Dest, SrlRes); + + MI->eraseFromParent(); // The instruction is gone now. + + return exitMBB; +} + +MachineBasicBlock * MipsTargetLowering::emitAtomicCmpSwap(MachineInstr *MI, + MachineBasicBlock *BB, + unsigned Size) const { + assert((Size == 4 || Size == 8) && "Unsupported size for EmitAtomicCmpSwap."); + + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::getIntegerVT(Size * 8)); + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + DebugLoc DL = MI->getDebugLoc(); + unsigned LL, SC, ZERO, BNE, BEQ; + + if (Size == 4) { + if (isMicroMips) { + LL = Mips::LL_MM; + SC = Mips::SC_MM; + } else { + LL = Subtarget.hasMips32r6() ? Mips::LL_R6 : Mips::LL; + SC = Subtarget.hasMips32r6() ? Mips::SC_R6 : Mips::SC; + } + ZERO = Mips::ZERO; + BNE = Mips::BNE; + BEQ = Mips::BEQ; + } else { + LL = Subtarget.hasMips64r6() ? Mips::LLD_R6 : Mips::LLD; + SC = Subtarget.hasMips64r6() ? Mips::SCD_R6 : Mips::SCD; + ZERO = Mips::ZERO_64; + BNE = Mips::BNE64; + BEQ = Mips::BEQ64; + } + + unsigned Dest = MI->getOperand(0).getReg(); + unsigned Ptr = MI->getOperand(1).getReg(); + unsigned OldVal = MI->getOperand(2).getReg(); + unsigned NewVal = MI->getOperand(3).getReg(); + + unsigned Success = RegInfo.createVirtualRegister(RC); + + // insert new blocks after the current block + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineBasicBlock *loop1MBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *loop2MBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineFunction::iterator It = ++BB->getIterator(); + MF->insert(It, loop1MBB); + MF->insert(It, loop2MBB); + MF->insert(It, exitMBB); + + // Transfer the remainder of BB and its successor edges to exitMBB. + exitMBB->splice(exitMBB->begin(), BB, + std::next(MachineBasicBlock::iterator(MI)), BB->end()); + exitMBB->transferSuccessorsAndUpdatePHIs(BB); + + // thisMBB: + // ... + // fallthrough --> loop1MBB + BB->addSuccessor(loop1MBB); + loop1MBB->addSuccessor(exitMBB); + loop1MBB->addSuccessor(loop2MBB); + loop2MBB->addSuccessor(loop1MBB); + loop2MBB->addSuccessor(exitMBB); + + // loop1MBB: + // ll dest, 0(ptr) + // bne dest, oldval, exitMBB + BB = loop1MBB; + BuildMI(BB, DL, TII->get(LL), Dest).addReg(Ptr).addImm(0); + BuildMI(BB, DL, TII->get(BNE)) + .addReg(Dest).addReg(OldVal).addMBB(exitMBB); + + // loop2MBB: + // sc success, newval, 0(ptr) + // beq success, $0, loop1MBB + BB = loop2MBB; + BuildMI(BB, DL, TII->get(SC), Success) + .addReg(NewVal).addReg(Ptr).addImm(0); + BuildMI(BB, DL, TII->get(BEQ)) + .addReg(Success).addReg(ZERO).addMBB(loop1MBB); + + MI->eraseFromParent(); // The instruction is gone now. + + return exitMBB; +} + +MachineBasicBlock * +MipsTargetLowering::emitAtomicCmpSwapPartword(MachineInstr *MI, + MachineBasicBlock *BB, + unsigned Size) const { + assert((Size == 1 || Size == 2) && + "Unsupported size for EmitAtomicCmpSwapPartial."); + + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + DebugLoc DL = MI->getDebugLoc(); + + unsigned Dest = MI->getOperand(0).getReg(); + unsigned Ptr = MI->getOperand(1).getReg(); + unsigned CmpVal = MI->getOperand(2).getReg(); + unsigned NewVal = MI->getOperand(3).getReg(); + + unsigned AlignedAddr = RegInfo.createVirtualRegister(RC); + unsigned ShiftAmt = RegInfo.createVirtualRegister(RC); + unsigned Mask = RegInfo.createVirtualRegister(RC); + unsigned Mask2 = RegInfo.createVirtualRegister(RC); + unsigned ShiftedCmpVal = RegInfo.createVirtualRegister(RC); + unsigned OldVal = RegInfo.createVirtualRegister(RC); + unsigned MaskedOldVal0 = RegInfo.createVirtualRegister(RC); + unsigned ShiftedNewVal = RegInfo.createVirtualRegister(RC); + unsigned MaskLSB2 = RegInfo.createVirtualRegister(RC); + unsigned PtrLSB2 = RegInfo.createVirtualRegister(RC); + unsigned MaskUpper = RegInfo.createVirtualRegister(RC); + unsigned MaskedCmpVal = RegInfo.createVirtualRegister(RC); + unsigned MaskedNewVal = RegInfo.createVirtualRegister(RC); + unsigned MaskedOldVal1 = RegInfo.createVirtualRegister(RC); + unsigned StoreVal = RegInfo.createVirtualRegister(RC); + unsigned SrlRes = RegInfo.createVirtualRegister(RC); + unsigned Success = RegInfo.createVirtualRegister(RC); + + // insert new blocks after the current block + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineBasicBlock *loop1MBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *loop2MBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineFunction::iterator It = ++BB->getIterator(); + MF->insert(It, loop1MBB); + MF->insert(It, loop2MBB); + MF->insert(It, sinkMBB); + MF->insert(It, exitMBB); + + // Transfer the remainder of BB and its successor edges to exitMBB. + exitMBB->splice(exitMBB->begin(), BB, + std::next(MachineBasicBlock::iterator(MI)), BB->end()); + exitMBB->transferSuccessorsAndUpdatePHIs(BB); + + BB->addSuccessor(loop1MBB); + loop1MBB->addSuccessor(sinkMBB); + loop1MBB->addSuccessor(loop2MBB); + loop2MBB->addSuccessor(loop1MBB); + loop2MBB->addSuccessor(sinkMBB); + sinkMBB->addSuccessor(exitMBB); + + // FIXME: computation of newval2 can be moved to loop2MBB. + // thisMBB: + // addiu masklsb2,$0,-4 # 0xfffffffc + // and alignedaddr,ptr,masklsb2 + // andi ptrlsb2,ptr,3 + // sll shiftamt,ptrlsb2,3 + // ori maskupper,$0,255 # 0xff + // sll mask,maskupper,shiftamt + // nor mask2,$0,mask + // andi maskedcmpval,cmpval,255 + // sll shiftedcmpval,maskedcmpval,shiftamt + // andi maskednewval,newval,255 + // sll shiftednewval,maskednewval,shiftamt + int64_t MaskImm = (Size == 1) ? 255 : 65535; + BuildMI(BB, DL, TII->get(Mips::ADDiu), MaskLSB2) + .addReg(Mips::ZERO).addImm(-4); + BuildMI(BB, DL, TII->get(Mips::AND), AlignedAddr) + .addReg(Ptr).addReg(MaskLSB2); + BuildMI(BB, DL, TII->get(Mips::ANDi), PtrLSB2).addReg(Ptr).addImm(3); + if (Subtarget.isLittle()) { + BuildMI(BB, DL, TII->get(Mips::SLL), ShiftAmt).addReg(PtrLSB2).addImm(3); + } else { + unsigned Off = RegInfo.createVirtualRegister(RC); + BuildMI(BB, DL, TII->get(Mips::XORi), Off) + .addReg(PtrLSB2).addImm((Size == 1) ? 3 : 2); + BuildMI(BB, DL, TII->get(Mips::SLL), ShiftAmt).addReg(Off).addImm(3); + } + BuildMI(BB, DL, TII->get(Mips::ORi), MaskUpper) + .addReg(Mips::ZERO).addImm(MaskImm); + BuildMI(BB, DL, TII->get(Mips::SLLV), Mask) + .addReg(MaskUpper).addReg(ShiftAmt); + BuildMI(BB, DL, TII->get(Mips::NOR), Mask2).addReg(Mips::ZERO).addReg(Mask); + BuildMI(BB, DL, TII->get(Mips::ANDi), MaskedCmpVal) + .addReg(CmpVal).addImm(MaskImm); + BuildMI(BB, DL, TII->get(Mips::SLLV), ShiftedCmpVal) + .addReg(MaskedCmpVal).addReg(ShiftAmt); + BuildMI(BB, DL, TII->get(Mips::ANDi), MaskedNewVal) + .addReg(NewVal).addImm(MaskImm); + BuildMI(BB, DL, TII->get(Mips::SLLV), ShiftedNewVal) + .addReg(MaskedNewVal).addReg(ShiftAmt); + + // loop1MBB: + // ll oldval,0(alginedaddr) + // and maskedoldval0,oldval,mask + // bne maskedoldval0,shiftedcmpval,sinkMBB + BB = loop1MBB; + unsigned LL = isMicroMips ? Mips::LL_MM : Mips::LL; + BuildMI(BB, DL, TII->get(LL), OldVal).addReg(AlignedAddr).addImm(0); + BuildMI(BB, DL, TII->get(Mips::AND), MaskedOldVal0) + .addReg(OldVal).addReg(Mask); + BuildMI(BB, DL, TII->get(Mips::BNE)) + .addReg(MaskedOldVal0).addReg(ShiftedCmpVal).addMBB(sinkMBB); + + // loop2MBB: + // and maskedoldval1,oldval,mask2 + // or storeval,maskedoldval1,shiftednewval + // sc success,storeval,0(alignedaddr) + // beq success,$0,loop1MBB + BB = loop2MBB; + BuildMI(BB, DL, TII->get(Mips::AND), MaskedOldVal1) + .addReg(OldVal).addReg(Mask2); + BuildMI(BB, DL, TII->get(Mips::OR), StoreVal) + .addReg(MaskedOldVal1).addReg(ShiftedNewVal); + unsigned SC = isMicroMips ? Mips::SC_MM : Mips::SC; + BuildMI(BB, DL, TII->get(SC), Success) + .addReg(StoreVal).addReg(AlignedAddr).addImm(0); + BuildMI(BB, DL, TII->get(Mips::BEQ)) + .addReg(Success).addReg(Mips::ZERO).addMBB(loop1MBB); + + // sinkMBB: + // srl srlres,maskedoldval0,shiftamt + // sign_extend dest,srlres + BB = sinkMBB; + + BuildMI(BB, DL, TII->get(Mips::SRLV), SrlRes) + .addReg(MaskedOldVal0).addReg(ShiftAmt); + BB = emitSignExtendToI32InReg(MI, BB, Size, Dest, SrlRes); + + MI->eraseFromParent(); // The instruction is gone now. + + return exitMBB; +} + +MachineBasicBlock *MipsTargetLowering::emitSEL_D(MachineInstr *MI, + MachineBasicBlock *BB) const { + MachineFunction *MF = BB->getParent(); + const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + DebugLoc DL = MI->getDebugLoc(); + MachineBasicBlock::iterator II(MI); + + unsigned Fc = MI->getOperand(1).getReg(); + const auto &FGR64RegClass = TRI->getRegClass(Mips::FGR64RegClassID); + + unsigned Fc2 = RegInfo.createVirtualRegister(FGR64RegClass); + + BuildMI(*BB, II, DL, TII->get(Mips::SUBREG_TO_REG), Fc2) + .addImm(0) + .addReg(Fc) + .addImm(Mips::sub_lo); + + // We don't erase the original instruction, we just replace the condition + // register with the 64-bit super-register. + MI->getOperand(1).setReg(Fc2); + + return BB; +} + +//===----------------------------------------------------------------------===// +// Misc Lower Operation implementation +//===----------------------------------------------------------------------===// +SDValue MipsTargetLowering::lowerBR_JT(SDValue Op, SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); + SDValue Table = Op.getOperand(1); + SDValue Index = Op.getOperand(2); + SDLoc DL(Op); + auto &TD = DAG.getDataLayout(); + EVT PTy = getPointerTy(TD); + unsigned EntrySize = + DAG.getMachineFunction().getJumpTableInfo()->getEntrySize(TD); + + Index = DAG.getNode(ISD::MUL, DL, PTy, Index, + DAG.getConstant(EntrySize, DL, PTy)); + SDValue Addr = DAG.getNode(ISD::ADD, DL, PTy, Index, Table); + + EVT MemVT = EVT::getIntegerVT(*DAG.getContext(), EntrySize * 8); + Addr = + DAG.getExtLoad(ISD::SEXTLOAD, DL, PTy, Chain, Addr, + MachinePointerInfo::getJumpTable(DAG.getMachineFunction()), + MemVT, false, false, false, 0); + Chain = Addr.getValue(1); + + if ((getTargetMachine().getRelocationModel() == Reloc::PIC_) || ABI.IsN64()) { + // For PIC, the sequence is: + // BRIND(load(Jumptable + index) + RelocBase) + // RelocBase can be JumpTable, GOT or some sort of global base. + Addr = DAG.getNode(ISD::ADD, DL, PTy, Addr, + getPICJumpTableRelocBase(Table, DAG)); + } + + return DAG.getNode(ISD::BRIND, DL, MVT::Other, Chain, Addr); +} + +SDValue MipsTargetLowering::lowerBRCOND(SDValue Op, SelectionDAG &DAG) const { + // The first operand is the chain, the second is the condition, the third is + // the block to branch to if the condition is true. + SDValue Chain = Op.getOperand(0); + SDValue Dest = Op.getOperand(2); + SDLoc DL(Op); + + assert(!Subtarget.hasMips32r6() && !Subtarget.hasMips64r6()); + SDValue CondRes = createFPCmp(DAG, Op.getOperand(1)); + + // Return if flag is not set by a floating point comparison. + if (CondRes.getOpcode() != MipsISD::FPCmp) + return Op; + + SDValue CCNode = CondRes.getOperand(2); + Mips::CondCode CC = + (Mips::CondCode)cast<ConstantSDNode>(CCNode)->getZExtValue(); + unsigned Opc = invertFPCondCodeUser(CC) ? Mips::BRANCH_F : Mips::BRANCH_T; + SDValue BrCode = DAG.getConstant(Opc, DL, MVT::i32); + SDValue FCC0 = DAG.getRegister(Mips::FCC0, MVT::i32); + return DAG.getNode(MipsISD::FPBrcond, DL, Op.getValueType(), Chain, BrCode, + FCC0, Dest, CondRes); +} + +SDValue MipsTargetLowering:: +lowerSELECT(SDValue Op, SelectionDAG &DAG) const +{ + assert(!Subtarget.hasMips32r6() && !Subtarget.hasMips64r6()); + SDValue Cond = createFPCmp(DAG, Op.getOperand(0)); + + // Return if flag is not set by a floating point comparison. + if (Cond.getOpcode() != MipsISD::FPCmp) + return Op; + + return createCMovFP(DAG, Cond, Op.getOperand(1), Op.getOperand(2), + SDLoc(Op)); +} + +SDValue MipsTargetLowering:: +lowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const +{ + SDLoc DL(Op); + EVT Ty = Op.getOperand(0).getValueType(); + SDValue Cond = + DAG.getNode(ISD::SETCC, DL, getSetCCResultType(DAG.getDataLayout(), + *DAG.getContext(), Ty), + Op.getOperand(0), Op.getOperand(1), Op.getOperand(4)); + + return DAG.getNode(ISD::SELECT, DL, Op.getValueType(), Cond, Op.getOperand(2), + Op.getOperand(3)); +} + +SDValue MipsTargetLowering::lowerSETCC(SDValue Op, SelectionDAG &DAG) const { + assert(!Subtarget.hasMips32r6() && !Subtarget.hasMips64r6()); + SDValue Cond = createFPCmp(DAG, Op); + + assert(Cond.getOpcode() == MipsISD::FPCmp && + "Floating point operand expected."); + + SDLoc DL(Op); + SDValue True = DAG.getConstant(1, DL, MVT::i32); + SDValue False = DAG.getConstant(0, DL, MVT::i32); + + return createCMovFP(DAG, Cond, True, False, DL); +} + +SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op, + SelectionDAG &DAG) const { + EVT Ty = Op.getValueType(); + GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op); + const GlobalValue *GV = N->getGlobal(); + + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !ABI.IsN64()) { + const MipsTargetObjectFile *TLOF = + static_cast<const MipsTargetObjectFile *>( + getTargetMachine().getObjFileLowering()); + if (TLOF->IsGlobalInSmallSection(GV, getTargetMachine())) + // %gp_rel relocation + return getAddrGPRel(N, SDLoc(N), Ty, DAG); + + // %hi/%lo relocation + return getAddrNonPIC(N, SDLoc(N), Ty, DAG); + } + + if (GV->hasInternalLinkage() || (GV->hasLocalLinkage() && !isa<Function>(GV))) + return getAddrLocal(N, SDLoc(N), Ty, DAG, ABI.IsN32() || ABI.IsN64()); + + if (LargeGOT) + return getAddrGlobalLargeGOT( + N, SDLoc(N), Ty, DAG, MipsII::MO_GOT_HI16, MipsII::MO_GOT_LO16, + DAG.getEntryNode(), + MachinePointerInfo::getGOT(DAG.getMachineFunction())); + + return getAddrGlobal( + N, SDLoc(N), Ty, DAG, + (ABI.IsN32() || ABI.IsN64()) ? MipsII::MO_GOT_DISP : MipsII::MO_GOT16, + DAG.getEntryNode(), MachinePointerInfo::getGOT(DAG.getMachineFunction())); +} + +SDValue MipsTargetLowering::lowerBlockAddress(SDValue Op, + SelectionDAG &DAG) const { + BlockAddressSDNode *N = cast<BlockAddressSDNode>(Op); + EVT Ty = Op.getValueType(); + + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !ABI.IsN64()) + return getAddrNonPIC(N, SDLoc(N), Ty, DAG); + + return getAddrLocal(N, SDLoc(N), Ty, DAG, ABI.IsN32() || ABI.IsN64()); +} + +SDValue MipsTargetLowering:: +lowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const +{ + // If the relocation model is PIC, use the General Dynamic TLS Model or + // Local Dynamic TLS model, otherwise use the Initial Exec or + // Local Exec TLS Model. + + GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op); + if (DAG.getTarget().Options.EmulatedTLS) + return LowerToTLSEmulatedModel(GA, DAG); + + SDLoc DL(GA); + const GlobalValue *GV = GA->getGlobal(); + EVT PtrVT = getPointerTy(DAG.getDataLayout()); + + TLSModel::Model model = getTargetMachine().getTLSModel(GV); + + if (model == TLSModel::GeneralDynamic || model == TLSModel::LocalDynamic) { + // General Dynamic and Local Dynamic TLS Model. + unsigned Flag = (model == TLSModel::LocalDynamic) ? MipsII::MO_TLSLDM + : MipsII::MO_TLSGD; + + SDValue TGA = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, Flag); + SDValue Argument = DAG.getNode(MipsISD::Wrapper, DL, PtrVT, + getGlobalReg(DAG, PtrVT), TGA); + unsigned PtrSize = PtrVT.getSizeInBits(); + IntegerType *PtrTy = Type::getIntNTy(*DAG.getContext(), PtrSize); + + SDValue TlsGetAddr = DAG.getExternalSymbol("__tls_get_addr", PtrVT); + + ArgListTy Args; + ArgListEntry Entry; + Entry.Node = Argument; + Entry.Ty = PtrTy; + Args.push_back(Entry); + + TargetLowering::CallLoweringInfo CLI(DAG); + CLI.setDebugLoc(DL).setChain(DAG.getEntryNode()) + .setCallee(CallingConv::C, PtrTy, TlsGetAddr, std::move(Args), 0); + std::pair<SDValue, SDValue> CallResult = LowerCallTo(CLI); + + SDValue Ret = CallResult.first; + + if (model != TLSModel::LocalDynamic) + return Ret; + + SDValue TGAHi = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, + MipsII::MO_DTPREL_HI); + SDValue Hi = DAG.getNode(MipsISD::Hi, DL, PtrVT, TGAHi); + SDValue TGALo = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, + MipsII::MO_DTPREL_LO); + SDValue Lo = DAG.getNode(MipsISD::Lo, DL, PtrVT, TGALo); + SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, Hi, Ret); + return DAG.getNode(ISD::ADD, DL, PtrVT, Add, Lo); + } + + SDValue Offset; + if (model == TLSModel::InitialExec) { + // Initial Exec TLS Model + SDValue TGA = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, + MipsII::MO_GOTTPREL); + TGA = DAG.getNode(MipsISD::Wrapper, DL, PtrVT, getGlobalReg(DAG, PtrVT), + TGA); + Offset = DAG.getLoad(PtrVT, DL, + DAG.getEntryNode(), TGA, MachinePointerInfo(), + false, false, false, 0); + } else { + // Local Exec TLS Model + assert(model == TLSModel::LocalExec); + SDValue TGAHi = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, + MipsII::MO_TPREL_HI); + SDValue TGALo = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, + MipsII::MO_TPREL_LO); + SDValue Hi = DAG.getNode(MipsISD::Hi, DL, PtrVT, TGAHi); + SDValue Lo = DAG.getNode(MipsISD::Lo, DL, PtrVT, TGALo); + Offset = DAG.getNode(ISD::ADD, DL, PtrVT, Hi, Lo); + } + + SDValue ThreadPointer = DAG.getNode(MipsISD::ThreadPointer, DL, PtrVT); + return DAG.getNode(ISD::ADD, DL, PtrVT, ThreadPointer, Offset); +} + +SDValue MipsTargetLowering:: +lowerJumpTable(SDValue Op, SelectionDAG &DAG) const +{ + JumpTableSDNode *N = cast<JumpTableSDNode>(Op); + EVT Ty = Op.getValueType(); + + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !ABI.IsN64()) + return getAddrNonPIC(N, SDLoc(N), Ty, DAG); + + return getAddrLocal(N, SDLoc(N), Ty, DAG, ABI.IsN32() || ABI.IsN64()); +} + +SDValue MipsTargetLowering:: +lowerConstantPool(SDValue Op, SelectionDAG &DAG) const +{ + ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); + EVT Ty = Op.getValueType(); + + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !ABI.IsN64()) { + const MipsTargetObjectFile *TLOF = + static_cast<const MipsTargetObjectFile *>( + getTargetMachine().getObjFileLowering()); + + if (TLOF->IsConstantInSmallSection(DAG.getDataLayout(), N->getConstVal(), + getTargetMachine())) + // %gp_rel relocation + return getAddrGPRel(N, SDLoc(N), Ty, DAG); + + return getAddrNonPIC(N, SDLoc(N), Ty, DAG); + } + + return getAddrLocal(N, SDLoc(N), Ty, DAG, ABI.IsN32() || ABI.IsN64()); +} + +SDValue MipsTargetLowering::lowerVASTART(SDValue Op, SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + MipsFunctionInfo *FuncInfo = MF.getInfo<MipsFunctionInfo>(); + + SDLoc DL(Op); + SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), + getPointerTy(MF.getDataLayout())); + + // vastart just stores the address of the VarArgsFrameIndex slot into the + // memory location argument. + const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); + return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1), + MachinePointerInfo(SV), false, false, 0); +} + +SDValue MipsTargetLowering::lowerVAARG(SDValue Op, SelectionDAG &DAG) const { + SDNode *Node = Op.getNode(); + EVT VT = Node->getValueType(0); + SDValue Chain = Node->getOperand(0); + SDValue VAListPtr = Node->getOperand(1); + unsigned Align = Node->getConstantOperandVal(3); + const Value *SV = cast<SrcValueSDNode>(Node->getOperand(2))->getValue(); + SDLoc DL(Node); + unsigned ArgSlotSizeInBytes = (ABI.IsN32() || ABI.IsN64()) ? 8 : 4; + + SDValue VAListLoad = + DAG.getLoad(getPointerTy(DAG.getDataLayout()), DL, Chain, VAListPtr, + MachinePointerInfo(SV), false, false, false, 0); + SDValue VAList = VAListLoad; + + // Re-align the pointer if necessary. + // It should only ever be necessary for 64-bit types on O32 since the minimum + // argument alignment is the same as the maximum type alignment for N32/N64. + // + // FIXME: We currently align too often. The code generator doesn't notice + // when the pointer is still aligned from the last va_arg (or pair of + // va_args for the i64 on O32 case). + if (Align > getMinStackArgumentAlignment()) { + assert(((Align & (Align-1)) == 0) && "Expected Align to be a power of 2"); + + VAList = DAG.getNode(ISD::ADD, DL, VAList.getValueType(), VAList, + DAG.getConstant(Align - 1, DL, VAList.getValueType())); + + VAList = DAG.getNode(ISD::AND, DL, VAList.getValueType(), VAList, + DAG.getConstant(-(int64_t)Align, DL, + VAList.getValueType())); + } + + // Increment the pointer, VAList, to the next vaarg. + auto &TD = DAG.getDataLayout(); + unsigned ArgSizeInBytes = + TD.getTypeAllocSize(VT.getTypeForEVT(*DAG.getContext())); + SDValue Tmp3 = DAG.getNode(ISD::ADD, DL, VAList.getValueType(), VAList, + DAG.getConstant(RoundUpToAlignment(ArgSizeInBytes, + ArgSlotSizeInBytes), + DL, VAList.getValueType())); + // Store the incremented VAList to the legalized pointer + Chain = DAG.getStore(VAListLoad.getValue(1), DL, Tmp3, VAListPtr, + MachinePointerInfo(SV), false, false, 0); + + // In big-endian mode we must adjust the pointer when the load size is smaller + // than the argument slot size. We must also reduce the known alignment to + // match. For example in the N64 ABI, we must add 4 bytes to the offset to get + // the correct half of the slot, and reduce the alignment from 8 (slot + // alignment) down to 4 (type alignment). + if (!Subtarget.isLittle() && ArgSizeInBytes < ArgSlotSizeInBytes) { + unsigned Adjustment = ArgSlotSizeInBytes - ArgSizeInBytes; + VAList = DAG.getNode(ISD::ADD, DL, VAListPtr.getValueType(), VAList, + DAG.getIntPtrConstant(Adjustment, DL)); + } + // Load the actual argument out of the pointer VAList + return DAG.getLoad(VT, DL, Chain, VAList, MachinePointerInfo(), false, false, + false, 0); +} + +static SDValue lowerFCOPYSIGN32(SDValue Op, SelectionDAG &DAG, + bool HasExtractInsert) { + EVT TyX = Op.getOperand(0).getValueType(); + EVT TyY = Op.getOperand(1).getValueType(); + SDLoc DL(Op); + SDValue Const1 = DAG.getConstant(1, DL, MVT::i32); + SDValue Const31 = DAG.getConstant(31, DL, MVT::i32); + SDValue Res; + + // If operand is of type f64, extract the upper 32-bit. Otherwise, bitcast it + // to i32. + SDValue X = (TyX == MVT::f32) ? + DAG.getNode(ISD::BITCAST, DL, MVT::i32, Op.getOperand(0)) : + DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, Op.getOperand(0), + Const1); + SDValue Y = (TyY == MVT::f32) ? + DAG.getNode(ISD::BITCAST, DL, MVT::i32, Op.getOperand(1)) : + DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, Op.getOperand(1), + Const1); + + if (HasExtractInsert) { + // ext E, Y, 31, 1 ; extract bit31 of Y + // ins X, E, 31, 1 ; insert extracted bit at bit31 of X + SDValue E = DAG.getNode(MipsISD::Ext, DL, MVT::i32, Y, Const31, Const1); + Res = DAG.getNode(MipsISD::Ins, DL, MVT::i32, E, Const31, Const1, X); + } else { + // sll SllX, X, 1 + // srl SrlX, SllX, 1 + // srl SrlY, Y, 31 + // sll SllY, SrlX, 31 + // or Or, SrlX, SllY + SDValue SllX = DAG.getNode(ISD::SHL, DL, MVT::i32, X, Const1); + SDValue SrlX = DAG.getNode(ISD::SRL, DL, MVT::i32, SllX, Const1); + SDValue SrlY = DAG.getNode(ISD::SRL, DL, MVT::i32, Y, Const31); + SDValue SllY = DAG.getNode(ISD::SHL, DL, MVT::i32, SrlY, Const31); + Res = DAG.getNode(ISD::OR, DL, MVT::i32, SrlX, SllY); + } + + if (TyX == MVT::f32) + return DAG.getNode(ISD::BITCAST, DL, Op.getOperand(0).getValueType(), Res); + + SDValue LowX = DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, + Op.getOperand(0), + DAG.getConstant(0, DL, MVT::i32)); + return DAG.getNode(MipsISD::BuildPairF64, DL, MVT::f64, LowX, Res); +} + +static SDValue lowerFCOPYSIGN64(SDValue Op, SelectionDAG &DAG, + bool HasExtractInsert) { + unsigned WidthX = Op.getOperand(0).getValueSizeInBits(); + unsigned WidthY = Op.getOperand(1).getValueSizeInBits(); + EVT TyX = MVT::getIntegerVT(WidthX), TyY = MVT::getIntegerVT(WidthY); + SDLoc DL(Op); + SDValue Const1 = DAG.getConstant(1, DL, MVT::i32); + + // Bitcast to integer nodes. + SDValue X = DAG.getNode(ISD::BITCAST, DL, TyX, Op.getOperand(0)); + SDValue Y = DAG.getNode(ISD::BITCAST, DL, TyY, Op.getOperand(1)); + + if (HasExtractInsert) { + // ext E, Y, width(Y) - 1, 1 ; extract bit width(Y)-1 of Y + // ins X, E, width(X) - 1, 1 ; insert extracted bit at bit width(X)-1 of X + SDValue E = DAG.getNode(MipsISD::Ext, DL, TyY, Y, + DAG.getConstant(WidthY - 1, DL, MVT::i32), Const1); + + if (WidthX > WidthY) + E = DAG.getNode(ISD::ZERO_EXTEND, DL, TyX, E); + else if (WidthY > WidthX) + E = DAG.getNode(ISD::TRUNCATE, DL, TyX, E); + + SDValue I = DAG.getNode(MipsISD::Ins, DL, TyX, E, + DAG.getConstant(WidthX - 1, DL, MVT::i32), Const1, + X); + return DAG.getNode(ISD::BITCAST, DL, Op.getOperand(0).getValueType(), I); + } + + // (d)sll SllX, X, 1 + // (d)srl SrlX, SllX, 1 + // (d)srl SrlY, Y, width(Y)-1 + // (d)sll SllY, SrlX, width(Y)-1 + // or Or, SrlX, SllY + SDValue SllX = DAG.getNode(ISD::SHL, DL, TyX, X, Const1); + SDValue SrlX = DAG.getNode(ISD::SRL, DL, TyX, SllX, Const1); + SDValue SrlY = DAG.getNode(ISD::SRL, DL, TyY, Y, + DAG.getConstant(WidthY - 1, DL, MVT::i32)); + + if (WidthX > WidthY) + SrlY = DAG.getNode(ISD::ZERO_EXTEND, DL, TyX, SrlY); + else if (WidthY > WidthX) + SrlY = DAG.getNode(ISD::TRUNCATE, DL, TyX, SrlY); + + SDValue SllY = DAG.getNode(ISD::SHL, DL, TyX, SrlY, + DAG.getConstant(WidthX - 1, DL, MVT::i32)); + SDValue Or = DAG.getNode(ISD::OR, DL, TyX, SrlX, SllY); + return DAG.getNode(ISD::BITCAST, DL, Op.getOperand(0).getValueType(), Or); +} + +SDValue +MipsTargetLowering::lowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const { + if (Subtarget.isGP64bit()) + return lowerFCOPYSIGN64(Op, DAG, Subtarget.hasExtractInsert()); + + return lowerFCOPYSIGN32(Op, DAG, Subtarget.hasExtractInsert()); +} + +SDValue MipsTargetLowering:: +lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { + // check the depth + assert((cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() == 0) && + "Frame address can only be determined for current frame."); + + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + MFI->setFrameAddressIsTaken(true); + EVT VT = Op.getValueType(); + SDLoc DL(Op); + SDValue FrameAddr = DAG.getCopyFromReg( + DAG.getEntryNode(), DL, ABI.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."); + + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MVT VT = Op.getSimpleValueType(); + unsigned RA = ABI.IsN64() ? Mips::RA_64 : Mips::RA; + MFI->setReturnAddressIsTaken(true); + + // Return RA, which contains the return address. Mark it an implicit live-in. + unsigned Reg = MF.addLiveIn(RA, getRegClassFor(VT)); + return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, VT); +} + +// An EH_RETURN is the result of lowering llvm.eh.return which in turn is +// generated from __builtin_eh_return (offset, handler) +// The effect of this is to adjust the stack pointer by "offset" +// and then branch to "handler". +SDValue MipsTargetLowering::lowerEH_RETURN(SDValue Op, SelectionDAG &DAG) + const { + MachineFunction &MF = DAG.getMachineFunction(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + MipsFI->setCallsEhReturn(); + SDValue Chain = Op.getOperand(0); + SDValue Offset = Op.getOperand(1); + SDValue Handler = Op.getOperand(2); + SDLoc DL(Op); + EVT Ty = ABI.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 = ABI.IsN64() ? Mips::V1_64 : Mips::V1; + unsigned AddrReg = ABI.IsN64() ? Mips::V0_64 : Mips::V0; + Chain = DAG.getCopyToReg(Chain, DL, OffsetReg, Offset, SDValue()); + Chain = DAG.getCopyToReg(Chain, DL, AddrReg, Handler, Chain.getValue(1)); + return DAG.getNode(MipsISD::EH_RETURN, DL, MVT::Other, Chain, + DAG.getRegister(OffsetReg, Ty), + DAG.getRegister(AddrReg, getPointerTy(MF.getDataLayout())), + Chain.getValue(1)); +} + +SDValue MipsTargetLowering::lowerATOMIC_FENCE(SDValue Op, + SelectionDAG &DAG) const { + // FIXME: Need pseudo-fence for 'singlethread' fences + // FIXME: Set SType for weaker fences where supported/appropriate. + unsigned SType = 0; + SDLoc DL(Op); + return DAG.getNode(MipsISD::Sync, DL, MVT::Other, Op.getOperand(0), + DAG.getConstant(SType, DL, MVT::i32)); +} + +SDValue MipsTargetLowering::lowerShiftLeftParts(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + MVT VT = Subtarget.isGP64bit() ? MVT::i64 : MVT::i32; + + SDValue Lo = Op.getOperand(0), Hi = Op.getOperand(1); + SDValue Shamt = Op.getOperand(2); + // if shamt < (VT.bits): + // lo = (shl lo, shamt) + // hi = (or (shl hi, shamt) (srl (srl lo, 1), ~shamt)) + // else: + // lo = 0 + // hi = (shl lo, shamt[4:0]) + SDValue Not = DAG.getNode(ISD::XOR, DL, MVT::i32, Shamt, + DAG.getConstant(-1, DL, MVT::i32)); + SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, + DAG.getConstant(1, DL, VT)); + SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, Not); + SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt); + SDValue Or = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo); + SDValue ShiftLeftLo = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt); + SDValue Cond = DAG.getNode(ISD::AND, DL, MVT::i32, Shamt, + DAG.getConstant(VT.getSizeInBits(), DL, MVT::i32)); + Lo = DAG.getNode(ISD::SELECT, DL, VT, Cond, + DAG.getConstant(0, DL, VT), ShiftLeftLo); + Hi = DAG.getNode(ISD::SELECT, DL, VT, Cond, ShiftLeftLo, Or); + + SDValue Ops[2] = {Lo, Hi}; + return DAG.getMergeValues(Ops, DL); +} + +SDValue MipsTargetLowering::lowerShiftRightParts(SDValue Op, SelectionDAG &DAG, + bool IsSRA) const { + SDLoc DL(Op); + SDValue Lo = Op.getOperand(0), Hi = Op.getOperand(1); + SDValue Shamt = Op.getOperand(2); + MVT VT = Subtarget.isGP64bit() ? MVT::i64 : MVT::i32; + + // if shamt < (VT.bits): + // lo = (or (shl (shl hi, 1), ~shamt) (srl lo, shamt)) + // if isSRA: + // hi = (sra hi, shamt) + // else: + // hi = (srl hi, shamt) + // else: + // if isSRA: + // lo = (sra hi, shamt[4:0]) + // hi = (sra hi, 31) + // else: + // lo = (srl hi, shamt[4:0]) + // hi = 0 + SDValue Not = DAG.getNode(ISD::XOR, DL, MVT::i32, Shamt, + DAG.getConstant(-1, DL, MVT::i32)); + SDValue ShiftLeft1Hi = DAG.getNode(ISD::SHL, DL, VT, Hi, + DAG.getConstant(1, DL, VT)); + SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, ShiftLeft1Hi, Not); + SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt); + SDValue Or = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo); + SDValue ShiftRightHi = DAG.getNode(IsSRA ? ISD::SRA : ISD::SRL, + DL, VT, Hi, Shamt); + SDValue Cond = DAG.getNode(ISD::AND, DL, MVT::i32, Shamt, + DAG.getConstant(VT.getSizeInBits(), DL, MVT::i32)); + SDValue Ext = DAG.getNode(ISD::SRA, DL, VT, Hi, + DAG.getConstant(VT.getSizeInBits() - 1, DL, VT)); + Lo = DAG.getNode(ISD::SELECT, DL, VT, Cond, ShiftRightHi, Or); + Hi = DAG.getNode(ISD::SELECT, DL, VT, Cond, + IsSRA ? Ext : DAG.getConstant(0, DL, VT), ShiftRightHi); + + SDValue Ops[2] = {Lo, Hi}; + return DAG.getMergeValues(Ops, DL); +} + +static SDValue createLoadLR(unsigned Opc, SelectionDAG &DAG, LoadSDNode *LD, + SDValue Chain, SDValue Src, unsigned Offset) { + SDValue Ptr = LD->getBasePtr(); + EVT VT = LD->getValueType(0), MemVT = LD->getMemoryVT(); + EVT BasePtrVT = Ptr.getValueType(); + SDLoc DL(LD); + SDVTList VTList = DAG.getVTList(VT, MVT::Other); + + if (Offset) + Ptr = DAG.getNode(ISD::ADD, DL, BasePtrVT, Ptr, + DAG.getConstant(Offset, DL, BasePtrVT)); + + SDValue Ops[] = { Chain, Ptr, Src }; + return DAG.getMemIntrinsicNode(Opc, DL, VTList, Ops, MemVT, + LD->getMemOperand()); +} + +// Expand an unaligned 32 or 64-bit integer load node. +SDValue MipsTargetLowering::lowerLOAD(SDValue Op, SelectionDAG &DAG) const { + LoadSDNode *LD = cast<LoadSDNode>(Op); + EVT MemVT = LD->getMemoryVT(); + + if (Subtarget.systemSupportsUnalignedAccess()) + return Op; + + // Return if load is aligned or if MemVT is neither i32 nor i64. + if ((LD->getAlignment() >= MemVT.getSizeInBits() / 8) || + ((MemVT != MVT::i32) && (MemVT != MVT::i64))) + return SDValue(); + + bool IsLittle = Subtarget.isLittle(); + EVT VT = Op.getValueType(); + ISD::LoadExtType ExtType = LD->getExtensionType(); + SDValue Chain = LD->getChain(), Undef = DAG.getUNDEF(VT); + + assert((VT == MVT::i32) || (VT == MVT::i64)); + + // Expand + // (set dst, (i64 (load baseptr))) + // to + // (set tmp, (ldl (add baseptr, 7), undef)) + // (set dst, (ldr baseptr, tmp)) + if ((VT == MVT::i64) && (ExtType == ISD::NON_EXTLOAD)) { + SDValue LDL = createLoadLR(MipsISD::LDL, DAG, LD, Chain, Undef, + IsLittle ? 7 : 0); + return createLoadLR(MipsISD::LDR, DAG, LD, LDL.getValue(1), LDL, + IsLittle ? 0 : 7); + } + + SDValue LWL = createLoadLR(MipsISD::LWL, DAG, LD, Chain, Undef, + IsLittle ? 3 : 0); + SDValue LWR = createLoadLR(MipsISD::LWR, DAG, LD, LWL.getValue(1), LWL, + IsLittle ? 0 : 3); + + // Expand + // (set dst, (i32 (load baseptr))) or + // (set dst, (i64 (sextload baseptr))) or + // (set dst, (i64 (extload baseptr))) + // to + // (set tmp, (lwl (add baseptr, 3), undef)) + // (set dst, (lwr baseptr, tmp)) + if ((VT == MVT::i32) || (ExtType == ISD::SEXTLOAD) || + (ExtType == ISD::EXTLOAD)) + return LWR; + + assert((VT == MVT::i64) && (ExtType == ISD::ZEXTLOAD)); + + // Expand + // (set dst, (i64 (zextload baseptr))) + // to + // (set tmp0, (lwl (add baseptr, 3), undef)) + // (set tmp1, (lwr baseptr, tmp0)) + // (set tmp2, (shl tmp1, 32)) + // (set dst, (srl tmp2, 32)) + SDLoc DL(LD); + SDValue Const32 = DAG.getConstant(32, DL, MVT::i32); + SDValue SLL = DAG.getNode(ISD::SHL, DL, MVT::i64, LWR, Const32); + SDValue SRL = DAG.getNode(ISD::SRL, DL, MVT::i64, SLL, Const32); + SDValue Ops[] = { SRL, LWR.getValue(1) }; + return DAG.getMergeValues(Ops, DL); +} + +static SDValue createStoreLR(unsigned Opc, SelectionDAG &DAG, StoreSDNode *SD, + SDValue Chain, unsigned Offset) { + SDValue Ptr = SD->getBasePtr(), Value = SD->getValue(); + EVT MemVT = SD->getMemoryVT(), BasePtrVT = Ptr.getValueType(); + SDLoc DL(SD); + SDVTList VTList = DAG.getVTList(MVT::Other); + + if (Offset) + Ptr = DAG.getNode(ISD::ADD, DL, BasePtrVT, Ptr, + DAG.getConstant(Offset, DL, BasePtrVT)); + + SDValue Ops[] = { Chain, Value, Ptr }; + return DAG.getMemIntrinsicNode(Opc, DL, VTList, Ops, MemVT, + SD->getMemOperand()); +} + +// Expand an unaligned 32 or 64-bit integer store node. +static SDValue lowerUnalignedIntStore(StoreSDNode *SD, SelectionDAG &DAG, + bool IsLittle) { + SDValue Value = SD->getValue(), Chain = SD->getChain(); + EVT VT = Value.getValueType(); + + // Expand + // (store val, baseptr) or + // (truncstore val, baseptr) + // to + // (swl val, (add baseptr, 3)) + // (swr val, baseptr) + if ((VT == MVT::i32) || SD->isTruncatingStore()) { + SDValue SWL = createStoreLR(MipsISD::SWL, DAG, SD, Chain, + IsLittle ? 3 : 0); + return createStoreLR(MipsISD::SWR, DAG, SD, SWL, IsLittle ? 0 : 3); + } + + assert(VT == MVT::i64); + + // Expand + // (store val, baseptr) + // to + // (sdl val, (add baseptr, 7)) + // (sdr val, baseptr) + SDValue SDL = createStoreLR(MipsISD::SDL, DAG, SD, Chain, IsLittle ? 7 : 0); + return createStoreLR(MipsISD::SDR, DAG, SD, SDL, IsLittle ? 0 : 7); +} + +// Lower (store (fp_to_sint $fp) $ptr) to (store (TruncIntFP $fp), $ptr). +static SDValue lowerFP_TO_SINT_STORE(StoreSDNode *SD, SelectionDAG &DAG) { + SDValue Val = SD->getValue(); + + if (Val.getOpcode() != ISD::FP_TO_SINT) + return SDValue(); + + EVT FPTy = EVT::getFloatingPointVT(Val.getValueSizeInBits()); + SDValue Tr = DAG.getNode(MipsISD::TruncIntFP, SDLoc(Val), FPTy, + Val.getOperand(0)); + + return DAG.getStore(SD->getChain(), SDLoc(SD), Tr, SD->getBasePtr(), + SD->getPointerInfo(), SD->isVolatile(), + SD->isNonTemporal(), SD->getAlignment()); +} + +SDValue MipsTargetLowering::lowerSTORE(SDValue Op, SelectionDAG &DAG) const { + StoreSDNode *SD = cast<StoreSDNode>(Op); + EVT MemVT = SD->getMemoryVT(); + + // Lower unaligned integer stores. + if (!Subtarget.systemSupportsUnalignedAccess() && + (SD->getAlignment() < MemVT.getSizeInBits() / 8) && + ((MemVT == MVT::i32) || (MemVT == MVT::i64))) + return lowerUnalignedIntStore(SD, DAG, Subtarget.isLittle()); + + return lowerFP_TO_SINT_STORE(SD, DAG); +} + +SDValue MipsTargetLowering::lowerADD(SDValue Op, SelectionDAG &DAG) const { + if (Op->getOperand(0).getOpcode() != ISD::FRAMEADDR + || cast<ConstantSDNode> + (Op->getOperand(0).getOperand(0))->getZExtValue() != 0 + || Op->getOperand(1).getOpcode() != ISD::FRAME_TO_ARGS_OFFSET) + return SDValue(); + + // The pattern + // (add (frameaddr 0), (frame_to_args_offset)) + // results from lowering llvm.eh.dwarf.cfa intrinsic. Transform it to + // (add FrameObject, 0) + // where FrameObject is a fixed StackObject with offset 0 which points to + // the old stack pointer. + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + EVT ValTy = Op->getValueType(0); + int FI = MFI->CreateFixedObject(Op.getValueSizeInBits() / 8, 0, false); + SDValue InArgsAddr = DAG.getFrameIndex(FI, ValTy); + SDLoc DL(Op); + return DAG.getNode(ISD::ADD, DL, ValTy, InArgsAddr, + DAG.getConstant(0, DL, ValTy)); +} + +SDValue MipsTargetLowering::lowerFP_TO_SINT(SDValue Op, + SelectionDAG &DAG) const { + EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits()); + SDValue Trunc = DAG.getNode(MipsISD::TruncIntFP, SDLoc(Op), FPTy, + Op.getOperand(0)); + return DAG.getNode(ISD::BITCAST, SDLoc(Op), Op.getValueType(), Trunc); +} + +//===----------------------------------------------------------------------===// +// Calling Convention Implementation +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// TODO: Implement a generic logic using tblgen that can support this. +// Mips O32 ABI rules: +// --- +// i32 - Passed in A0, A1, A2, A3 and stack +// f32 - Only passed in f32 registers if no int reg has been used yet to hold +// an argument. Otherwise, passed in A1, A2, A3 and stack. +// f64 - Only passed in two aliased f32 registers if no int reg has been used +// yet to hold an argument. Otherwise, use A2, A3 and stack. If A1 is +// not used, it must be shadowed. If only A3 is available, shadow it and +// go to stack. +// +// For vararg functions, all arguments are passed in A0, A1, A2, A3 and stack. +//===----------------------------------------------------------------------===// + +static bool CC_MipsO32(unsigned ValNo, MVT ValVT, MVT LocVT, + CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, + CCState &State, ArrayRef<MCPhysReg> F64Regs) { + const MipsSubtarget &Subtarget = static_cast<const MipsSubtarget &>( + State.getMachineFunction().getSubtarget()); + + static const MCPhysReg IntRegs[] = { Mips::A0, Mips::A1, Mips::A2, Mips::A3 }; + static const MCPhysReg F32Regs[] = { Mips::F12, Mips::F14 }; + + // Do not process byval args here. + if (ArgFlags.isByVal()) + return true; + + // Promote i8 and i16 + if (ArgFlags.isInReg() && !Subtarget.isLittle()) { + if (LocVT == MVT::i8 || LocVT == MVT::i16 || LocVT == MVT::i32) { + LocVT = MVT::i32; + if (ArgFlags.isSExt()) + LocInfo = CCValAssign::SExtUpper; + else if (ArgFlags.isZExt()) + LocInfo = CCValAssign::ZExtUpper; + else + LocInfo = CCValAssign::AExtUpper; + } + } + + // Promote i8 and i16 + if (LocVT == MVT::i8 || LocVT == MVT::i16) { + LocVT = MVT::i32; + if (ArgFlags.isSExt()) + LocInfo = CCValAssign::SExt; + else if (ArgFlags.isZExt()) + LocInfo = CCValAssign::ZExt; + else + LocInfo = CCValAssign::AExt; + } + + unsigned Reg; + + // f32 and f64 are allocated in A0, A1, A2, A3 when either of the following + // is true: function is vararg, argument is 3rd or higher, there is previous + // argument which is not f32 or f64. + bool AllocateFloatsInIntReg = State.isVarArg() || ValNo > 1 || + State.getFirstUnallocated(F32Regs) != ValNo; + unsigned OrigAlign = ArgFlags.getOrigAlign(); + bool isI64 = (ValVT == MVT::i32 && OrigAlign == 8); + + if (ValVT == MVT::i32 || (ValVT == MVT::f32 && AllocateFloatsInIntReg)) { + Reg = State.AllocateReg(IntRegs); + // If this is the first part of an i64 arg, + // the allocated register must be either A0 or A2. + if (isI64 && (Reg == Mips::A1 || Reg == Mips::A3)) + Reg = State.AllocateReg(IntRegs); + LocVT = MVT::i32; + } else if (ValVT == MVT::f64 && AllocateFloatsInIntReg) { + // Allocate int register and shadow next int register. If first + // available register is Mips::A1 or Mips::A3, shadow it too. + Reg = State.AllocateReg(IntRegs); + if (Reg == Mips::A1 || Reg == Mips::A3) + Reg = State.AllocateReg(IntRegs); + State.AllocateReg(IntRegs); + LocVT = MVT::i32; + } else if (ValVT.isFloatingPoint() && !AllocateFloatsInIntReg) { + // we are guaranteed to find an available float register + if (ValVT == MVT::f32) { + Reg = State.AllocateReg(F32Regs); + // Shadow int register + State.AllocateReg(IntRegs); + } else { + Reg = State.AllocateReg(F64Regs); + // Shadow int registers + unsigned Reg2 = State.AllocateReg(IntRegs); + if (Reg2 == Mips::A1 || Reg2 == Mips::A3) + State.AllocateReg(IntRegs); + State.AllocateReg(IntRegs); + } + } else + llvm_unreachable("Cannot handle this ValVT."); + + if (!Reg) { + unsigned Offset = State.AllocateStack(ValVT.getSizeInBits() >> 3, + OrigAlign); + State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); + } else + State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + + return false; +} + +static bool CC_MipsO32_FP32(unsigned ValNo, MVT ValVT, + MVT LocVT, CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags, CCState &State) { + static const MCPhysReg F64Regs[] = { Mips::D6, Mips::D7 }; + + return CC_MipsO32(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State, F64Regs); +} + +static bool CC_MipsO32_FP64(unsigned ValNo, MVT ValVT, + MVT LocVT, CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags, CCState &State) { + static const MCPhysReg F64Regs[] = { Mips::D12_64, Mips::D14_64 }; + + return CC_MipsO32(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State, F64Regs); +} + +static bool CC_MipsO32(unsigned ValNo, MVT ValVT, MVT LocVT, + CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, + CCState &State) LLVM_ATTRIBUTE_UNUSED; + +#include "MipsGenCallingConv.inc" + +//===----------------------------------------------------------------------===// +// Call Calling Convention Implementation +//===----------------------------------------------------------------------===// + +// Return next O32 integer argument register. +static unsigned getNextIntArgReg(unsigned Reg) { + assert((Reg == Mips::A0) || (Reg == Mips::A2)); + return (Reg == Mips::A0) ? Mips::A1 : Mips::A3; +} + +SDValue +MipsTargetLowering::passArgOnStack(SDValue StackPtr, unsigned Offset, + SDValue Chain, SDValue Arg, SDLoc DL, + bool IsTailCall, SelectionDAG &DAG) const { + if (!IsTailCall) { + SDValue PtrOff = + DAG.getNode(ISD::ADD, DL, getPointerTy(DAG.getDataLayout()), StackPtr, + DAG.getIntPtrConstant(Offset, DL)); + return DAG.getStore(Chain, DL, Arg, PtrOff, MachinePointerInfo(), false, + false, 0); + } + + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + int FI = MFI->CreateFixedObject(Arg.getValueSizeInBits() / 8, Offset, false); + SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); + return DAG.getStore(Chain, DL, Arg, FIN, MachinePointerInfo(), + /*isVolatile=*/ true, false, 0); +} + +void MipsTargetLowering:: +getOpndList(SmallVectorImpl<SDValue> &Ops, + std::deque< std::pair<unsigned, SDValue> > &RegsToPass, + bool IsPICCall, bool GlobalOrExternal, bool InternalLinkage, + bool IsCallReloc, CallLoweringInfo &CLI, SDValue Callee, + SDValue Chain) const { + // Insert node "GP copy globalreg" before call to function. + // + // R_MIPS_CALL* operators (emitted when non-internal functions are called + // in PIC mode) allow symbols to be resolved via lazy binding. + // The lazy binding stub requires GP to point to the GOT. + // Note that we don't need GP to point to the GOT for indirect calls + // (when R_MIPS_CALL* is not used for the call) because Mips linker generates + // lazy binding stub for a function only when R_MIPS_CALL* are the only relocs + // used for the function (that is, Mips linker doesn't generate lazy binding + // stub for a function whose address is taken in the program). + if (IsPICCall && !InternalLinkage && IsCallReloc) { + unsigned GPReg = ABI.IsN64() ? Mips::GP_64 : Mips::GP; + EVT Ty = ABI.IsN64() ? MVT::i64 : MVT::i32; + RegsToPass.push_back(std::make_pair(GPReg, getGlobalReg(CLI.DAG, Ty))); + } + + // Build a sequence of copy-to-reg nodes chained together with token + // chain and flag operands which copy the outgoing args into registers. + // The InFlag in necessary since all emitted instructions must be + // stuck together. + SDValue InFlag; + + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { + Chain = CLI.DAG.getCopyToReg(Chain, CLI.DL, RegsToPass[i].first, + RegsToPass[i].second, InFlag); + InFlag = Chain.getValue(1); + } + + // Add argument registers to the end of the list so that they are + // known live into the call. + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) + Ops.push_back(CLI.DAG.getRegister(RegsToPass[i].first, + RegsToPass[i].second.getValueType())); + + // Add a register mask operand representing the call-preserved registers. + const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); + const uint32_t *Mask = + TRI->getCallPreservedMask(CLI.DAG.getMachineFunction(), CLI.CallConv); + assert(Mask && "Missing call preserved mask for calling convention"); + if (Subtarget.inMips16HardFloat()) { + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(CLI.Callee)) { + llvm::StringRef Sym = G->getGlobal()->getName(); + Function *F = G->getGlobal()->getParent()->getFunction(Sym); + if (F && F->hasFnAttribute("__Mips16RetHelper")) { + Mask = MipsRegisterInfo::getMips16RetHelperMask(); + } + } + } + Ops.push_back(CLI.DAG.getRegisterMask(Mask)); + + if (InFlag.getNode()) + Ops.push_back(InFlag); +} + +/// LowerCall - functions arguments are copied from virtual regs to +/// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. +SDValue +MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl<SDValue> &InVals) const { + SelectionDAG &DAG = CLI.DAG; + SDLoc DL = CLI.DL; + SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; + SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; + SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; + SDValue Chain = CLI.Chain; + SDValue Callee = CLI.Callee; + bool &IsTailCall = CLI.IsTailCall; + CallingConv::ID CallConv = CLI.CallConv; + bool IsVarArg = CLI.IsVarArg; + + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + const TargetFrameLowering *TFL = Subtarget.getFrameLowering(); + MipsFunctionInfo *FuncInfo = MF.getInfo<MipsFunctionInfo>(); + bool IsPIC = getTargetMachine().getRelocationModel() == Reloc::PIC_; + + // Analyze operands of the call, assigning locations to each operand. + SmallVector<CCValAssign, 16> ArgLocs; + MipsCCState CCInfo( + CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, *DAG.getContext(), + MipsCCState::getSpecialCallingConvForCallee(Callee.getNode(), Subtarget)); + + // Allocate the reserved argument area. It seems strange to do this from the + // caller side but removing it breaks the frame size calculation. + CCInfo.AllocateStack(ABI.GetCalleeAllocdArgSizeInBytes(CallConv), 1); + + CCInfo.AnalyzeCallOperands(Outs, CC_Mips, CLI.getArgs(), Callee.getNode()); + + // Get a count of how many bytes are to be pushed on the stack. + unsigned NextStackOffset = CCInfo.getNextStackOffset(); + + // Check if it's really possible to do a tail call. + if (IsTailCall) + IsTailCall = isEligibleForTailCallOptimization( + CCInfo, NextStackOffset, *MF.getInfo<MipsFunctionInfo>()); + + if (!IsTailCall && CLI.CS && CLI.CS->isMustTailCall()) + report_fatal_error("failed to perform tail call elimination on a call " + "site marked musttail"); + + if (IsTailCall) + ++NumTailCalls; + + // Chain is the output chain of the last Load/Store or CopyToReg node. + // ByValChain is the output chain of the last Memcpy node created for copying + // byval arguments to the stack. + unsigned StackAlignment = TFL->getStackAlignment(); + NextStackOffset = RoundUpToAlignment(NextStackOffset, StackAlignment); + SDValue NextStackOffsetVal = DAG.getIntPtrConstant(NextStackOffset, DL, true); + + if (!IsTailCall) + Chain = DAG.getCALLSEQ_START(Chain, NextStackOffsetVal, DL); + + SDValue StackPtr = + DAG.getCopyFromReg(Chain, DL, ABI.IsN64() ? Mips::SP_64 : Mips::SP, + getPointerTy(DAG.getDataLayout())); + + // With EABI is it possible to have 16 args on registers. + std::deque< std::pair<unsigned, SDValue> > RegsToPass; + SmallVector<SDValue, 8> MemOpChains; + + CCInfo.rewindByValRegsInfo(); + + // Walk the register/memloc assignments, inserting copies/loads. + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + SDValue Arg = OutVals[i]; + CCValAssign &VA = ArgLocs[i]; + MVT ValVT = VA.getValVT(), LocVT = VA.getLocVT(); + ISD::ArgFlagsTy Flags = Outs[i].Flags; + bool UseUpperBits = false; + + // ByVal Arg. + if (Flags.isByVal()) { + unsigned FirstByValReg, LastByValReg; + unsigned ByValIdx = CCInfo.getInRegsParamsProcessed(); + CCInfo.getInRegsParamInfo(ByValIdx, FirstByValReg, LastByValReg); + + assert(Flags.getByValSize() && + "ByVal args of size 0 should have been ignored by front-end."); + assert(ByValIdx < CCInfo.getInRegsParamsCount()); + assert(!IsTailCall && + "Do not tail-call optimize if there is a byval argument."); + passByValArg(Chain, DL, RegsToPass, MemOpChains, StackPtr, MFI, DAG, Arg, + FirstByValReg, LastByValReg, Flags, Subtarget.isLittle(), + VA); + CCInfo.nextInRegsParam(); + continue; + } + + // Promote the value if needed. + switch (VA.getLocInfo()) { + default: + llvm_unreachable("Unknown loc info!"); + case CCValAssign::Full: + if (VA.isRegLoc()) { + if ((ValVT == MVT::f32 && LocVT == MVT::i32) || + (ValVT == MVT::f64 && LocVT == MVT::i64) || + (ValVT == MVT::i64 && LocVT == MVT::f64)) + Arg = DAG.getNode(ISD::BITCAST, DL, LocVT, Arg); + else if (ValVT == MVT::f64 && LocVT == MVT::i32) { + SDValue Lo = DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, + Arg, DAG.getConstant(0, DL, MVT::i32)); + SDValue Hi = DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, + Arg, DAG.getConstant(1, DL, MVT::i32)); + if (!Subtarget.isLittle()) + std::swap(Lo, Hi); + unsigned LocRegLo = VA.getLocReg(); + unsigned LocRegHigh = getNextIntArgReg(LocRegLo); + RegsToPass.push_back(std::make_pair(LocRegLo, Lo)); + RegsToPass.push_back(std::make_pair(LocRegHigh, Hi)); + continue; + } + } + break; + case CCValAssign::BCvt: + Arg = DAG.getNode(ISD::BITCAST, DL, LocVT, Arg); + break; + case CCValAssign::SExtUpper: + UseUpperBits = true; + // Fallthrough + case CCValAssign::SExt: + Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, LocVT, Arg); + break; + case CCValAssign::ZExtUpper: + UseUpperBits = true; + // Fallthrough + case CCValAssign::ZExt: + Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, LocVT, Arg); + break; + case CCValAssign::AExtUpper: + UseUpperBits = true; + // Fallthrough + case CCValAssign::AExt: + Arg = DAG.getNode(ISD::ANY_EXTEND, DL, LocVT, Arg); + break; + } + + if (UseUpperBits) { + unsigned ValSizeInBits = Outs[i].ArgVT.getSizeInBits(); + unsigned LocSizeInBits = VA.getLocVT().getSizeInBits(); + Arg = DAG.getNode( + ISD::SHL, DL, VA.getLocVT(), Arg, + DAG.getConstant(LocSizeInBits - ValSizeInBits, DL, VA.getLocVT())); + } + + // Arguments that can be passed on register must be kept at + // RegsToPass vector + if (VA.isRegLoc()) { + RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); + continue; + } + + // Register can't get to this point... + assert(VA.isMemLoc()); + + // emit ISD::STORE whichs stores the + // parameter value to a stack Location + MemOpChains.push_back(passArgOnStack(StackPtr, VA.getLocMemOffset(), + Chain, Arg, DL, IsTailCall, DAG)); + } + + // Transform all store nodes into one single node because all store + // nodes are independent of each other. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains); + + // 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 = (ABI.IsN64() || IsPIC); // true if calls are translated to + // jalr $25 + bool GlobalOrExternal = false, InternalLinkage = false, IsCallReloc = false; + SDValue CalleeLo; + EVT Ty = Callee.getValueType(); + + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) { + if (IsPICCall) { + const GlobalValue *Val = G->getGlobal(); + InternalLinkage = Val->hasInternalLinkage(); + + if (InternalLinkage) + Callee = getAddrLocal(G, DL, Ty, DAG, ABI.IsN32() || ABI.IsN64()); + else if (LargeGOT) { + Callee = getAddrGlobalLargeGOT(G, DL, Ty, DAG, MipsII::MO_CALL_HI16, + MipsII::MO_CALL_LO16, Chain, + FuncInfo->callPtrInfo(Val)); + IsCallReloc = true; + } else { + Callee = getAddrGlobal(G, DL, Ty, DAG, MipsII::MO_GOT_CALL, Chain, + FuncInfo->callPtrInfo(Val)); + IsCallReloc = true; + } + } else + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, + getPointerTy(DAG.getDataLayout()), 0, + MipsII::MO_NO_FLAG); + GlobalOrExternal = true; + } + else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) { + const char *Sym = S->getSymbol(); + + if (!ABI.IsN64() && !IsPIC) // !N64 && static + Callee = DAG.getTargetExternalSymbol( + Sym, getPointerTy(DAG.getDataLayout()), MipsII::MO_NO_FLAG); + else if (LargeGOT) { + Callee = getAddrGlobalLargeGOT(S, DL, Ty, DAG, MipsII::MO_CALL_HI16, + MipsII::MO_CALL_LO16, Chain, + FuncInfo->callPtrInfo(Sym)); + IsCallReloc = true; + } else { // N64 || PIC + Callee = getAddrGlobal(S, DL, Ty, DAG, MipsII::MO_GOT_CALL, Chain, + FuncInfo->callPtrInfo(Sym)); + IsCallReloc = true; + } + + GlobalOrExternal = true; + } + + SmallVector<SDValue, 8> Ops(1, Chain); + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + + getOpndList(Ops, RegsToPass, IsPICCall, GlobalOrExternal, InternalLinkage, + IsCallReloc, CLI, Callee, Chain); + + if (IsTailCall) + return DAG.getNode(MipsISD::TailCall, DL, MVT::Other, Ops); + + Chain = DAG.getNode(MipsISD::JmpLink, DL, NodeTys, Ops); + SDValue InFlag = Chain.getValue(1); + + // Create the CALLSEQ_END node. + Chain = DAG.getCALLSEQ_END(Chain, NextStackOffsetVal, + DAG.getIntPtrConstant(0, DL, true), InFlag, DL); + InFlag = Chain.getValue(1); + + // Handle result values, copying them out of physregs into vregs that we + // return. + return LowerCallResult(Chain, InFlag, CallConv, IsVarArg, Ins, DL, DAG, + InVals, CLI); +} + +/// LowerCallResult - Lower the result values of a call into the +/// appropriate copies out of appropriate physical registers. +SDValue MipsTargetLowering::LowerCallResult( + SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals, + TargetLowering::CallLoweringInfo &CLI) const { + // Assign locations to each value returned by this call. + SmallVector<CCValAssign, 16> RVLocs; + MipsCCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, + *DAG.getContext()); + CCInfo.AnalyzeCallResult(Ins, RetCC_Mips, CLI); + + // Copy all of the result registers out of their specified physreg. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + CCValAssign &VA = RVLocs[i]; + assert(VA.isRegLoc() && "Can only return in registers!"); + + SDValue Val = DAG.getCopyFromReg(Chain, DL, RVLocs[i].getLocReg(), + RVLocs[i].getLocVT(), InFlag); + Chain = Val.getValue(1); + InFlag = Val.getValue(2); + + if (VA.isUpperBitsInLoc()) { + unsigned ValSizeInBits = Ins[i].ArgVT.getSizeInBits(); + unsigned LocSizeInBits = VA.getLocVT().getSizeInBits(); + unsigned Shift = + VA.getLocInfo() == CCValAssign::ZExtUpper ? ISD::SRL : ISD::SRA; + Val = DAG.getNode( + Shift, DL, VA.getLocVT(), Val, + DAG.getConstant(LocSizeInBits - ValSizeInBits, DL, VA.getLocVT())); + } + + switch (VA.getLocInfo()) { + default: + llvm_unreachable("Unknown loc info!"); + case CCValAssign::Full: + break; + case CCValAssign::BCvt: + Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val); + break; + case CCValAssign::AExt: + case CCValAssign::AExtUpper: + Val = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Val); + break; + case CCValAssign::ZExt: + case CCValAssign::ZExtUpper: + Val = DAG.getNode(ISD::AssertZext, DL, VA.getLocVT(), Val, + DAG.getValueType(VA.getValVT())); + Val = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Val); + break; + case CCValAssign::SExt: + case CCValAssign::SExtUpper: + Val = DAG.getNode(ISD::AssertSext, DL, VA.getLocVT(), Val, + DAG.getValueType(VA.getValVT())); + Val = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Val); + break; + } + + InVals.push_back(Val); + } + + return Chain; +} + +static SDValue UnpackFromArgumentSlot(SDValue Val, const CCValAssign &VA, + EVT ArgVT, SDLoc DL, SelectionDAG &DAG) { + MVT LocVT = VA.getLocVT(); + EVT ValVT = VA.getValVT(); + + // Shift into the upper bits if necessary. + switch (VA.getLocInfo()) { + default: + break; + case CCValAssign::AExtUpper: + case CCValAssign::SExtUpper: + case CCValAssign::ZExtUpper: { + unsigned ValSizeInBits = ArgVT.getSizeInBits(); + unsigned LocSizeInBits = VA.getLocVT().getSizeInBits(); + unsigned Opcode = + VA.getLocInfo() == CCValAssign::ZExtUpper ? ISD::SRL : ISD::SRA; + Val = DAG.getNode( + Opcode, DL, VA.getLocVT(), Val, + DAG.getConstant(LocSizeInBits - ValSizeInBits, DL, VA.getLocVT())); + break; + } + } + + // If this is an value smaller than the argument slot size (32-bit for O32, + // 64-bit for N32/N64), it has been promoted in some way to the argument slot + // size. Extract the value and insert any appropriate assertions regarding + // sign/zero extension. + switch (VA.getLocInfo()) { + default: + llvm_unreachable("Unknown loc info!"); + case CCValAssign::Full: + break; + case CCValAssign::AExtUpper: + case CCValAssign::AExt: + Val = DAG.getNode(ISD::TRUNCATE, DL, ValVT, Val); + break; + case CCValAssign::SExtUpper: + case CCValAssign::SExt: + Val = DAG.getNode(ISD::AssertSext, DL, LocVT, Val, DAG.getValueType(ValVT)); + Val = DAG.getNode(ISD::TRUNCATE, DL, ValVT, Val); + break; + case CCValAssign::ZExtUpper: + case CCValAssign::ZExt: + Val = DAG.getNode(ISD::AssertZext, DL, LocVT, Val, DAG.getValueType(ValVT)); + Val = DAG.getNode(ISD::TRUNCATE, DL, ValVT, Val); + break; + case CCValAssign::BCvt: + Val = DAG.getNode(ISD::BITCAST, DL, ValVT, Val); + break; + } + + return Val; +} + +//===----------------------------------------------------------------------===// +// Formal Arguments Calling Convention Implementation +//===----------------------------------------------------------------------===// +/// LowerFormalArguments - transform physical registers into virtual registers +/// and generate load operations for arguments places on the stack. +SDValue +MipsTargetLowering::LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + SDLoc DL, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) + const { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + MipsFI->setVarArgsFrameIndex(0); + + // Used with vargs to acumulate store chains. + std::vector<SDValue> OutChains; + + // Assign locations to all of the incoming arguments. + SmallVector<CCValAssign, 16> ArgLocs; + MipsCCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, + *DAG.getContext()); + CCInfo.AllocateStack(ABI.GetCalleeAllocdArgSizeInBytes(CallConv), 1); + const Function *Func = DAG.getMachineFunction().getFunction(); + Function::const_arg_iterator FuncArg = Func->arg_begin(); + + if (Func->hasFnAttribute("interrupt") && !Func->arg_empty()) + report_fatal_error( + "Functions with the interrupt attribute cannot have arguments!"); + + CCInfo.AnalyzeFormalArguments(Ins, CC_Mips_FixedArg); + MipsFI->setFormalArgInfo(CCInfo.getNextStackOffset(), + CCInfo.getInRegsParamsCount() > 0); + + unsigned CurArgIdx = 0; + CCInfo.rewindByValRegsInfo(); + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + if (Ins[i].isOrigArg()) { + std::advance(FuncArg, Ins[i].getOrigArgIndex() - CurArgIdx); + CurArgIdx = Ins[i].getOrigArgIndex(); + } + EVT ValVT = VA.getValVT(); + ISD::ArgFlagsTy Flags = Ins[i].Flags; + bool IsRegLoc = VA.isRegLoc(); + + if (Flags.isByVal()) { + assert(Ins[i].isOrigArg() && "Byval arguments cannot be implicit"); + unsigned FirstByValReg, LastByValReg; + unsigned ByValIdx = CCInfo.getInRegsParamsProcessed(); + CCInfo.getInRegsParamInfo(ByValIdx, FirstByValReg, LastByValReg); + + assert(Flags.getByValSize() && + "ByVal args of size 0 should have been ignored by front-end."); + assert(ByValIdx < CCInfo.getInRegsParamsCount()); + copyByValRegs(Chain, DL, OutChains, DAG, Flags, InVals, &*FuncArg, + FirstByValReg, LastByValReg, VA, CCInfo); + CCInfo.nextInRegsParam(); + continue; + } + + // Arguments stored on registers + if (IsRegLoc) { + MVT RegVT = VA.getLocVT(); + unsigned ArgReg = VA.getLocReg(); + const TargetRegisterClass *RC = getRegClassFor(RegVT); + + // Transform the arguments stored on + // physical registers into virtual ones + unsigned Reg = addLiveIn(DAG.getMachineFunction(), ArgReg, RC); + SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, RegVT); + + ArgValue = UnpackFromArgumentSlot(ArgValue, VA, Ins[i].ArgVT, DL, DAG); + + // Handle floating point arguments passed in integer registers and + // long double arguments passed in floating point registers. + if ((RegVT == MVT::i32 && ValVT == MVT::f32) || + (RegVT == MVT::i64 && ValVT == MVT::f64) || + (RegVT == MVT::f64 && ValVT == MVT::i64)) + ArgValue = DAG.getNode(ISD::BITCAST, DL, ValVT, ArgValue); + else if (ABI.IsO32() && RegVT == MVT::i32 && + ValVT == MVT::f64) { + unsigned Reg2 = addLiveIn(DAG.getMachineFunction(), + getNextIntArgReg(ArgReg), RC); + SDValue ArgValue2 = DAG.getCopyFromReg(Chain, DL, Reg2, RegVT); + if (!Subtarget.isLittle()) + std::swap(ArgValue, ArgValue2); + ArgValue = DAG.getNode(MipsISD::BuildPairF64, DL, MVT::f64, + ArgValue, ArgValue2); + } + + InVals.push_back(ArgValue); + } else { // VA.isRegLoc() + MVT LocVT = VA.getLocVT(); + + if (ABI.IsO32()) { + // We ought to be able to use LocVT directly but O32 sets it to i32 + // when allocating floating point values to integer registers. + // This shouldn't influence how we load the value into registers unless + // we are targeting softfloat. + if (VA.getValVT().isFloatingPoint() && !Subtarget.useSoftFloat()) + LocVT = VA.getValVT(); + } + + // sanity check + assert(VA.isMemLoc()); + + // The stack pointer offset is relative to the caller stack frame. + int FI = MFI->CreateFixedObject(LocVT.getSizeInBits() / 8, + VA.getLocMemOffset(), true); + + // Create load nodes to retrieve arguments from the stack + SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); + SDValue ArgValue = DAG.getLoad( + LocVT, DL, Chain, FIN, + MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), + false, false, false, 0); + OutChains.push_back(ArgValue.getValue(1)); + + ArgValue = UnpackFromArgumentSlot(ArgValue, VA, Ins[i].ArgVT, DL, DAG); + + InVals.push_back(ArgValue); + } + } + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + // The mips ABIs for returning structs by value requires that we copy + // the sret argument into $v0 for the return. Save the argument into + // a virtual register so that we can access it from the return points. + if (Ins[i].Flags.isSRet()) { + unsigned Reg = MipsFI->getSRetReturnReg(); + if (!Reg) { + Reg = MF.getRegInfo().createVirtualRegister( + getRegClassFor(ABI.IsN64() ? MVT::i64 : MVT::i32)); + MipsFI->setSRetReturnReg(Reg); + } + SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), DL, Reg, InVals[i]); + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Copy, Chain); + break; + } + } + + if (IsVarArg) + writeVarArgRegs(OutChains, Chain, DL, DAG, CCInfo); + + // All stores are grouped in one node to allow the matching between + // the size of Ins and InVals. This only happens when on varg functions + if (!OutChains.empty()) { + OutChains.push_back(Chain); + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains); + } + + return Chain; +} + +//===----------------------------------------------------------------------===// +// Return Value Calling Convention Implementation +//===----------------------------------------------------------------------===// + +bool +MipsTargetLowering::CanLowerReturn(CallingConv::ID CallConv, + MachineFunction &MF, bool IsVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + LLVMContext &Context) const { + SmallVector<CCValAssign, 16> RVLocs; + MipsCCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); + return CCInfo.CheckReturn(Outs, RetCC_Mips); +} + +bool +MipsTargetLowering::shouldSignExtendTypeInLibCall(EVT Type, bool IsSigned) const { + if (Subtarget.hasMips3() && Subtarget.useSoftFloat()) { + if (Type == MVT::i32) + return true; + } + return IsSigned; +} + +SDValue +MipsTargetLowering::LowerInterruptReturn(SmallVectorImpl<SDValue> &RetOps, + SDLoc DL, SelectionDAG &DAG) const { + + MachineFunction &MF = DAG.getMachineFunction(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + MipsFI->setISR(); + + return DAG.getNode(MipsISD::ERet, DL, MVT::Other, RetOps); +} + +SDValue +MipsTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + SDLoc DL, SelectionDAG &DAG) const { + // CCValAssign - represent the assignment of + // the return value to a location + SmallVector<CCValAssign, 16> RVLocs; + MachineFunction &MF = DAG.getMachineFunction(); + + // CCState - Info about the registers and stack slot. + MipsCCState CCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext()); + + // Analyze return values. + CCInfo.AnalyzeReturn(Outs, RetCC_Mips); + + SDValue Flag; + SmallVector<SDValue, 4> RetOps(1, Chain); + + // Copy the result values into the output registers. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + SDValue Val = OutVals[i]; + CCValAssign &VA = RVLocs[i]; + assert(VA.isRegLoc() && "Can only return in registers!"); + bool UseUpperBits = false; + + switch (VA.getLocInfo()) { + default: + llvm_unreachable("Unknown loc info!"); + case CCValAssign::Full: + break; + case CCValAssign::BCvt: + Val = DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Val); + break; + case CCValAssign::AExtUpper: + UseUpperBits = true; + // Fallthrough + case CCValAssign::AExt: + Val = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Val); + break; + case CCValAssign::ZExtUpper: + UseUpperBits = true; + // Fallthrough + case CCValAssign::ZExt: + Val = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Val); + break; + case CCValAssign::SExtUpper: + UseUpperBits = true; + // Fallthrough + case CCValAssign::SExt: + Val = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Val); + break; + } + + if (UseUpperBits) { + unsigned ValSizeInBits = Outs[i].ArgVT.getSizeInBits(); + unsigned LocSizeInBits = VA.getLocVT().getSizeInBits(); + Val = DAG.getNode( + ISD::SHL, DL, VA.getLocVT(), Val, + DAG.getConstant(LocSizeInBits - ValSizeInBits, DL, VA.getLocVT())); + } + + Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Flag); + + // Guarantee that all emitted copies are stuck together with flags. + Flag = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); + } + + // The mips ABIs for returning structs by value requires that we copy + // the sret argument into $v0 for the return. We saved the argument into + // a virtual register in the entry block, so now we copy the value out + // and into $v0. + if (MF.getFunction()->hasStructRetAttr()) { + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + unsigned Reg = MipsFI->getSRetReturnReg(); + + if (!Reg) + llvm_unreachable("sret virtual register not created in the entry block"); + SDValue Val = + DAG.getCopyFromReg(Chain, DL, Reg, getPointerTy(DAG.getDataLayout())); + unsigned V0 = ABI.IsN64() ? Mips::V0_64 : Mips::V0; + + Chain = DAG.getCopyToReg(Chain, DL, V0, Val, Flag); + Flag = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(V0, getPointerTy(DAG.getDataLayout()))); + } + + RetOps[0] = Chain; // Update chain. + + // Add the flag if we have it. + if (Flag.getNode()) + RetOps.push_back(Flag); + + // ISRs must use "eret". + if (DAG.getMachineFunction().getFunction()->hasFnAttribute("interrupt")) + return LowerInterruptReturn(RetOps, DL, DAG); + + // Standard return on Mips is a "jr $ra" + return DAG.getNode(MipsISD::Ret, DL, MVT::Other, RetOps); +} + +//===----------------------------------------------------------------------===// +// Mips Inline Assembly Support +//===----------------------------------------------------------------------===// + +/// getConstraintType - Given a constraint letter, return the type of +/// constraint it is for this target. +MipsTargetLowering::ConstraintType +MipsTargetLowering::getConstraintType(StringRef Constraint) const { + // Mips specific constraints + // GCC config/mips/constraints.md + // + // 'd' : An address register. Equivalent to r + // unless generating MIPS16 code. + // 'y' : Equivalent to r; retained for + // backwards compatibility. + // 'c' : A register suitable for use in an indirect + // jump. This will always be $25 for -mabicalls. + // 'l' : The lo register. 1 word storage. + // 'x' : The hilo register pair. Double word storage. + if (Constraint.size() == 1) { + switch (Constraint[0]) { + default : break; + case 'd': + case 'y': + case 'f': + case 'c': + case 'l': + case 'x': + return C_RegisterClass; + case 'R': + return C_Memory; + } + } + + if (Constraint == "ZC") + return C_Memory; + + return TargetLowering::getConstraintType(Constraint); +} + +/// Examine constraint type and operand type and determine a weight value. +/// This object must already have been set up with the operand type +/// and the current alternative constraint selected. +TargetLowering::ConstraintWeight +MipsTargetLowering::getSingleConstraintMatchWeight( + AsmOperandInfo &info, const char *constraint) const { + ConstraintWeight weight = CW_Invalid; + Value *CallOperandVal = info.CallOperandVal; + // If we don't have a value, we can't do a match, + // but allow it at the lowest weight. + if (!CallOperandVal) + return CW_Default; + Type *type = CallOperandVal->getType(); + // Look at the constraint type. + switch (*constraint) { + default: + weight = TargetLowering::getSingleConstraintMatchWeight(info, constraint); + break; + case 'd': + case 'y': + if (type->isIntegerTy()) + weight = CW_Register; + break; + case 'f': // FPU or MSA register + if (Subtarget.hasMSA() && type->isVectorTy() && + cast<VectorType>(type)->getBitWidth() == 128) + weight = CW_Register; + else if (type->isFloatTy()) + weight = CW_Register; + break; + case 'c': // $25 for indirect jumps + case 'l': // lo register + case 'x': // hilo register pair + if (type->isIntegerTy()) + weight = CW_SpecificReg; + break; + case 'I': // signed 16 bit immediate + case 'J': // integer zero + case 'K': // unsigned 16 bit immediate + case 'L': // signed 32 bit immediate where lower 16 bits are 0 + case 'N': // immediate in the range of -65535 to -1 (inclusive) + case 'O': // signed 15 bit immediate (+- 16383) + case 'P': // immediate in the range of 65535 to 1 (inclusive) + if (isa<ConstantInt>(CallOperandVal)) + weight = CW_Constant; + break; + case 'R': + weight = CW_Memory; + break; + } + return weight; +} + +/// This is a helper function to parse a physical register string and split it +/// into non-numeric and numeric parts (Prefix and Reg). The first boolean flag +/// that is returned indicates whether parsing was successful. The second flag +/// is true if the numeric part exists. +static std::pair<bool, bool> parsePhysicalReg(StringRef C, StringRef &Prefix, + unsigned long long &Reg) { + if (C.front() != '{' || C.back() != '}') + return std::make_pair(false, false); + + // Search for the first numeric character. + StringRef::const_iterator I, B = C.begin() + 1, E = C.end() - 1; + I = std::find_if(B, E, isdigit); + + Prefix = StringRef(B, I - B); + + // The second flag is set to false if no numeric characters were found. + if (I == E) + return std::make_pair(true, false); + + // Parse the numeric characters. + return std::make_pair(!getAsUnsignedInteger(StringRef(I, E - I), 10, Reg), + true); +} + +std::pair<unsigned, const TargetRegisterClass *> MipsTargetLowering:: +parseRegForInlineAsmConstraint(StringRef C, MVT VT) const { + const TargetRegisterInfo *TRI = + Subtarget.getRegisterInfo(); + const TargetRegisterClass *RC; + StringRef Prefix; + unsigned long long Reg; + + std::pair<bool, bool> R = parsePhysicalReg(C, Prefix, Reg); + + if (!R.first) + return std::make_pair(0U, nullptr); + + if ((Prefix == "hi" || Prefix == "lo")) { // Parse hi/lo. + // No numeric characters follow "hi" or "lo". + if (R.second) + return std::make_pair(0U, nullptr); + + RC = TRI->getRegClass(Prefix == "hi" ? + Mips::HI32RegClassID : Mips::LO32RegClassID); + return std::make_pair(*(RC->begin()), RC); + } else if (Prefix.startswith("$msa")) { + // Parse $msa(ir|csr|access|save|modify|request|map|unmap) + + // No numeric characters follow the name. + if (R.second) + return std::make_pair(0U, nullptr); + + Reg = StringSwitch<unsigned long long>(Prefix) + .Case("$msair", Mips::MSAIR) + .Case("$msacsr", Mips::MSACSR) + .Case("$msaaccess", Mips::MSAAccess) + .Case("$msasave", Mips::MSASave) + .Case("$msamodify", Mips::MSAModify) + .Case("$msarequest", Mips::MSARequest) + .Case("$msamap", Mips::MSAMap) + .Case("$msaunmap", Mips::MSAUnmap) + .Default(0); + + if (!Reg) + return std::make_pair(0U, nullptr); + + RC = TRI->getRegClass(Mips::MSACtrlRegClassID); + return std::make_pair(Reg, RC); + } + + if (!R.second) + return std::make_pair(0U, nullptr); + + if (Prefix == "$f") { // Parse $f0-$f31. + // If the size of FP registers is 64-bit or Reg is an even number, select + // the 64-bit register class. Otherwise, select the 32-bit register class. + if (VT == MVT::Other) + VT = (Subtarget.isFP64bit() || !(Reg % 2)) ? MVT::f64 : MVT::f32; + + RC = getRegClassFor(VT); + + if (RC == &Mips::AFGR64RegClass) { + assert(Reg % 2 == 0); + Reg >>= 1; + } + } else if (Prefix == "$fcc") // Parse $fcc0-$fcc7. + RC = TRI->getRegClass(Mips::FCCRegClassID); + else if (Prefix == "$w") { // Parse $w0-$w31. + RC = getRegClassFor((VT == MVT::Other) ? MVT::v16i8 : VT); + } else { // Parse $0-$31. + assert(Prefix == "$"); + RC = getRegClassFor((VT == MVT::Other) ? MVT::i32 : VT); + } + + assert(Reg < RC->getNumRegs()); + return std::make_pair(*(RC->begin() + Reg), RC); +} + +/// Given a register class constraint, like 'r', if this corresponds directly +/// to an LLVM register class, return a register of 0 and the register class +/// pointer. +std::pair<unsigned, const TargetRegisterClass *> +MipsTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, + StringRef Constraint, + MVT VT) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + case 'd': // Address register. Same as 'r' unless generating MIPS16 code. + case 'y': // Same as 'r'. Exists for compatibility. + case 'r': + if (VT == MVT::i32 || VT == MVT::i16 || VT == MVT::i8) { + if (Subtarget.inMips16Mode()) + return std::make_pair(0U, &Mips::CPU16RegsRegClass); + return std::make_pair(0U, &Mips::GPR32RegClass); + } + if (VT == MVT::i64 && !Subtarget.isGP64bit()) + return std::make_pair(0U, &Mips::GPR32RegClass); + if (VT == MVT::i64 && Subtarget.isGP64bit()) + return std::make_pair(0U, &Mips::GPR64RegClass); + // This will generate an error message + return std::make_pair(0U, nullptr); + case 'f': // FPU or MSA register + if (VT == MVT::v16i8) + return std::make_pair(0U, &Mips::MSA128BRegClass); + else if (VT == MVT::v8i16 || VT == MVT::v8f16) + return std::make_pair(0U, &Mips::MSA128HRegClass); + else if (VT == MVT::v4i32 || VT == MVT::v4f32) + return std::make_pair(0U, &Mips::MSA128WRegClass); + else if (VT == MVT::v2i64 || VT == MVT::v2f64) + return std::make_pair(0U, &Mips::MSA128DRegClass); + else if (VT == MVT::f32) + return std::make_pair(0U, &Mips::FGR32RegClass); + else if ((VT == MVT::f64) && (!Subtarget.isSingleFloat())) { + if (Subtarget.isFP64bit()) + return std::make_pair(0U, &Mips::FGR64RegClass); + return std::make_pair(0U, &Mips::AFGR64RegClass); + } + break; + case 'c': // register suitable for indirect jump + if (VT == MVT::i32) + return std::make_pair((unsigned)Mips::T9, &Mips::GPR32RegClass); + assert(VT == MVT::i64 && "Unexpected type."); + return std::make_pair((unsigned)Mips::T9_64, &Mips::GPR64RegClass); + case 'l': // register suitable for indirect jump + if (VT == MVT::i32) + return std::make_pair((unsigned)Mips::LO0, &Mips::LO32RegClass); + return std::make_pair((unsigned)Mips::LO0_64, &Mips::LO64RegClass); + case 'x': // register suitable for indirect jump + // Fixme: Not triggering the use of both hi and low + // This will generate an error message + return std::make_pair(0U, nullptr); + } + } + + std::pair<unsigned, const TargetRegisterClass *> R; + R = parseRegForInlineAsmConstraint(Constraint, VT); + + if (R.second) + return R; + + return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); +} + +/// LowerAsmOperandForConstraint - Lower the specified operand into the Ops +/// vector. If it is invalid, don't add anything to Ops. +void MipsTargetLowering::LowerAsmOperandForConstraint(SDValue Op, + std::string &Constraint, + std::vector<SDValue>&Ops, + SelectionDAG &DAG) const { + SDLoc DL(Op); + SDValue Result; + + // Only support length 1 constraints for now. + if (Constraint.length() > 1) return; + + char ConstraintLetter = Constraint[0]; + switch (ConstraintLetter) { + default: break; // This will fall through to the generic implementation + case 'I': // Signed 16 bit constant + // If this fails, the parent routine will give an error + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { + EVT Type = Op.getValueType(); + int64_t Val = C->getSExtValue(); + if (isInt<16>(Val)) { + Result = DAG.getTargetConstant(Val, DL, Type); + break; + } + } + return; + case 'J': // integer zero + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { + EVT Type = Op.getValueType(); + int64_t Val = C->getZExtValue(); + if (Val == 0) { + Result = DAG.getTargetConstant(0, DL, Type); + break; + } + } + return; + case 'K': // unsigned 16 bit immediate + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { + EVT Type = Op.getValueType(); + uint64_t Val = (uint64_t)C->getZExtValue(); + if (isUInt<16>(Val)) { + Result = DAG.getTargetConstant(Val, DL, Type); + break; + } + } + return; + case 'L': // signed 32 bit immediate where lower 16 bits are 0 + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { + EVT Type = Op.getValueType(); + int64_t Val = C->getSExtValue(); + if ((isInt<32>(Val)) && ((Val & 0xffff) == 0)){ + Result = DAG.getTargetConstant(Val, DL, Type); + break; + } + } + return; + case 'N': // immediate in the range of -65535 to -1 (inclusive) + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { + EVT Type = Op.getValueType(); + int64_t Val = C->getSExtValue(); + if ((Val >= -65535) && (Val <= -1)) { + Result = DAG.getTargetConstant(Val, DL, Type); + break; + } + } + return; + case 'O': // signed 15 bit immediate + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { + EVT Type = Op.getValueType(); + int64_t Val = C->getSExtValue(); + if ((isInt<15>(Val))) { + Result = DAG.getTargetConstant(Val, DL, Type); + break; + } + } + return; + case 'P': // immediate in the range of 1 to 65535 (inclusive) + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { + EVT Type = Op.getValueType(); + int64_t Val = C->getSExtValue(); + if ((Val <= 65535) && (Val >= 1)) { + Result = DAG.getTargetConstant(Val, DL, Type); + break; + } + } + return; + } + + if (Result.getNode()) { + Ops.push_back(Result); + return; + } + + TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); +} + +bool MipsTargetLowering::isLegalAddressingMode(const DataLayout &DL, + const AddrMode &AM, Type *Ty, + unsigned AS) const { + // No global is ever allowed as a base. + if (AM.BaseGV) + return false; + + switch (AM.Scale) { + case 0: // "r+i" or just "i", depending on HasBaseReg. + break; + case 1: + if (!AM.HasBaseReg) // allow "r+i". + break; + return false; // disallow "r+r" or "r+r+i". + default: + return false; + } + + return true; +} + +bool +MipsTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { + // The Mips target isn't yet aware of offsets. + return false; +} + +EVT MipsTargetLowering::getOptimalMemOpType(uint64_t Size, unsigned DstAlign, + unsigned SrcAlign, + bool IsMemset, bool ZeroMemset, + bool MemcpyStrSrc, + MachineFunction &MF) const { + if (Subtarget.hasMips64()) + return MVT::i64; + + return MVT::i32; +} + +bool MipsTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const { + if (VT != MVT::f32 && VT != MVT::f64) + return false; + if (Imm.isNegZero()) + return false; + return Imm.isZero(); +} + +unsigned MipsTargetLowering::getJumpTableEncoding() const { + if (ABI.IsN64()) + return MachineJumpTableInfo::EK_GPRel64BlockAddress; + + return TargetLowering::getJumpTableEncoding(); +} + +bool MipsTargetLowering::useSoftFloat() const { + return Subtarget.useSoftFloat(); +} + +void MipsTargetLowering::copyByValRegs( + SDValue Chain, SDLoc DL, std::vector<SDValue> &OutChains, SelectionDAG &DAG, + const ISD::ArgFlagsTy &Flags, SmallVectorImpl<SDValue> &InVals, + const Argument *FuncArg, unsigned FirstReg, unsigned LastReg, + const CCValAssign &VA, MipsCCState &State) const { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + unsigned GPRSizeInBytes = Subtarget.getGPRSizeInBytes(); + unsigned NumRegs = LastReg - FirstReg; + unsigned RegAreaSize = NumRegs * GPRSizeInBytes; + unsigned FrameObjSize = std::max(Flags.getByValSize(), RegAreaSize); + int FrameObjOffset; + ArrayRef<MCPhysReg> ByValArgRegs = ABI.GetByValArgRegs(); + + if (RegAreaSize) + FrameObjOffset = + (int)ABI.GetCalleeAllocdArgSizeInBytes(State.getCallingConv()) - + (int)((ByValArgRegs.size() - FirstReg) * GPRSizeInBytes); + else + FrameObjOffset = VA.getLocMemOffset(); + + // Create frame object. + EVT PtrTy = getPointerTy(DAG.getDataLayout()); + int FI = MFI->CreateFixedObject(FrameObjSize, FrameObjOffset, true); + SDValue FIN = DAG.getFrameIndex(FI, PtrTy); + InVals.push_back(FIN); + + if (!NumRegs) + return; + + // Copy arg registers. + MVT RegTy = MVT::getIntegerVT(GPRSizeInBytes * 8); + const TargetRegisterClass *RC = getRegClassFor(RegTy); + + for (unsigned I = 0; I < NumRegs; ++I) { + unsigned ArgReg = ByValArgRegs[FirstReg + I]; + unsigned VReg = addLiveIn(MF, ArgReg, RC); + unsigned Offset = I * GPRSizeInBytes; + SDValue StorePtr = DAG.getNode(ISD::ADD, DL, PtrTy, FIN, + DAG.getConstant(Offset, DL, PtrTy)); + SDValue Store = DAG.getStore(Chain, DL, DAG.getRegister(VReg, RegTy), + StorePtr, MachinePointerInfo(FuncArg, Offset), + false, false, 0); + OutChains.push_back(Store); + } +} + +// Copy byVal arg to registers and stack. +void MipsTargetLowering::passByValArg( + SDValue Chain, SDLoc DL, + std::deque<std::pair<unsigned, SDValue>> &RegsToPass, + SmallVectorImpl<SDValue> &MemOpChains, SDValue StackPtr, + MachineFrameInfo *MFI, SelectionDAG &DAG, SDValue Arg, unsigned FirstReg, + unsigned LastReg, const ISD::ArgFlagsTy &Flags, bool isLittle, + const CCValAssign &VA) const { + unsigned ByValSizeInBytes = Flags.getByValSize(); + unsigned OffsetInBytes = 0; // From beginning of struct + unsigned RegSizeInBytes = Subtarget.getGPRSizeInBytes(); + unsigned Alignment = std::min(Flags.getByValAlign(), RegSizeInBytes); + EVT PtrTy = getPointerTy(DAG.getDataLayout()), + RegTy = MVT::getIntegerVT(RegSizeInBytes * 8); + unsigned NumRegs = LastReg - FirstReg; + + if (NumRegs) { + ArrayRef<MCPhysReg> ArgRegs = ABI.GetByValArgRegs(); + bool LeftoverBytes = (NumRegs * RegSizeInBytes > ByValSizeInBytes); + unsigned I = 0; + + // Copy words to registers. + for (; I < NumRegs - LeftoverBytes; ++I, OffsetInBytes += RegSizeInBytes) { + SDValue LoadPtr = DAG.getNode(ISD::ADD, DL, PtrTy, Arg, + DAG.getConstant(OffsetInBytes, DL, PtrTy)); + SDValue LoadVal = DAG.getLoad(RegTy, DL, Chain, LoadPtr, + MachinePointerInfo(), false, false, false, + Alignment); + MemOpChains.push_back(LoadVal.getValue(1)); + unsigned ArgReg = ArgRegs[FirstReg + I]; + RegsToPass.push_back(std::make_pair(ArgReg, LoadVal)); + } + + // Return if the struct has been fully copied. + if (ByValSizeInBytes == OffsetInBytes) + return; + + // Copy the remainder of the byval argument with sub-word loads and shifts. + if (LeftoverBytes) { + SDValue Val; + + for (unsigned LoadSizeInBytes = RegSizeInBytes / 2, TotalBytesLoaded = 0; + OffsetInBytes < ByValSizeInBytes; LoadSizeInBytes /= 2) { + unsigned RemainingSizeInBytes = ByValSizeInBytes - OffsetInBytes; + + if (RemainingSizeInBytes < LoadSizeInBytes) + continue; + + // Load subword. + SDValue LoadPtr = DAG.getNode(ISD::ADD, DL, PtrTy, Arg, + DAG.getConstant(OffsetInBytes, DL, + PtrTy)); + SDValue LoadVal = DAG.getExtLoad( + ISD::ZEXTLOAD, DL, RegTy, Chain, LoadPtr, MachinePointerInfo(), + MVT::getIntegerVT(LoadSizeInBytes * 8), false, false, false, + Alignment); + MemOpChains.push_back(LoadVal.getValue(1)); + + // Shift the loaded value. + unsigned Shamt; + + if (isLittle) + Shamt = TotalBytesLoaded * 8; + else + Shamt = (RegSizeInBytes - (TotalBytesLoaded + LoadSizeInBytes)) * 8; + + SDValue Shift = DAG.getNode(ISD::SHL, DL, RegTy, LoadVal, + DAG.getConstant(Shamt, DL, MVT::i32)); + + if (Val.getNode()) + Val = DAG.getNode(ISD::OR, DL, RegTy, Val, Shift); + else + Val = Shift; + + OffsetInBytes += LoadSizeInBytes; + TotalBytesLoaded += LoadSizeInBytes; + Alignment = std::min(Alignment, LoadSizeInBytes); + } + + unsigned ArgReg = ArgRegs[FirstReg + I]; + RegsToPass.push_back(std::make_pair(ArgReg, Val)); + return; + } + } + + // Copy remainder of byval arg to it with memcpy. + unsigned MemCpySize = ByValSizeInBytes - OffsetInBytes; + SDValue Src = DAG.getNode(ISD::ADD, DL, PtrTy, Arg, + DAG.getConstant(OffsetInBytes, DL, PtrTy)); + SDValue Dst = DAG.getNode(ISD::ADD, DL, PtrTy, StackPtr, + DAG.getIntPtrConstant(VA.getLocMemOffset(), DL)); + Chain = DAG.getMemcpy(Chain, DL, Dst, Src, + DAG.getConstant(MemCpySize, DL, PtrTy), + Alignment, /*isVolatile=*/false, /*AlwaysInline=*/false, + /*isTailCall=*/false, + MachinePointerInfo(), MachinePointerInfo()); + MemOpChains.push_back(Chain); +} + +void MipsTargetLowering::writeVarArgRegs(std::vector<SDValue> &OutChains, + SDValue Chain, SDLoc DL, + SelectionDAG &DAG, + CCState &State) const { + ArrayRef<MCPhysReg> ArgRegs = ABI.GetVarArgRegs(); + unsigned Idx = State.getFirstUnallocated(ArgRegs); + unsigned RegSizeInBytes = Subtarget.getGPRSizeInBytes(); + MVT RegTy = MVT::getIntegerVT(RegSizeInBytes * 8); + const TargetRegisterClass *RC = getRegClassFor(RegTy); + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + // Offset of the first variable argument from stack pointer. + int VaArgOffset; + + if (ArgRegs.size() == Idx) + VaArgOffset = + RoundUpToAlignment(State.getNextStackOffset(), RegSizeInBytes); + else { + VaArgOffset = + (int)ABI.GetCalleeAllocdArgSizeInBytes(State.getCallingConv()) - + (int)(RegSizeInBytes * (ArgRegs.size() - Idx)); + } + + // Record the frame index of the first variable argument + // which is a value necessary to VASTART. + int FI = MFI->CreateFixedObject(RegSizeInBytes, VaArgOffset, true); + MipsFI->setVarArgsFrameIndex(FI); + + // Copy the integer registers that have not been used for argument passing + // to the argument register save area. For O32, the save area is allocated + // in the caller's stack frame, while for N32/64, it is allocated in the + // callee's stack frame. + for (unsigned I = Idx; I < ArgRegs.size(); + ++I, VaArgOffset += RegSizeInBytes) { + unsigned Reg = addLiveIn(MF, ArgRegs[I], RC); + SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, RegTy); + FI = MFI->CreateFixedObject(RegSizeInBytes, VaArgOffset, true); + SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); + SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff, + MachinePointerInfo(), false, false, 0); + cast<StoreSDNode>(Store.getNode())->getMemOperand()->setValue( + (Value *)nullptr); + OutChains.push_back(Store); + } +} + +void MipsTargetLowering::HandleByVal(CCState *State, unsigned &Size, + unsigned Align) const { + const TargetFrameLowering *TFL = Subtarget.getFrameLowering(); + + assert(Size && "Byval argument's size shouldn't be 0."); + + Align = std::min(Align, TFL->getStackAlignment()); + + unsigned FirstReg = 0; + unsigned NumRegs = 0; + + if (State->getCallingConv() != CallingConv::Fast) { + unsigned RegSizeInBytes = Subtarget.getGPRSizeInBytes(); + ArrayRef<MCPhysReg> IntArgRegs = ABI.GetByValArgRegs(); + // FIXME: The O32 case actually describes no shadow registers. + const MCPhysReg *ShadowRegs = + ABI.IsO32() ? IntArgRegs.data() : Mips64DPRegs; + + // We used to check the size as well but we can't do that anymore since + // CCState::HandleByVal() rounds up the size after calling this function. + assert(!(Align % RegSizeInBytes) && + "Byval argument's alignment should be a multiple of" + "RegSizeInBytes."); + + FirstReg = State->getFirstUnallocated(IntArgRegs); + + // If Align > RegSizeInBytes, the first arg register must be even. + // FIXME: This condition happens to do the right thing but it's not the + // right way to test it. We want to check that the stack frame offset + // of the register is aligned. + if ((Align > RegSizeInBytes) && (FirstReg % 2)) { + State->AllocateReg(IntArgRegs[FirstReg], ShadowRegs[FirstReg]); + ++FirstReg; + } + + // Mark the registers allocated. + Size = RoundUpToAlignment(Size, RegSizeInBytes); + for (unsigned I = FirstReg; Size > 0 && (I < IntArgRegs.size()); + Size -= RegSizeInBytes, ++I, ++NumRegs) + State->AllocateReg(IntArgRegs[I], ShadowRegs[I]); + } + + State->addInRegsParamInfo(FirstReg, FirstReg + NumRegs); +} + +MachineBasicBlock * +MipsTargetLowering::emitPseudoSELECT(MachineInstr *MI, MachineBasicBlock *BB, + bool isFPCmp, unsigned Opc) const { + assert(!(Subtarget.hasMips4() || Subtarget.hasMips32()) && + "Subtarget already supports SELECT nodes with the use of" + "conditional-move instructions."); + + const TargetInstrInfo *TII = + Subtarget.getInstrInfo(); + DebugLoc DL = MI->getDebugLoc(); + + // To "insert" a SELECT instruction, we actually have to insert the + // diamond control-flow pattern. The incoming instruction knows the + // destination vreg to set, the condition code register to branch on, the + // true/false values to select between, and a branch opcode to use. + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = ++BB->getIterator(); + + // thisMBB: + // ... + // TrueVal = ... + // setcc r1, r2, r3 + // bNE r1, r0, copy1MBB + // fallthrough --> copy0MBB + MachineBasicBlock *thisMBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, copy0MBB); + F->insert(It, sinkMBB); + + // Transfer the remainder of BB and its successor edges to sinkMBB. + sinkMBB->splice(sinkMBB->begin(), BB, + std::next(MachineBasicBlock::iterator(MI)), BB->end()); + sinkMBB->transferSuccessorsAndUpdatePHIs(BB); + + // Next, add the true and fallthrough blocks as its successors. + BB->addSuccessor(copy0MBB); + BB->addSuccessor(sinkMBB); + + if (isFPCmp) { + // bc1[tf] cc, sinkMBB + BuildMI(BB, DL, TII->get(Opc)) + .addReg(MI->getOperand(1).getReg()) + .addMBB(sinkMBB); + } else { + // bne rs, $0, sinkMBB + BuildMI(BB, DL, TII->get(Opc)) + .addReg(MI->getOperand(1).getReg()) + .addReg(Mips::ZERO) + .addMBB(sinkMBB); + } + + // copy0MBB: + // %FalseValue = ... + // # fallthrough to sinkMBB + BB = copy0MBB; + + // Update machine-CFG edges + BB->addSuccessor(sinkMBB); + + // sinkMBB: + // %Result = phi [ %TrueValue, thisMBB ], [ %FalseValue, copy0MBB ] + // ... + BB = sinkMBB; + + BuildMI(*BB, BB->begin(), DL, + TII->get(Mips::PHI), MI->getOperand(0).getReg()) + .addReg(MI->getOperand(2).getReg()).addMBB(thisMBB) + .addReg(MI->getOperand(3).getReg()).addMBB(copy0MBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + + return BB; +} + +// FIXME? Maybe this could be a TableGen attribute on some registers and +// this table could be generated automatically from RegInfo. +unsigned MipsTargetLowering::getRegisterByName(const char* RegName, EVT VT, + SelectionDAG &DAG) const { + // Named registers is expected to be fairly rare. For now, just support $28 + // since the linux kernel uses it. + if (Subtarget.isGP64bit()) { + unsigned Reg = StringSwitch<unsigned>(RegName) + .Case("$28", Mips::GP_64) + .Default(0); + if (Reg) + return Reg; + } else { + unsigned Reg = StringSwitch<unsigned>(RegName) + .Case("$28", Mips::GP) + .Default(0); + if (Reg) + return Reg; + } + report_fatal_error("Invalid register name global variable"); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsISelLowering.h b/contrib/llvm/lib/Target/Mips/MipsISelLowering.h new file mode 100644 index 0000000..b33e125 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsISelLowering.h @@ -0,0 +1,600 @@ +//===-- MipsISelLowering.h - Mips DAG Lowering Interface --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interfaces that Mips uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSISELLOWERING_H +#define LLVM_LIB_TARGET_MIPS_MIPSISELLOWERING_H + +#include "MCTargetDesc/MipsABIInfo.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "Mips.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/IR/Function.h" +#include "llvm/Target/TargetLowering.h" +#include <deque> +#include <string> + +namespace llvm { + namespace MipsISD { + enum NodeType : unsigned { + // Start the numbering from where ISD NodeType finishes. + FIRST_NUMBER = ISD::BUILTIN_OP_END, + + // Jump and link (call) + JmpLink, + + // Tail call + TailCall, + + // Get the Higher 16 bits from a 32-bit immediate + // No relation with Mips Hi register + Hi, + + // Get the Lower 16 bits from a 32-bit immediate + // No relation with Mips Lo register + Lo, + + // Handle gp_rel (small data/bss sections) relocation. + GPRel, + + // Thread Pointer + ThreadPointer, + + // Floating Point Branch Conditional + FPBrcond, + + // Floating Point Compare + FPCmp, + + // Floating Point Conditional Moves + CMovFP_T, + CMovFP_F, + + // FP-to-int truncation node. + TruncIntFP, + + // Return + Ret, + + // Interrupt, exception, error trap Return + ERet, + + // Software Exception Return. + EH_RETURN, + + // Node used to extract integer from accumulator. + MFHI, + MFLO, + + // Node used to insert integers to accumulator. + MTLOHI, + + // Mult nodes. + Mult, + Multu, + + // MAdd/Sub nodes + MAdd, + MAddu, + MSub, + MSubu, + + // DivRem(u) + DivRem, + DivRemU, + DivRem16, + DivRemU16, + + BuildPairF64, + ExtractElementF64, + + Wrapper, + + DynAlloc, + + Sync, + + Ext, + Ins, + + // EXTR.W instrinsic nodes. + EXTP, + EXTPDP, + EXTR_S_H, + EXTR_W, + EXTR_R_W, + EXTR_RS_W, + SHILO, + MTHLIP, + + // DPA.W intrinsic nodes. + MULSAQ_S_W_PH, + MAQ_S_W_PHL, + MAQ_S_W_PHR, + MAQ_SA_W_PHL, + MAQ_SA_W_PHR, + DPAU_H_QBL, + DPAU_H_QBR, + DPSU_H_QBL, + DPSU_H_QBR, + DPAQ_S_W_PH, + DPSQ_S_W_PH, + DPAQ_SA_L_W, + DPSQ_SA_L_W, + DPA_W_PH, + DPS_W_PH, + DPAQX_S_W_PH, + DPAQX_SA_W_PH, + DPAX_W_PH, + DPSX_W_PH, + DPSQX_S_W_PH, + DPSQX_SA_W_PH, + MULSA_W_PH, + + MULT, + MULTU, + MADD_DSP, + MADDU_DSP, + MSUB_DSP, + MSUBU_DSP, + + // DSP shift nodes. + SHLL_DSP, + SHRA_DSP, + SHRL_DSP, + + // DSP setcc and select_cc nodes. + SETCC_DSP, + SELECT_CC_DSP, + + // Vector comparisons. + // These take a vector and return a boolean. + VALL_ZERO, + VANY_ZERO, + VALL_NONZERO, + VANY_NONZERO, + + // These take a vector and return a vector bitmask. + VCEQ, + VCLE_S, + VCLE_U, + VCLT_S, + VCLT_U, + + // Element-wise vector max/min. + VSMAX, + VSMIN, + VUMAX, + VUMIN, + + // Vector Shuffle with mask as an operand + VSHF, // Generic shuffle + SHF, // 4-element set shuffle. + ILVEV, // Interleave even elements + ILVOD, // Interleave odd elements + ILVL, // Interleave left elements + ILVR, // Interleave right elements + PCKEV, // Pack even elements + PCKOD, // Pack odd elements + + // Vector Lane Copy + INSVE, // Copy element from one vector to another + + // Combined (XOR (OR $a, $b), -1) + VNOR, + + // Extended vector element extraction + VEXTRACT_SEXT_ELT, + VEXTRACT_ZEXT_ELT, + + // Load/Store Left/Right nodes. + LWL = ISD::FIRST_TARGET_MEMORY_OPCODE, + LWR, + SWL, + SWR, + LDL, + LDR, + SDL, + SDR + }; + } + + //===--------------------------------------------------------------------===// + // TargetLowering Implementation + //===--------------------------------------------------------------------===// + class MipsFunctionInfo; + class MipsSubtarget; + class MipsCCState; + + class MipsTargetLowering : public TargetLowering { + bool isMicroMips; + public: + explicit MipsTargetLowering(const MipsTargetMachine &TM, + const MipsSubtarget &STI); + + static const MipsTargetLowering *create(const MipsTargetMachine &TM, + const MipsSubtarget &STI); + + /// createFastISel - This method returns a target specific FastISel object, + /// or null if the target does not support "fast" ISel. + FastISel *createFastISel(FunctionLoweringInfo &funcInfo, + const TargetLibraryInfo *libInfo) const override; + + MVT getScalarShiftAmountTy(const DataLayout &, EVT) const override { + return MVT::i32; + } + + bool isCheapToSpeculateCttz() const override; + bool isCheapToSpeculateCtlz() const override; + + void LowerOperationWrapper(SDNode *N, + SmallVectorImpl<SDValue> &Results, + SelectionDAG &DAG) const override; + + /// LowerOperation - Provide custom lowering hooks for some operations. + SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; + + /// ReplaceNodeResults - Replace the results of node with an illegal result + /// type with new values built out of custom code. + /// + void ReplaceNodeResults(SDNode *N, SmallVectorImpl<SDValue>&Results, + SelectionDAG &DAG) const override; + + /// getTargetNodeName - This method returns the name of a target specific + // DAG node. + const char *getTargetNodeName(unsigned Opcode) const override; + + /// getSetCCResultType - get the ISD::SETCC result ValueType + EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, + EVT VT) const override; + + SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override; + + MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *MBB) const override; + + void HandleByVal(CCState *, unsigned &, unsigned) const override; + + unsigned getRegisterByName(const char* RegName, EVT VT, + SelectionDAG &DAG) const override; + + /// If a physical register, this returns the register that receives the + /// exception address on entry to an EH pad. + unsigned + getExceptionPointerRegister(const Constant *PersonalityFn) const override { + return ABI.IsN64() ? Mips::A0_64 : Mips::A0; + } + + /// If a physical register, this returns the register that receives the + /// exception typeid on entry to a landing pad. + unsigned + getExceptionSelectorRegister(const Constant *PersonalityFn) const override { + return ABI.IsN64() ? Mips::A1_64 : Mips::A1; + } + + /// Returns true if a cast between SrcAS and DestAS is a noop. + bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const override { + // Mips doesn't have any special address spaces so we just reserve + // the first 256 for software use (e.g. OpenCL) and treat casts + // between them as noops. + return SrcAS < 256 && DestAS < 256; + } + + protected: + SDValue getGlobalReg(SelectionDAG &DAG, EVT Ty) const; + + // This method creates the following nodes, which are necessary for + // computing a local symbol's address: + // + // (add (load (wrapper $gp, %got(sym)), %lo(sym)) + template <class NodeTy> + SDValue getAddrLocal(NodeTy *N, SDLoc DL, EVT Ty, SelectionDAG &DAG, + bool IsN32OrN64) const { + 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(DAG.getMachineFunction()), + false, false, false, 0); + 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); + } + + // This method creates the following nodes, which are necessary for + // computing a global symbol's address: + // + // (load (wrapper $gp, %got(sym))) + template <class NodeTy> + SDValue getAddrGlobal(NodeTy *N, SDLoc DL, EVT Ty, SelectionDAG &DAG, + unsigned Flag, SDValue Chain, + const MachinePointerInfo &PtrInfo) const { + SDValue Tgt = DAG.getNode(MipsISD::Wrapper, DL, Ty, getGlobalReg(DAG, Ty), + getTargetNode(N, Ty, DAG, Flag)); + return DAG.getLoad(Ty, DL, Chain, Tgt, PtrInfo, false, false, false, 0); + } + + // This method creates the following nodes, which are necessary for + // computing a global symbol's address in large-GOT mode: + // + // (load (wrapper (add %hi(sym), $gp), %lo(sym))) + template <class NodeTy> + SDValue getAddrGlobalLargeGOT(NodeTy *N, SDLoc DL, EVT Ty, + SelectionDAG &DAG, unsigned HiFlag, + unsigned LoFlag, SDValue Chain, + const MachinePointerInfo &PtrInfo) const { + SDValue Hi = + DAG.getNode(MipsISD::Hi, DL, Ty, getTargetNode(N, Ty, DAG, HiFlag)); + Hi = DAG.getNode(ISD::ADD, DL, Ty, Hi, getGlobalReg(DAG, Ty)); + SDValue Wrapper = DAG.getNode(MipsISD::Wrapper, DL, Ty, Hi, + getTargetNode(N, Ty, DAG, LoFlag)); + return DAG.getLoad(Ty, DL, Chain, Wrapper, PtrInfo, false, false, false, + 0); + } + + // This method creates the following nodes, which are necessary for + // computing a symbol's address in non-PIC mode: + // + // (add %hi(sym), %lo(sym)) + template <class NodeTy> + SDValue getAddrNonPIC(NodeTy *N, SDLoc DL, EVT Ty, + SelectionDAG &DAG) const { + SDValue Hi = getTargetNode(N, Ty, DAG, MipsII::MO_ABS_HI); + SDValue Lo = getTargetNode(N, Ty, DAG, MipsII::MO_ABS_LO); + return DAG.getNode(ISD::ADD, DL, Ty, + DAG.getNode(MipsISD::Hi, DL, Ty, Hi), + DAG.getNode(MipsISD::Lo, DL, Ty, Lo)); + } + + // This method creates the following nodes, which are necessary for + // computing a symbol's address using gp-relative addressing: + // + // (add $gp, %gp_rel(sym)) + template <class NodeTy> + SDValue getAddrGPRel(NodeTy *N, SDLoc DL, EVT Ty, SelectionDAG &DAG) const { + assert(Ty == MVT::i32); + SDValue GPRel = getTargetNode(N, Ty, DAG, MipsII::MO_GPREL); + return DAG.getNode(ISD::ADD, DL, Ty, + DAG.getRegister(Mips::GP, Ty), + DAG.getNode(MipsISD::GPRel, DL, DAG.getVTList(Ty), + GPRel)); + } + + /// This function fills Ops, which is the list of operands that will later + /// be used when a function call node is created. It also generates + /// copyToReg nodes to set up argument registers. + virtual void + getOpndList(SmallVectorImpl<SDValue> &Ops, + std::deque< std::pair<unsigned, SDValue> > &RegsToPass, + bool IsPICCall, bool GlobalOrExternal, bool InternalLinkage, + bool IsCallReloc, CallLoweringInfo &CLI, SDValue Callee, + SDValue Chain) const; + + protected: + SDValue lowerLOAD(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerSTORE(SDValue Op, SelectionDAG &DAG) const; + + // Subtarget Info + const MipsSubtarget &Subtarget; + // Cache the ABI from the TargetMachine, we use it everywhere. + const MipsABIInfo &ABI; + + private: + // Create a TargetGlobalAddress node. + SDValue getTargetNode(GlobalAddressSDNode *N, EVT Ty, SelectionDAG &DAG, + unsigned Flag) const; + + // Create a TargetExternalSymbol node. + SDValue getTargetNode(ExternalSymbolSDNode *N, EVT Ty, SelectionDAG &DAG, + unsigned Flag) const; + + // Create a TargetBlockAddress node. + SDValue getTargetNode(BlockAddressSDNode *N, EVT Ty, SelectionDAG &DAG, + unsigned Flag) const; + + // Create a TargetJumpTable node. + SDValue getTargetNode(JumpTableSDNode *N, EVT Ty, SelectionDAG &DAG, + unsigned Flag) const; + + // Create a TargetConstantPool node. + SDValue getTargetNode(ConstantPoolSDNode *N, EVT Ty, SelectionDAG &DAG, + unsigned Flag) const; + + // Lower Operand helpers + SDValue LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc dl, + SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals, + TargetLowering::CallLoweringInfo &CLI) const; + + // Lower Operand specifics + SDValue lowerBR_JT(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerBRCOND(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerConstantPool(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerJumpTable(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerSELECT(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerSETCC(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerVASTART(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerVAARG(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerFABS(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerATOMIC_FENCE(SDValue Op, SelectionDAG& DAG) const; + SDValue lowerShiftLeftParts(SDValue Op, SelectionDAG& DAG) const; + SDValue lowerShiftRightParts(SDValue Op, SelectionDAG& DAG, + bool IsSRA) const; + SDValue lowerADD(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) const; + + /// isEligibleForTailCallOptimization - Check whether the call is eligible + /// for tail call optimization. + virtual bool + isEligibleForTailCallOptimization(const CCState &CCInfo, + unsigned NextStackOffset, + const MipsFunctionInfo &FI) const = 0; + + /// copyByValArg - Copy argument registers which were used to pass a byval + /// argument to the stack. Create a stack frame object for the byval + /// argument. + void copyByValRegs(SDValue Chain, SDLoc DL, std::vector<SDValue> &OutChains, + SelectionDAG &DAG, const ISD::ArgFlagsTy &Flags, + SmallVectorImpl<SDValue> &InVals, + const Argument *FuncArg, unsigned FirstReg, + unsigned LastReg, const CCValAssign &VA, + MipsCCState &State) const; + + /// passByValArg - Pass a byval argument in registers or on stack. + void passByValArg(SDValue Chain, SDLoc DL, + std::deque<std::pair<unsigned, SDValue>> &RegsToPass, + SmallVectorImpl<SDValue> &MemOpChains, SDValue StackPtr, + MachineFrameInfo *MFI, SelectionDAG &DAG, SDValue Arg, + unsigned FirstReg, unsigned LastReg, + const ISD::ArgFlagsTy &Flags, bool isLittle, + const CCValAssign &VA) const; + + /// writeVarArgRegs - Write variable function arguments passed in registers + /// to the stack. Also create a stack frame object for the first variable + /// argument. + void writeVarArgRegs(std::vector<SDValue> &OutChains, SDValue Chain, + SDLoc DL, SelectionDAG &DAG, CCState &State) const; + + SDValue + LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + SDLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const override; + + SDValue passArgOnStack(SDValue StackPtr, unsigned Offset, SDValue Chain, + SDValue Arg, SDLoc DL, bool IsTailCall, + SelectionDAG &DAG) const; + + SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl<SDValue> &InVals) const override; + + bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, + bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + LLVMContext &Context) const override; + + SDValue LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + SDLoc dl, SelectionDAG &DAG) const override; + + SDValue LowerInterruptReturn(SmallVectorImpl<SDValue> &RetOps, SDLoc DL, + SelectionDAG &DAG) const; + + bool shouldSignExtendTypeInLibCall(EVT Type, bool IsSigned) const override; + + // Inline asm support + ConstraintType getConstraintType(StringRef Constraint) const override; + + /// Examine constraint string and operand type and determine a weight value. + /// The operand object must already have been set up with the operand type. + ConstraintWeight getSingleConstraintMatchWeight( + AsmOperandInfo &info, const char *constraint) const override; + + /// This function parses registers that appear in inline-asm constraints. + /// It returns pair (0, 0) on failure. + std::pair<unsigned, const TargetRegisterClass *> + parseRegForInlineAsmConstraint(StringRef C, MVT VT) const; + + std::pair<unsigned, const TargetRegisterClass *> + getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, + StringRef Constraint, MVT VT) const override; + + /// LowerAsmOperandForConstraint - Lower the specified operand into the Ops + /// vector. If it is invalid, don't add anything to Ops. If hasMemory is + /// true it means one of the asm constraint of the inline asm instruction + /// being processed is 'm'. + void LowerAsmOperandForConstraint(SDValue Op, + std::string &Constraint, + std::vector<SDValue> &Ops, + SelectionDAG &DAG) const override; + + unsigned + getInlineAsmMemConstraint(StringRef ConstraintCode) const override { + if (ConstraintCode == "R") + return InlineAsm::Constraint_R; + else if (ConstraintCode == "ZC") + return InlineAsm::Constraint_ZC; + return TargetLowering::getInlineAsmMemConstraint(ConstraintCode); + } + + bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, + Type *Ty, unsigned AS) const override; + + bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override; + + EVT getOptimalMemOpType(uint64_t Size, unsigned DstAlign, + unsigned SrcAlign, + bool IsMemset, bool ZeroMemset, + bool MemcpyStrSrc, + MachineFunction &MF) const override; + + /// isFPImmLegal - Returns true if the target can instruction select the + /// specified FP immediate natively. If false, the legalizer will + /// materialize the FP immediate as a load from a constant pool. + bool isFPImmLegal(const APFloat &Imm, EVT VT) const override; + + unsigned getJumpTableEncoding() const override; + bool useSoftFloat() const override; + + /// Emit a sign-extension using sll/sra, seb, or seh appropriately. + MachineBasicBlock *emitSignExtendToI32InReg(MachineInstr *MI, + MachineBasicBlock *BB, + unsigned Size, unsigned DstReg, + unsigned SrcRec) const; + + MachineBasicBlock *emitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB, + unsigned Size, unsigned BinOpcode, bool Nand = false) const; + MachineBasicBlock *emitAtomicBinaryPartword(MachineInstr *MI, + MachineBasicBlock *BB, unsigned Size, unsigned BinOpcode, + bool Nand = false) const; + MachineBasicBlock *emitAtomicCmpSwap(MachineInstr *MI, + MachineBasicBlock *BB, unsigned Size) const; + MachineBasicBlock *emitAtomicCmpSwapPartword(MachineInstr *MI, + MachineBasicBlock *BB, unsigned Size) const; + MachineBasicBlock *emitSEL_D(MachineInstr *MI, MachineBasicBlock *BB) const; + MachineBasicBlock *emitPseudoSELECT(MachineInstr *MI, + MachineBasicBlock *BB, bool isFPCmp, + unsigned Opc) const; + }; + + /// Create MipsTargetLowering objects. + const MipsTargetLowering * + createMips16TargetLowering(const MipsTargetMachine &TM, + const MipsSubtarget &STI); + const MipsTargetLowering * + createMipsSETargetLowering(const MipsTargetMachine &TM, + const MipsSubtarget &STI); + + namespace Mips { + FastISel *createFastISel(FunctionLoweringInfo &funcInfo, + const TargetLibraryInfo *libInfo); + } +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrFPU.td b/contrib/llvm/lib/Target/Mips/MipsInstrFPU.td new file mode 100644 index 0000000..377260f --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsInstrFPU.td @@ -0,0 +1,618 @@ +//===-- MipsInstrFPU.td - Mips FPU Instruction Information -*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the Mips FPU instruction set. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Floating Point Instructions +// ------------------------ +// * 64bit fp: +// - 32 64-bit registers (default mode) +// - 16 even 32-bit registers (32-bit compatible mode) for +// single and double access. +// * 32bit fp: +// - 16 even 32-bit registers - single and double (aliased) +// - 32 32-bit registers (within single-only mode) +//===----------------------------------------------------------------------===// + +// Floating Point Compare and Branch +def SDT_MipsFPBrcond : SDTypeProfile<0, 3, [SDTCisInt<0>, + SDTCisVT<1, i32>, + SDTCisVT<2, OtherVT>]>; +def SDT_MipsFPCmp : SDTypeProfile<0, 3, [SDTCisSameAs<0, 1>, SDTCisFP<1>, + SDTCisVT<2, i32>]>; +def SDT_MipsCMovFP : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, SDTCisVT<2, i32>, + SDTCisSameAs<1, 3>]>; +def SDT_MipsTruncIntFP : SDTypeProfile<1, 1, [SDTCisFP<0>, SDTCisFP<1>]>; +def SDT_MipsBuildPairF64 : SDTypeProfile<1, 2, [SDTCisVT<0, f64>, + SDTCisVT<1, i32>, + SDTCisSameAs<1, 2>]>; +def SDT_MipsExtractElementF64 : SDTypeProfile<1, 2, [SDTCisVT<0, i32>, + SDTCisVT<1, f64>, + SDTCisVT<2, i32>]>; + +def MipsFPCmp : SDNode<"MipsISD::FPCmp", SDT_MipsFPCmp, [SDNPOutGlue]>; +def MipsCMovFP_T : SDNode<"MipsISD::CMovFP_T", SDT_MipsCMovFP, [SDNPInGlue]>; +def MipsCMovFP_F : SDNode<"MipsISD::CMovFP_F", SDT_MipsCMovFP, [SDNPInGlue]>; +def MipsFPBrcond : SDNode<"MipsISD::FPBrcond", SDT_MipsFPBrcond, + [SDNPHasChain, SDNPOptInGlue]>; +def MipsTruncIntFP : SDNode<"MipsISD::TruncIntFP", SDT_MipsTruncIntFP>; +def MipsBuildPairF64 : SDNode<"MipsISD::BuildPairF64", SDT_MipsBuildPairF64>; +def MipsExtractElementF64 : SDNode<"MipsISD::ExtractElementF64", + SDT_MipsExtractElementF64>; + +// Operand for printing out a condition code. +let PrintMethod = "printFCCOperand", DecoderMethod = "DecodeCondCode" in + def condcode : Operand<i32>; + +//===----------------------------------------------------------------------===// +// Feature predicates. +//===----------------------------------------------------------------------===// + +def IsFP64bit : Predicate<"Subtarget->isFP64bit()">, + AssemblerPredicate<"FeatureFP64Bit">; +def NotFP64bit : Predicate<"!Subtarget->isFP64bit()">, + AssemblerPredicate<"!FeatureFP64Bit">; +def IsSingleFloat : Predicate<"Subtarget->isSingleFloat()">, + AssemblerPredicate<"FeatureSingleFloat">; +def IsNotSingleFloat : Predicate<"!Subtarget->isSingleFloat()">, + AssemblerPredicate<"!FeatureSingleFloat">; +def IsNotSoftFloat : Predicate<"!Subtarget->useSoftFloat()">, + AssemblerPredicate<"!FeatureSoftFloat">; + +//===----------------------------------------------------------------------===// +// Mips FGR size adjectives. +// They are mutually exclusive. +//===----------------------------------------------------------------------===// + +class FGR_32 { list<Predicate> FGRPredicates = [NotFP64bit]; } +class FGR_64 { list<Predicate> FGRPredicates = [IsFP64bit]; } +class HARDFLOAT { list<Predicate> HardFloatPredicate = [IsNotSoftFloat]; } + +//===----------------------------------------------------------------------===// + +// FP immediate patterns. +def fpimm0 : PatLeaf<(fpimm), [{ + return N->isExactlyValue(+0.0); +}]>; + +def fpimm0neg : PatLeaf<(fpimm), [{ + return N->isExactlyValue(-0.0); +}]>; + +//===----------------------------------------------------------------------===// +// Instruction Class Templates +// +// A set of multiclasses is used to address the register usage. +// +// S32 - single precision in 16 32bit even fp registers +// single precision in 32 32bit fp registers in SingleOnly mode +// S64 - single precision in 32 64bit fp registers (In64BitMode) +// D32 - double precision in 16 32bit even fp registers +// D64 - double precision in 32 64bit fp registers (In64BitMode) +// +// Only S32 and D32 are supported right now. +//===----------------------------------------------------------------------===// +class ADDS_FT<string opstr, RegisterOperand RC, InstrItinClass Itin, bit IsComm, + SDPatternOperator OpNode= null_frag> : + InstSE<(outs RC:$fd), (ins RC:$fs, RC:$ft), + !strconcat(opstr, "\t$fd, $fs, $ft"), + [(set RC:$fd, (OpNode RC:$fs, RC:$ft))], Itin, FrmFR, opstr>, + HARDFLOAT { + let isCommutable = IsComm; +} + +multiclass ADDS_M<string opstr, InstrItinClass Itin, bit IsComm, + SDPatternOperator OpNode = null_frag> { + def _D32 : MMRel, ADDS_FT<opstr, AFGR64Opnd, Itin, IsComm, OpNode>, FGR_32; + def _D64 : ADDS_FT<opstr, FGR64Opnd, Itin, IsComm, OpNode>, FGR_64 { + string DecoderNamespace = "Mips64"; + } +} + +class ABSS_FT<string opstr, RegisterOperand DstRC, RegisterOperand SrcRC, + InstrItinClass Itin, SDPatternOperator OpNode= null_frag> : + InstSE<(outs DstRC:$fd), (ins SrcRC:$fs), !strconcat(opstr, "\t$fd, $fs"), + [(set DstRC:$fd, (OpNode SrcRC:$fs))], Itin, FrmFR, opstr>, + HARDFLOAT, + NeverHasSideEffects; + +multiclass ABSS_M<string opstr, InstrItinClass Itin, + SDPatternOperator OpNode= null_frag> { + def _D32 : MMRel, ABSS_FT<opstr, AFGR64Opnd, AFGR64Opnd, Itin, OpNode>, + FGR_32; + def _D64 : ABSS_FT<opstr, FGR64Opnd, FGR64Opnd, Itin, OpNode>, FGR_64 { + string DecoderNamespace = "Mips64"; + } +} + +multiclass ROUND_M<string opstr, InstrItinClass Itin> { + def _D32 : MMRel, ABSS_FT<opstr, FGR32Opnd, AFGR64Opnd, Itin>, FGR_32; + def _D64 : StdMMR6Rel, ABSS_FT<opstr, FGR32Opnd, FGR64Opnd, Itin>, FGR_64 { + let DecoderNamespace = "Mips64"; + } +} + +class MFC1_FT<string opstr, RegisterOperand DstRC, RegisterOperand SrcRC, + InstrItinClass Itin, SDPatternOperator OpNode= null_frag> : + InstSE<(outs DstRC:$rt), (ins SrcRC:$fs), !strconcat(opstr, "\t$rt, $fs"), + [(set DstRC:$rt, (OpNode SrcRC:$fs))], Itin, FrmFR, opstr>, HARDFLOAT; + +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, opstr>, HARDFLOAT; + +class MTC1_64_FT<string opstr, RegisterOperand DstRC, RegisterOperand SrcRC, + InstrItinClass Itin> : + InstSE<(outs DstRC:$fs), (ins DstRC:$fs_in, SrcRC:$rt), + !strconcat(opstr, "\t$rt, $fs"), [], Itin, FrmFR, opstr>, HARDFLOAT { + // $fs_in is part of a white lie to work around a widespread bug in the FPU + // implementation. See expandBuildPairF64 for details. + let Constraints = "$fs = $fs_in"; +} + +class LW_FT<string opstr, RegisterOperand RC, InstrItinClass Itin, + SDPatternOperator OpNode= null_frag> : + InstSE<(outs RC:$rt), (ins mem:$addr), !strconcat(opstr, "\t$rt, $addr"), + [(set RC:$rt, (OpNode addrDefault:$addr))], Itin, FrmFI, opstr>, + HARDFLOAT { + let DecoderMethod = "DecodeFMem"; + let mayLoad = 1; +} + +class SW_FT<string opstr, RegisterOperand RC, InstrItinClass Itin, + SDPatternOperator OpNode= null_frag> : + InstSE<(outs), (ins RC:$rt, mem:$addr), !strconcat(opstr, "\t$rt, $addr"), + [(OpNode RC:$rt, addrDefault:$addr)], Itin, FrmFI, opstr>, HARDFLOAT { + let DecoderMethod = "DecodeFMem"; + let mayStore = 1; +} + +class MADDS_FT<string opstr, RegisterOperand RC, InstrItinClass Itin, + SDPatternOperator OpNode = null_frag> : + InstSE<(outs RC:$fd), (ins RC:$fr, RC:$fs, RC:$ft), + !strconcat(opstr, "\t$fd, $fr, $fs, $ft"), + [(set RC:$fd, (OpNode (fmul RC:$fs, RC:$ft), RC:$fr))], Itin, + FrmFR, opstr>, HARDFLOAT; + +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, opstr>, HARDFLOAT; + +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, opstr>, HARDFLOAT { + let AddedComplexity = 20; +} + +class SWXC1_FT<string opstr, RegisterOperand DRC, + InstrItinClass Itin, SDPatternOperator OpNode = null_frag> : + InstSE<(outs), (ins DRC:$fs, PtrRC:$base, PtrRC:$index), + !strconcat(opstr, "\t$fs, ${index}(${base})"), + [(OpNode DRC:$fs, (add iPTR:$base, iPTR:$index))], Itin, + FrmFI, opstr>, HARDFLOAT { + let AddedComplexity = 20; +} + +class BC1F_FT<string opstr, DAGOperand opnd, InstrItinClass Itin, + SDPatternOperator Op = null_frag, bit DelaySlot = 1> : + InstSE<(outs), (ins FCCRegsOpnd:$fcc, opnd:$offset), + !strconcat(opstr, "\t$fcc, $offset"), + [(MipsFPBrcond Op, FCCRegsOpnd:$fcc, bb:$offset)], Itin, + FrmFI, opstr>, HARDFLOAT { + let isBranch = 1; + let isTerminator = 1; + let hasDelaySlot = DelaySlot; + let Defs = [AT]; +} + +class CEQS_FT<string typestr, RegisterClass RC, InstrItinClass Itin, + SDPatternOperator OpNode = null_frag> : + InstSE<(outs), (ins RC:$fs, RC:$ft, condcode:$cond), + !strconcat("c.$cond.", typestr, "\t$fs, $ft"), + [(OpNode RC:$fs, RC:$ft, imm:$cond)], Itin, FrmFR, + !strconcat("c.$cond.", typestr)>, HARDFLOAT { + let Defs = [FCC0]; + let isCodeGenOnly = 1; +} + +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"), [], itin, + FrmFR>, HARDFLOAT; + +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>, ISA_MIPS1_NOT_32R6_64R6; +defm D32 : C_COND_M<"d", AFGR64Opnd, 17, II_C_CC_D>, ISA_MIPS1_NOT_32R6_64R6, + FGR_32; +let DecoderNamespace = "Mips64" in +defm D64 : C_COND_M<"d", FGR64Opnd, 17, II_C_CC_D>, ISA_MIPS1_NOT_32R6_64R6, + FGR_64; + +//===----------------------------------------------------------------------===// +// Floating Point Instructions +//===----------------------------------------------------------------------===// +def ROUND_W_S : MMRel, StdMMR6Rel, ABSS_FT<"round.w.s", FGR32Opnd, FGR32Opnd, II_ROUND>, + ABSS_FM<0xc, 16>, ISA_MIPS2; +defm ROUND_W : ROUND_M<"round.w.d", II_ROUND>, ABSS_FM<0xc, 17>, ISA_MIPS2; +def TRUNC_W_S : MMRel, StdMMR6Rel, ABSS_FT<"trunc.w.s", FGR32Opnd, FGR32Opnd, II_TRUNC>, + ABSS_FM<0xd, 16>, ISA_MIPS2; +def CEIL_W_S : MMRel, StdMMR6Rel, ABSS_FT<"ceil.w.s", FGR32Opnd, FGR32Opnd, II_CEIL>, + ABSS_FM<0xe, 16>, ISA_MIPS2; +def FLOOR_W_S : MMRel, StdMMR6Rel, ABSS_FT<"floor.w.s", FGR32Opnd, FGR32Opnd, II_FLOOR>, + ABSS_FM<0xf, 16>, ISA_MIPS2; +def CVT_W_S : MMRel, ABSS_FT<"cvt.w.s", FGR32Opnd, FGR32Opnd, II_CVT>, + ABSS_FM<0x24, 16>; + +defm TRUNC_W : ROUND_M<"trunc.w.d", II_TRUNC>, ABSS_FM<0xd, 17>, ISA_MIPS2; +defm CEIL_W : ROUND_M<"ceil.w.d", II_CEIL>, ABSS_FM<0xe, 17>, ISA_MIPS2; +defm FLOOR_W : ROUND_M<"floor.w.d", II_FLOOR>, ABSS_FM<0xf, 17>, ISA_MIPS2; +defm CVT_W : ROUND_M<"cvt.w.d", II_CVT>, ABSS_FM<0x24, 17>; + +let DecoderNamespace = "Mips64" in { + let AdditionalPredicates = [NotInMicroMips] in { + def ROUND_L_S : ABSS_FT<"round.l.s", FGR64Opnd, FGR32Opnd, II_ROUND>, + ABSS_FM<0x8, 16>, FGR_64; + def ROUND_L_D64 : ABSS_FT<"round.l.d", FGR64Opnd, FGR64Opnd, II_ROUND>, + ABSS_FM<0x8, 17>, FGR_64; + def TRUNC_L_S : ABSS_FT<"trunc.l.s", FGR64Opnd, FGR32Opnd, II_TRUNC>, + ABSS_FM<0x9, 16>, FGR_64; + def TRUNC_L_D64 : ABSS_FT<"trunc.l.d", FGR64Opnd, FGR64Opnd, II_TRUNC>, + ABSS_FM<0x9, 17>, FGR_64; + def CEIL_L_S : ABSS_FT<"ceil.l.s", FGR64Opnd, FGR32Opnd, II_CEIL>, + ABSS_FM<0xa, 16>, FGR_64; + def CEIL_L_D64 : ABSS_FT<"ceil.l.d", FGR64Opnd, FGR64Opnd, II_CEIL>, + ABSS_FM<0xa, 17>, FGR_64; + def FLOOR_L_S : ABSS_FT<"floor.l.s", FGR64Opnd, FGR32Opnd, II_FLOOR>, + ABSS_FM<0xb, 16>, FGR_64; + def FLOOR_L_D64 : ABSS_FT<"floor.l.d", FGR64Opnd, FGR64Opnd, II_FLOOR>, + ABSS_FM<0xb, 17>, FGR_64; + } +} + +def CVT_S_W : MMRel, ABSS_FT<"cvt.s.w", FGR32Opnd, FGR32Opnd, II_CVT>, + ABSS_FM<0x20, 20>; +let AdditionalPredicates = [NotInMicroMips] in{ + def CVT_L_S : MMRel, ABSS_FT<"cvt.l.s", FGR64Opnd, FGR32Opnd, II_CVT>, + ABSS_FM<0x25, 16>, INSN_MIPS3_32R2; + def CVT_L_D64: MMRel, ABSS_FT<"cvt.l.d", FGR64Opnd, FGR64Opnd, II_CVT>, + ABSS_FM<0x25, 17>, INSN_MIPS3_32R2; +} + +def CVT_S_D32 : MMRel, ABSS_FT<"cvt.s.d", FGR32Opnd, AFGR64Opnd, II_CVT>, + ABSS_FM<0x20, 17>, FGR_32; +def CVT_D32_W : MMRel, ABSS_FT<"cvt.d.w", AFGR64Opnd, FGR32Opnd, II_CVT>, + ABSS_FM<0x21, 20>, FGR_32; +def CVT_D32_S : MMRel, ABSS_FT<"cvt.d.s", AFGR64Opnd, FGR32Opnd, II_CVT>, + ABSS_FM<0x21, 16>, FGR_32; + +let DecoderNamespace = "Mips64" in { + def CVT_S_D64 : ABSS_FT<"cvt.s.d", FGR32Opnd, FGR64Opnd, II_CVT>, + ABSS_FM<0x20, 17>, FGR_64; + let AdditionalPredicates = [NotInMicroMips] in{ + def CVT_S_L : ABSS_FT<"cvt.s.l", FGR32Opnd, FGR64Opnd, II_CVT>, + ABSS_FM<0x20, 21>, FGR_64; + } + def CVT_D64_W : ABSS_FT<"cvt.d.w", FGR64Opnd, FGR32Opnd, II_CVT>, + ABSS_FM<0x21, 20>, FGR_64; + def CVT_D64_S : ABSS_FT<"cvt.d.s", FGR64Opnd, FGR32Opnd, II_CVT>, + ABSS_FM<0x21, 16>, FGR_64; + def CVT_D64_L : ABSS_FT<"cvt.d.l", FGR64Opnd, FGR64Opnd, II_CVT>, + ABSS_FM<0x21, 21>, FGR_64; +} + +let isPseudo = 1, isCodeGenOnly = 1 in { + def PseudoCVT_S_W : ABSS_FT<"", FGR32Opnd, GPR32Opnd, 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>; +} + +def FABS_S : MMRel, ABSS_FT<"abs.s", FGR32Opnd, FGR32Opnd, II_ABS, fabs>, + ABSS_FM<0x5, 16>; +def FNEG_S : MMRel, ABSS_FT<"neg.s", FGR32Opnd, FGR32Opnd, II_NEG, fneg>, + ABSS_FM<0x7, 16>; +defm FABS : ABSS_M<"abs.d", II_ABS, fabs>, ABSS_FM<0x5, 17>; +defm FNEG : ABSS_M<"neg.d", II_NEG, fneg>, ABSS_FM<0x7, 17>; + +def FSQRT_S : MMRel, StdMMR6Rel, ABSS_FT<"sqrt.s", FGR32Opnd, FGR32Opnd, + II_SQRT_S, fsqrt>, ABSS_FM<0x4, 16>, ISA_MIPS2; +defm FSQRT : ABSS_M<"sqrt.d", II_SQRT_D, fsqrt>, ABSS_FM<0x4, 17>, ISA_MIPS2; + +// The odd-numbered registers are only referenced when doing loads, +// stores, and moves between floating-point and integer registers. +// When defining instructions, we reference all 32-bit registers, +// regardless of register aliasing. + +/// Move Control Registers From/To CPU Registers +def CFC1 : MMRel, MFC1_FT<"cfc1", GPR32Opnd, CCROpnd, II_CFC1>, MFC1_FM<2>; +def CTC1 : MMRel, MTC1_FT<"ctc1", CCROpnd, GPR32Opnd, II_CTC1>, MFC1_FM<6>; +def MFC1 : MMRel, MFC1_FT<"mfc1", GPR32Opnd, FGR32Opnd, II_MFC1, + bitconvert>, MFC1_FM<0>; +def MTC1 : MMRel, MTC1_FT<"mtc1", FGR32Opnd, GPR32Opnd, II_MTC1, + bitconvert>, MFC1_FM<4>; +def MFHC1_D32 : MMRel, MFC1_FT<"mfhc1", GPR32Opnd, AFGR64Opnd, II_MFHC1>, + MFC1_FM<3>, ISA_MIPS32R2, FGR_32; +def MFHC1_D64 : MFC1_FT<"mfhc1", GPR32Opnd, FGR64Opnd, II_MFHC1>, + MFC1_FM<3>, ISA_MIPS32R2, FGR_64 { + let DecoderNamespace = "Mips64"; +} +def MTHC1_D32 : MMRel, MTC1_64_FT<"mthc1", AFGR64Opnd, GPR32Opnd, II_MTHC1>, + MFC1_FM<7>, ISA_MIPS32R2, FGR_32; +def MTHC1_D64 : MTC1_64_FT<"mthc1", FGR64Opnd, GPR32Opnd, II_MTHC1>, + MFC1_FM<7>, ISA_MIPS32R2, FGR_64 { + let DecoderNamespace = "Mips64"; +} +def DMFC1 : MFC1_FT<"dmfc1", GPR64Opnd, FGR64Opnd, II_DMFC1, + bitconvert>, MFC1_FM<1>, ISA_MIPS3; +def DMTC1 : MTC1_FT<"dmtc1", FGR64Opnd, GPR64Opnd, II_DMTC1, + bitconvert>, MFC1_FM<5>, ISA_MIPS3; + +def FMOV_S : MMRel, ABSS_FT<"mov.s", FGR32Opnd, FGR32Opnd, II_MOV_S>, + ABSS_FM<0x6, 16>; +def FMOV_D32 : MMRel, ABSS_FT<"mov.d", AFGR64Opnd, AFGR64Opnd, II_MOV_D>, + ABSS_FM<0x6, 17>, FGR_32; +def FMOV_D64 : ABSS_FT<"mov.d", FGR64Opnd, FGR64Opnd, II_MOV_D>, + ABSS_FM<0x6, 17>, FGR_64 { + let DecoderNamespace = "Mips64"; +} + +/// Floating Point Memory Instructions +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 DecoderNamespace = "Mips64" in { + def LDC164 : LW_FT<"ldc1", FGR64Opnd, II_LDC1, load>, LW_FM<0x35>, ISA_MIPS2, + FGR_64; + def SDC164 : SW_FT<"sdc1", FGR64Opnd, II_SDC1, store>, LW_FM<0x3d>, ISA_MIPS2, + FGR_64; +} + +def LDC1 : MMRel, LW_FT<"ldc1", AFGR64Opnd, II_LDC1, load>, LW_FM<0x35>, + ISA_MIPS2, FGR_32; +def SDC1 : MMRel, SW_FT<"sdc1", AFGR64Opnd, II_SDC1, store>, LW_FM<0x3d>, + ISA_MIPS2, FGR_32; + +// Indexed loads and stores. +// Base register + offset register addressing mode (indicated by "x" in the +// instruction mnemonic) is disallowed under NaCl. +let AdditionalPredicates = [IsNotNaCl] in { + def LWXC1 : MMRel, LWXC1_FT<"lwxc1", FGR32Opnd, II_LWXC1, load>, LWXC1_FM<0>, + INSN_MIPS4_32R2_NOT_32R6_64R6; + def SWXC1 : MMRel, SWXC1_FT<"swxc1", FGR32Opnd, II_SWXC1, store>, SWXC1_FM<8>, + INSN_MIPS4_32R2_NOT_32R6_64R6; +} + +let AdditionalPredicates = [NotInMicroMips, IsNotNaCl] in { + def LDXC1 : LWXC1_FT<"ldxc1", AFGR64Opnd, II_LDXC1, load>, LWXC1_FM<1>, + INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_32; + def SDXC1 : SWXC1_FT<"sdxc1", AFGR64Opnd, II_SDXC1, store>, SWXC1_FM<9>, + INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_32; +} + +let DecoderNamespace="Mips64" in { + def LDXC164 : LWXC1_FT<"ldxc1", FGR64Opnd, II_LDXC1, load>, LWXC1_FM<1>, + INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_64; + def SDXC164 : SWXC1_FT<"sdxc1", FGR64Opnd, II_SDXC1, store>, SWXC1_FM<9>, + INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_64; +} + +// Load/store doubleword indexed unaligned. +let AdditionalPredicates = [IsNotNaCl] in { + def LUXC1 : MMRel, LWXC1_FT<"luxc1", AFGR64Opnd, II_LUXC1>, LWXC1_FM<0x5>, + INSN_MIPS5_32R2_NOT_32R6_64R6, FGR_32; + def SUXC1 : MMRel, SWXC1_FT<"suxc1", AFGR64Opnd, II_SUXC1>, SWXC1_FM<0xd>, + INSN_MIPS5_32R2_NOT_32R6_64R6, FGR_32; +} + +let DecoderNamespace="Mips64" in { + def LUXC164 : LWXC1_FT<"luxc1", FGR64Opnd, II_LUXC1>, LWXC1_FM<0x5>, + INSN_MIPS5_32R2_NOT_32R6_64R6, FGR_64; + def SUXC164 : SWXC1_FT<"suxc1", FGR64Opnd, II_SUXC1>, SWXC1_FM<0xd>, + INSN_MIPS5_32R2_NOT_32R6_64R6, FGR_64; +} + +/// Floating-point Aritmetic +def FADD_S : MMRel, ADDS_FT<"add.s", FGR32Opnd, II_ADD_S, 1, fadd>, + ADDS_FM<0x00, 16>; +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", 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", 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", II_SUB_D, 0, fsub>, ADDS_FM<0x01, 17>; + +def MADD_S : MMRel, MADDS_FT<"madd.s", FGR32Opnd, II_MADD_S, fadd>, + MADDS_FM<4, 0>, INSN_MIPS4_32R2_NOT_32R6_64R6; +def MSUB_S : MMRel, MADDS_FT<"msub.s", FGR32Opnd, II_MSUB_S, fsub>, + MADDS_FM<5, 0>, INSN_MIPS4_32R2_NOT_32R6_64R6; + +let AdditionalPredicates = [NoNaNsFPMath] in { + def NMADD_S : MMRel, NMADDS_FT<"nmadd.s", FGR32Opnd, II_NMADD_S, fadd>, + MADDS_FM<6, 0>, INSN_MIPS4_32R2_NOT_32R6_64R6; + def NMSUB_S : MMRel, NMADDS_FT<"nmsub.s", FGR32Opnd, II_NMSUB_S, fsub>, + MADDS_FM<7, 0>, INSN_MIPS4_32R2_NOT_32R6_64R6; +} + +def MADD_D32 : MMRel, MADDS_FT<"madd.d", AFGR64Opnd, II_MADD_D, fadd>, + MADDS_FM<4, 1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_32; +def MSUB_D32 : MMRel, MADDS_FT<"msub.d", AFGR64Opnd, II_MSUB_D, fsub>, + MADDS_FM<5, 1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_32; + +let AdditionalPredicates = [NoNaNsFPMath] in { + def NMADD_D32 : MMRel, NMADDS_FT<"nmadd.d", AFGR64Opnd, II_NMADD_D, fadd>, + MADDS_FM<6, 1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_32; + def NMSUB_D32 : MMRel, NMADDS_FT<"nmsub.d", AFGR64Opnd, II_NMSUB_D, fsub>, + MADDS_FM<7, 1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_32; +} + +let DecoderNamespace = "Mips64" in { + def MADD_D64 : MADDS_FT<"madd.d", FGR64Opnd, II_MADD_D, fadd>, + MADDS_FM<4, 1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_64; + def MSUB_D64 : MADDS_FT<"msub.d", FGR64Opnd, II_MSUB_D, fsub>, + MADDS_FM<5, 1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_64; +} + +let AdditionalPredicates = [NoNaNsFPMath], + DecoderNamespace = "Mips64" in { + def NMADD_D64 : NMADDS_FT<"nmadd.d", FGR64Opnd, II_NMADD_D, fadd>, + MADDS_FM<6, 1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_64; + def NMSUB_D64 : NMADDS_FT<"nmsub.d", FGR64Opnd, II_NMSUB_D, fsub>, + MADDS_FM<7, 1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_64; +} + +//===----------------------------------------------------------------------===// +// Floating Point Branch Codes +//===----------------------------------------------------------------------===// +// Mips branch codes. These correspond to condcode in MipsInstrInfo.h. +// They must be kept in synch. +def MIPS_BRANCH_F : PatLeaf<(i32 0)>; +def MIPS_BRANCH_T : PatLeaf<(i32 1)>; + +def BC1F : MMRel, BC1F_FT<"bc1f", brtarget, II_BC1F, MIPS_BRANCH_F>, + BC1F_FM<0, 0>, ISA_MIPS1_NOT_32R6_64R6; +def BC1FL : MMRel, BC1F_FT<"bc1fl", brtarget, II_BC1FL, MIPS_BRANCH_F, 0>, + BC1F_FM<1, 0>, ISA_MIPS2_NOT_32R6_64R6; +def BC1T : MMRel, BC1F_FT<"bc1t", brtarget, II_BC1T, MIPS_BRANCH_T>, + BC1F_FM<0, 1>, ISA_MIPS1_NOT_32R6_64R6; +def BC1TL : MMRel, BC1F_FT<"bc1tl", brtarget, II_BC1TL, MIPS_BRANCH_T, 0>, + BC1F_FM<1, 1>, ISA_MIPS2_NOT_32R6_64R6; + +/// Floating Point Compare +def FCMP_S32 : MMRel, CEQS_FT<"s", FGR32, II_C_CC_S, MipsFPCmp>, CEQS_FM<16>, + ISA_MIPS1_NOT_32R6_64R6; +def FCMP_D32 : MMRel, CEQS_FT<"d", AFGR64, II_C_CC_D, MipsFPCmp>, CEQS_FM<17>, + ISA_MIPS1_NOT_32R6_64R6, FGR_32; +let DecoderNamespace = "Mips64" in +def FCMP_D64 : CEQS_FT<"d", FGR64, II_C_CC_D, MipsFPCmp>, CEQS_FM<17>, + ISA_MIPS1_NOT_32R6_64R6, FGR_64; + +//===----------------------------------------------------------------------===// +// Floating Point Pseudo-Instructions +//===----------------------------------------------------------------------===// + +// This pseudo instr gets expanded into 2 mtc1 instrs after register +// allocation. +class BuildPairF64Base<RegisterOperand RO> : + PseudoSE<(outs RO:$dst), (ins GPR32Opnd:$lo, GPR32Opnd:$hi), + [(set RO:$dst, (MipsBuildPairF64 GPR32Opnd:$lo, GPR32Opnd:$hi))]>; + +def BuildPairF64 : BuildPairF64Base<AFGR64Opnd>, FGR_32, HARDFLOAT; +def BuildPairF64_64 : BuildPairF64Base<FGR64Opnd>, FGR_64, HARDFLOAT; + +// This pseudo instr gets expanded into 2 mfc1 instrs after register +// allocation. +// if n is 0, lower part of src is extracted. +// if n is 1, higher part of src is extracted. +class ExtractElementF64Base<RegisterOperand RO> : + PseudoSE<(outs GPR32Opnd:$dst), (ins RO:$src, i32imm:$n), + [(set GPR32Opnd:$dst, (MipsExtractElementF64 RO:$src, imm:$n))]>; + +def ExtractElementF64 : ExtractElementF64Base<AFGR64Opnd>, FGR_32, HARDFLOAT; +def ExtractElementF64_64 : ExtractElementF64Base<FGR64Opnd>, FGR_64, HARDFLOAT; + +//===----------------------------------------------------------------------===// +// InstAliases. +//===----------------------------------------------------------------------===// +def : MipsInstAlias<"bc1t $offset", (BC1T FCC0, brtarget:$offset)>, + ISA_MIPS1_NOT_32R6_64R6, HARDFLOAT; +def : MipsInstAlias<"bc1tl $offset", (BC1TL FCC0, brtarget:$offset)>, + ISA_MIPS2_NOT_32R6_64R6, HARDFLOAT; +def : MipsInstAlias<"bc1f $offset", (BC1F FCC0, brtarget:$offset)>, + ISA_MIPS1_NOT_32R6_64R6, HARDFLOAT; +def : MipsInstAlias<"bc1fl $offset", (BC1FL FCC0, brtarget:$offset)>, + ISA_MIPS2_NOT_32R6_64R6, HARDFLOAT; + +//===----------------------------------------------------------------------===// +// Floating Point Patterns +//===----------------------------------------------------------------------===// +def : MipsPat<(f32 fpimm0), (MTC1 ZERO)>; +def : MipsPat<(f32 fpimm0neg), (FNEG_S (MTC1 ZERO))>; + +def : MipsPat<(f32 (sint_to_fp GPR32Opnd:$src)), + (PseudoCVT_S_W GPR32Opnd:$src)>; +def : MipsPat<(MipsTruncIntFP FGR32Opnd:$src), + (TRUNC_W_S FGR32Opnd:$src)>; + +def : MipsPat<(f64 (sint_to_fp GPR32Opnd:$src)), + (PseudoCVT_D32_W GPR32Opnd:$src)>, FGR_32; +def : MipsPat<(MipsTruncIntFP AFGR64Opnd:$src), + (TRUNC_W_D32 AFGR64Opnd:$src)>, FGR_32; +def : MipsPat<(f32 (fround AFGR64Opnd:$src)), + (CVT_S_D32 AFGR64Opnd:$src)>, FGR_32; +def : MipsPat<(f64 (fextend FGR32Opnd:$src)), + (CVT_D32_S FGR32Opnd:$src)>, FGR_32; + +def : MipsPat<(f64 fpimm0), (DMTC1 ZERO_64)>, FGR_64; +def : MipsPat<(f64 fpimm0neg), (FNEG_D64 (DMTC1 ZERO_64))>, FGR_64; + +def : MipsPat<(f64 (sint_to_fp GPR32Opnd:$src)), + (PseudoCVT_D64_W GPR32Opnd:$src)>, FGR_64; +def : MipsPat<(f32 (sint_to_fp GPR64Opnd:$src)), + (EXTRACT_SUBREG (PseudoCVT_S_L GPR64Opnd:$src), sub_lo)>, FGR_64; +def : MipsPat<(f64 (sint_to_fp GPR64Opnd:$src)), + (PseudoCVT_D64_L GPR64Opnd:$src)>, FGR_64; + +def : MipsPat<(MipsTruncIntFP FGR64Opnd:$src), + (TRUNC_W_D64 FGR64Opnd:$src)>, FGR_64; +def : MipsPat<(MipsTruncIntFP FGR32Opnd:$src), + (TRUNC_L_S FGR32Opnd:$src)>, FGR_64; +def : MipsPat<(MipsTruncIntFP FGR64Opnd:$src), + (TRUNC_L_D64 FGR64Opnd:$src)>, FGR_64; + +def : MipsPat<(f32 (fround FGR64Opnd:$src)), + (CVT_S_D64 FGR64Opnd:$src)>, FGR_64; +def : MipsPat<(f64 (fextend FGR32Opnd:$src)), + (CVT_D64_S FGR32Opnd:$src)>, FGR_64; + +// Patterns for loads/stores with a reg+imm operand. +let AddedComplexity = 40 in { + def : LoadRegImmPat<LWC1, f32, load>; + def : StoreRegImmPat<SWC1, f32>; + + def : LoadRegImmPat<LDC164, f64, load>, FGR_64; + def : StoreRegImmPat<SDC164, f64>, FGR_64; + + def : LoadRegImmPat<LDC1, f64, load>, FGR_32; + def : StoreRegImmPat<SDC1, f64>, FGR_32; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrFormats.td b/contrib/llvm/lib/Target/Mips/MipsInstrFormats.td new file mode 100644 index 0000000..45baf27 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsInstrFormats.td @@ -0,0 +1,959 @@ +//===-- MipsInstrFormats.td - Mips Instruction Formats -----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Describe MIPS instructions format +// +// CPU INSTRUCTION FORMATS +// +// opcode - operation code. +// rs - src reg. +// rt - dst reg (on a 2 regs instr) or src reg (on a 3 reg instr). +// rd - dst reg, only used on 3 regs instr. +// shamt - only used on shift instructions, contains the shift amount. +// funct - combined with opcode field give us an operation code. +// +//===----------------------------------------------------------------------===// + +// Format specifies the encoding used by the instruction. This is part of the +// ad-hoc solution used to emit machine instruction encodings by our machine +// code emitter. +class Format<bits<4> val> { + bits<4> Value = val; +} + +def Pseudo : Format<0>; +def FrmR : Format<1>; +def FrmI : Format<2>; +def FrmJ : Format<3>; +def FrmFR : Format<4>; +def FrmFI : Format<5>; +def FrmOther : Format<6>; // Instruction w/ a custom format + +class MMRel; + +def Std2MicroMips : InstrMapping { + let FilterClass = "MMRel"; + // Instructions with the same BaseOpcode and isNVStore values form a row. + let RowFields = ["BaseOpcode"]; + // Instructions with the same predicate sense form a column. + let ColFields = ["Arch"]; + // The key column is the unpredicated instructions. + let KeyCol = ["se"]; + // Value columns are PredSense=true and PredSense=false + let ValueCols = [["se"], ["micromips"]]; +} + +class StdMMR6Rel; + +def Std2MicroMipsR6 : InstrMapping { + let FilterClass = "StdMMR6Rel"; + // Instructions with the same BaseOpcode and isNVStore values form a row. + let RowFields = ["BaseOpcode"]; + // Instructions with the same predicate sense form a column. + let ColFields = ["Arch"]; + // The key column is the unpredicated instructions. + let KeyCol = ["se"]; + // Value columns are PredSense=true and PredSense=false + let ValueCols = [["se"], ["micromipsr6"]]; +} + +class StdArch { + string Arch = "se"; +} + +// Generic Mips Format +class MipsInst<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin, Format f>: Instruction +{ + field bits<32> Inst; + Format Form = f; + + let Namespace = "Mips"; + + let Size = 4; + + bits<6> Opcode = 0; + + // Top 6 bits are the 'opcode' field + let Inst{31-26} = Opcode; + + let OutOperandList = outs; + let InOperandList = ins; + + let AsmString = asmstr; + let Pattern = pattern; + let Itinerary = itin; + + // + // Attributes specific to Mips instructions... + // + bits<4> FormBits = Form.Value; + + // TSFlags layout should be kept in sync with MipsInstrInfo.h. + let TSFlags{3-0} = FormBits; + + let DecoderNamespace = "Mips"; + + field bits<32> SoftFail = 0; +} + +// Mips32/64 Instruction Format +class InstSE<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin, Format f, string opstr = ""> : + MipsInst<outs, ins, asmstr, pattern, itin, f>, PredicateControl { + let EncodingPredicates = [HasStdEnc]; + string BaseOpcode = opstr; + string Arch; +} + +// Mips Pseudo Instructions Format +class MipsPseudo<dag outs, dag ins, list<dag> pattern, + InstrItinClass itin = IIPseudo> : + MipsInst<outs, ins, "", pattern, itin, Pseudo> { + let isCodeGenOnly = 1; + let isPseudo = 1; +} + +// Mips32/64 Pseudo Instruction Format +class PseudoSE<dag outs, dag ins, list<dag> pattern, + InstrItinClass itin = IIPseudo> : + MipsPseudo<outs, ins, pattern, itin>, PredicateControl { + let EncodingPredicates = [HasStdEnc]; +} + +// Pseudo-instructions for alternate assembly syntax (never used by codegen). +// These are aliases that require C++ handling to convert to the target +// instruction, while InstAliases can be handled directly by tblgen. +class MipsAsmPseudoInst<dag outs, dag ins, string asmstr>: + MipsInst<outs, ins, asmstr, [], IIPseudo, Pseudo>, PredicateControl { + let isPseudo = 1; + let Pattern = []; +} +//===----------------------------------------------------------------------===// +// Format R instruction class in Mips : <|opcode|rs|rt|rd|shamt|funct|> +//===----------------------------------------------------------------------===// + +class FR<bits<6> op, bits<6> _funct, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + InstSE<outs, ins, asmstr, pattern, itin, FrmR> +{ + bits<5> rd; + bits<5> rs; + bits<5> rt; + bits<5> shamt; + bits<6> funct; + + let Opcode = op; + let funct = _funct; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = shamt; + let Inst{5-0} = funct; +} + +//===----------------------------------------------------------------------===// +// Format I instruction class in Mips : <|opcode|rs|rt|immediate|> +//===----------------------------------------------------------------------===// + +class FI<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin>: InstSE<outs, ins, asmstr, pattern, itin, FrmI> +{ + bits<5> rt; + bits<5> rs; + bits<16> imm16; + + let Opcode = op; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-0} = imm16; +} + +class BranchBase<bits<6> op, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + InstSE<outs, ins, asmstr, pattern, itin, FrmI> +{ + bits<5> rs; + bits<5> rt; + bits<16> imm16; + + let Opcode = op; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-0} = imm16; +} + +//===----------------------------------------------------------------------===// +// Format J instruction class in Mips : <|opcode|address|> +//===----------------------------------------------------------------------===// + +class FJ<bits<6> op> : StdArch +{ + bits<26> target; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-0} = target; +} + +//===----------------------------------------------------------------------===// +// MFC instruction class in Mips : <|op|mf|rt|rd|0000000|sel|> +//===----------------------------------------------------------------------===// +class MFC3OP_FM<bits<6> op, bits<5> mfmt> +{ + bits<5> rt; + bits<5> rd; + bits<3> sel; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = mfmt; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-3} = 0; + let Inst{2-0} = sel; +} + +class MFC2OP_FM<bits<6> op, bits<5> mfmt> : StdArch { + bits<5> rt; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = mfmt; + let Inst{20-16} = rt; + let Inst{15-0} = imm16; +} + +class ADD_FM<bits<6> op, bits<6> funct> : StdArch { + bits<5> rd; + bits<5> rs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = 0; + let Inst{5-0} = funct; +} + +class ADDI_FM<bits<6> op> : StdArch { + bits<5> rs; + bits<5> rt; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-0} = imm16; +} + +class SRA_FM<bits<6> funct, bit rotate> : StdArch { + bits<5> rd; + bits<5> rt; + bits<5> shamt; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-22} = 0; + let Inst{21} = rotate; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = shamt; + let Inst{5-0} = funct; +} + +class SRLV_FM<bits<6> funct, bit rotate> : StdArch { + bits<5> rd; + bits<5> rt; + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-7} = 0; + let Inst{6} = rotate; + let Inst{5-0} = funct; +} + +class BEQ_FM<bits<6> op> : StdArch { + bits<5> rs; + bits<5> rt; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-0} = offset; +} + +class BGEZ_FM<bits<6> op, bits<5> funct> : StdArch { + bits<5> rs; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rs; + let Inst{20-16} = funct; + let Inst{15-0} = offset; +} + +class BBIT_FM<bits<6> op> : StdArch { + bits<5> rs; + bits<5> p; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rs; + let Inst{20-16} = p; + let Inst{15-0} = offset; +} + +class SLTI_FM<bits<6> op> : StdArch { + bits<5> rt; + bits<5> rs; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-0} = imm16; +} + +class MFLO_FM<bits<6> funct> : StdArch { + bits<5> rd; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-16} = 0; + let Inst{15-11} = rd; + let Inst{10-6} = 0; + let Inst{5-0} = funct; +} + +class MTLO_FM<bits<6> funct> : StdArch { + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rs; + let Inst{20-6} = 0; + let Inst{5-0} = funct; +} + +class SEB_FM<bits<5> funct, bits<6> funct2> : StdArch { + bits<5> rd; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0x1f; + let Inst{25-21} = 0; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = funct; + let Inst{5-0} = funct2; +} + +class CLO_FM<bits<6> funct> : StdArch { + bits<5> rd; + bits<5> rs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0x1c; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = 0; + let Inst{5-0} = funct; + let rt = rd; +} + +class LUI_FM : StdArch { + bits<5> rt; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = 0xf; + let Inst{25-21} = 0; + let Inst{20-16} = rt; + let Inst{15-0} = imm16; +} + +class JALR_FM { + bits<5> rd; + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rs; + let Inst{20-16} = 0; + let Inst{15-11} = rd; + let Inst{10-6} = 0; + let Inst{5-0} = 9; +} + +class BGEZAL_FM<bits<5> funct> : StdArch { + bits<5> rs; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = 1; + let Inst{25-21} = rs; + let Inst{20-16} = funct; + let Inst{15-0} = offset; +} + +class SYNC_FM : StdArch { + bits<5> stype; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{10-6} = stype; + let Inst{5-0} = 0xf; +} + +class SYNCI_FM : StdArch { + // Produced by the mem_simm16 address as reg << 16 | imm (see getMemEncoding). + bits<21> addr; + bits<5> rs = addr{20-16}; + bits<16> offset = addr{15-0}; + + bits<32> Inst; + + let Inst{31-26} = 0b000001; + let Inst{25-21} = rs; + let Inst{20-16} = 0b11111; + let Inst{15-0} = offset; +} + +class MULT_FM<bits<6> op, bits<6> funct> : StdArch { + bits<5> rs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-6} = 0; + let Inst{5-0} = funct; +} + +class EXT_FM<bits<6> funct> : StdArch { + bits<5> rt; + bits<5> rs; + bits<5> pos; + bits<5> size; + + bits<32> Inst; + + let Inst{31-26} = 0x1f; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = size; + let Inst{10-6} = pos; + let Inst{5-0} = funct; +} + +class RDHWR_FM : StdArch { + bits<5> rt; + bits<5> rd; + + bits<32> Inst; + + let Inst{31-26} = 0x1f; + let Inst{25-21} = 0; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = 0; + let Inst{5-0} = 0x3b; +} + +class TEQ_FM<bits<6> funct> : StdArch { + bits<5> rs; + bits<5> rt; + bits<10> code_; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-6} = code_; + let Inst{5-0} = funct; +} + +class TEQI_FM<bits<5> funct> : StdArch { + bits<5> rs; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = 1; + let Inst{25-21} = rs; + let Inst{20-16} = funct; + let Inst{15-0} = imm16; +} + +class WAIT_FM : StdArch { + bits<32> Inst; + + let Inst{31-26} = 0x10; + let Inst{25} = 1; + let Inst{24-6} = 0; + let Inst{5-0} = 0x20; +} + +class EXTS_FM<bits<6> funct> : StdArch { + bits<5> rt; + bits<5> rs; + bits<5> pos; + bits<5> lenm1; + + bits<32> Inst; + + let Inst{31-26} = 0x1c; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = lenm1; + let Inst{10-6} = pos; + let Inst{5-0} = funct; +} + +class MTMR_FM<bits<6> funct> : StdArch { + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0x1c; + let Inst{25-21} = rs; + let Inst{20-6} = 0; + let Inst{5-0} = funct; +} + +class POP_FM<bits<6> funct> : StdArch { + bits<5> rd; + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0x1c; + let Inst{25-21} = rs; + let Inst{20-16} = 0; + let Inst{15-11} = rd; + let Inst{10-6} = 0; + let Inst{5-0} = funct; +} + +class SEQ_FM<bits<6> funct> : StdArch { + bits<5> rd; + bits<5> rs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0x1c; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = 0; + let Inst{5-0} = funct; +} + +class SEQI_FM<bits<6> funct> : StdArch { + bits<5> rs; + bits<5> rt; + bits<10> imm10; + + bits<32> Inst; + + let Inst{31-26} = 0x1c; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-6} = imm10; + let Inst{5-0} = funct; +} + +//===----------------------------------------------------------------------===// +// System calls format <op|code_|funct> +//===----------------------------------------------------------------------===// + +class SYS_FM<bits<6> funct> : StdArch +{ + bits<20> code_; + bits<32> Inst; + let Inst{31-26} = 0x0; + let Inst{25-6} = code_; + let Inst{5-0} = funct; +} + +//===----------------------------------------------------------------------===// +// Break instruction format <op|code_1|funct> +//===----------------------------------------------------------------------===// + +class BRK_FM<bits<6> funct> : StdArch +{ + bits<10> code_1; + bits<10> code_2; + bits<32> Inst; + let Inst{31-26} = 0x0; + let Inst{25-16} = code_1; + let Inst{15-6} = code_2; + let Inst{5-0} = funct; +} + +//===----------------------------------------------------------------------===// +// Exception return format <Cop0|1|0|funct> +//===----------------------------------------------------------------------===// + +class ER_FM<bits<6> funct, bit LLBit> : StdArch +{ + bits<32> Inst; + let Inst{31-26} = 0x10; + let Inst{25} = 1; + let Inst{24-7} = 0; + let Inst{6} = LLBit; + let Inst{5-0} = funct; +} + +//===----------------------------------------------------------------------===// +// Enable/disable interrupt instruction format <Cop0|MFMC0|rt|12|0|sc|0|0> +//===----------------------------------------------------------------------===// + +class EI_FM<bits<1> sc> : StdArch +{ + bits<32> Inst; + bits<5> rt; + let Inst{31-26} = 0x10; + let Inst{25-21} = 0xb; + let Inst{20-16} = rt; + let Inst{15-11} = 0xc; + let Inst{10-6} = 0; + let Inst{5} = sc; + let Inst{4-0} = 0; +} + +//===----------------------------------------------------------------------===// +// +// FLOATING POINT INSTRUCTION FORMATS +// +// opcode - operation code. +// fs - src reg. +// ft - dst reg (on a 2 regs instr) or src reg (on a 3 reg instr). +// fd - dst reg, only used on 3 regs instr. +// fmt - double or single precision. +// funct - combined with opcode field give us an operation code. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Format FI instruction class in Mips : <|opcode|base|ft|immediate|> +//===----------------------------------------------------------------------===// + +class FFI<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern>: + InstSE<outs, ins, asmstr, pattern, NoItinerary, FrmFI> +{ + bits<5> ft; + bits<5> base; + bits<16> imm16; + + let Opcode = op; + + let Inst{25-21} = base; + let Inst{20-16} = ft; + let Inst{15-0} = imm16; +} + +class ADDS_FM<bits<6> funct, bits<5> fmt> : StdArch { + bits<5> fd; + bits<5> fs; + bits<5> ft; + + bits<32> Inst; + + let Inst{31-26} = 0x11; + let Inst{25-21} = fmt; + let Inst{20-16} = ft; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5-0} = funct; +} + +class ABSS_FM<bits<6> funct, bits<5> fmt> : StdArch { + bits<5> fd; + bits<5> fs; + + bits<32> Inst; + + let Inst{31-26} = 0x11; + let Inst{25-21} = fmt; + let Inst{20-16} = 0; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5-0} = funct; +} + +class MFC1_FM<bits<5> funct> : StdArch { + bits<5> rt; + bits<5> fs; + + bits<32> Inst; + + let Inst{31-26} = 0x11; + let Inst{25-21} = funct; + let Inst{20-16} = rt; + let Inst{15-11} = fs; + let Inst{10-0} = 0; +} + +class LW_FM<bits<6> op> : StdArch { + bits<5> rt; + bits<21> addr; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = addr{20-16}; + let Inst{20-16} = rt; + let Inst{15-0} = addr{15-0}; +} + +class MADDS_FM<bits<3> funct, bits<3> fmt> : StdArch { + bits<5> fd; + bits<5> fr; + bits<5> fs; + bits<5> ft; + + bits<32> Inst; + + let Inst{31-26} = 0x13; + let Inst{25-21} = fr; + let Inst{20-16} = ft; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5-3} = funct; + let Inst{2-0} = fmt; +} + +class LWXC1_FM<bits<6> funct> : StdArch { + bits<5> fd; + bits<5> base; + bits<5> index; + + bits<32> Inst; + + let Inst{31-26} = 0x13; + let Inst{25-21} = base; + let Inst{20-16} = index; + let Inst{15-11} = 0; + let Inst{10-6} = fd; + let Inst{5-0} = funct; +} + +class SWXC1_FM<bits<6> funct> : StdArch { + bits<5> fs; + bits<5> base; + bits<5> index; + + bits<32> Inst; + + let Inst{31-26} = 0x13; + let Inst{25-21} = base; + let Inst{20-16} = index; + let Inst{15-11} = fs; + let Inst{10-6} = 0; + let Inst{5-0} = funct; +} + +class BC1F_FM<bit nd, bit tf> : StdArch { + bits<3> fcc; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = 0x11; + let Inst{25-21} = 0x8; + let Inst{20-18} = fcc; + let Inst{17} = nd; + let Inst{16} = tf; + let Inst{15-0} = offset; +} + +class CEQS_FM<bits<5> fmt> : StdArch { + bits<5> fs; + bits<5> ft; + bits<4> cond; + + bits<32> Inst; + + let Inst{31-26} = 0x11; + let Inst{25-21} = fmt; + let Inst{20-16} = ft; + let Inst{15-11} = fs; + let Inst{10-8} = 0; // cc + let Inst{7-4} = 0x3; + let Inst{3-0} = cond; +} + +class C_COND_FM<bits<5> fmt, bits<4> c> : CEQS_FM<fmt> { + let cond = c; +} + +class CMov_I_F_FM<bits<6> funct, bits<5> fmt> : StdArch { + bits<5> fd; + bits<5> fs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0x11; + let Inst{25-21} = fmt; + let Inst{20-16} = rt; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5-0} = funct; +} + +class CMov_F_I_FM<bit tf> : StdArch { + bits<5> rd; + bits<5> rs; + bits<3> fcc; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rs; + let Inst{20-18} = fcc; + let Inst{17} = 0; + let Inst{16} = tf; + let Inst{15-11} = rd; + let Inst{10-6} = 0; + let Inst{5-0} = 1; +} + +class CMov_F_F_FM<bits<5> fmt, bit tf> : StdArch { + bits<5> fd; + bits<5> fs; + bits<3> fcc; + + bits<32> Inst; + + let Inst{31-26} = 0x11; + let Inst{25-21} = fmt; + let Inst{20-18} = fcc; + let Inst{17} = 0; + let Inst{16} = tf; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5-0} = 0x11; +} + +class BARRIER_FM<bits<5> op> : StdArch { + bits<32> Inst; + + let Inst{31-26} = 0; // SPECIAL + let Inst{25-21} = 0; + let Inst{20-16} = 0; // rt = 0 + let Inst{15-11} = 0; // rd = 0 + let Inst{10-6} = op; // Operation + let Inst{5-0} = 0; // SLL +} + +class SDBBP_FM : StdArch { + bits<20> code_; + + bits<32> Inst; + + let Inst{31-26} = 0b011100; // SPECIAL2 + let Inst{25-6} = code_; + let Inst{5-0} = 0b111111; // SDBBP +} + +class JR_HB_FM<bits<6> op> : StdArch{ + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0; // SPECIAL + let Inst{25-21} = rs; + let Inst{20-11} = 0; + let Inst{10} = 1; + let Inst{9-6} = 0; + let Inst{5-0} = op; +} + +class JALR_HB_FM<bits<6> op> : StdArch { + bits<5> rd; + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0; // SPECIAL + let Inst{25-21} = rs; + let Inst{20-16} = 0; + let Inst{15-11} = rd; + let Inst{10} = 1; + let Inst{9-6} = 0; + let Inst{5-0} = op; +} + +class COP0_TLB_FM<bits<6> op> : StdArch { + bits<32> Inst; + + let Inst{31-26} = 0x10; // COP0 + let Inst{25} = 1; // CO + let Inst{24-6} = 0; + let Inst{5-0} = op; // Operation +} + +class CACHEOP_FM<bits<6> op> : StdArch { + bits<21> addr; + bits<5> hint; + bits<5> base = addr{20-16}; + bits<16> offset = addr{15-0}; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = base; + let Inst{20-16} = hint; + let Inst{15-0} = offset; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.cpp new file mode 100644 index 0000000..b1d6950 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.cpp @@ -0,0 +1,288 @@ +//===-- MipsInstrInfo.cpp - Mips Instruction Information ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "MipsInstrInfo.h" +#include "InstPrinter/MipsInstPrinter.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsMachineFunction.h" +#include "MipsSubtarget.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +#define GET_INSTRINFO_CTOR_DTOR +#include "MipsGenInstrInfo.inc" + +// Pin the vtable to this file. +void MipsInstrInfo::anchor() {} + +MipsInstrInfo::MipsInstrInfo(const MipsSubtarget &STI, unsigned UncondBr) + : MipsGenInstrInfo(Mips::ADJCALLSTACKDOWN, Mips::ADJCALLSTACKUP), + Subtarget(STI), UncondBrOpc(UncondBr) {} + +const MipsInstrInfo *MipsInstrInfo::create(MipsSubtarget &STI) { + if (STI.inMips16Mode()) + return llvm::createMips16InstrInfo(STI); + + return llvm::createMipsSEInstrInfo(STI); +} + +bool MipsInstrInfo::isZeroImm(const MachineOperand &op) const { + return op.isImm() && op.getImm() == 0; +} + +/// insertNoop - If data hazard condition is found insert the target nop +/// instruction. +void MipsInstrInfo:: +insertNoop(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const +{ + DebugLoc DL; + BuildMI(MBB, MI, DL, get(Mips::NOP)); +} + +MachineMemOperand *MipsInstrInfo::GetMemOperand(MachineBasicBlock &MBB, int FI, + unsigned Flag) const { + MachineFunction &MF = *MBB.getParent(); + MachineFrameInfo &MFI = *MF.getFrameInfo(); + unsigned Align = MFI.getObjectAlignment(FI); + + return MF.getMachineMemOperand(MachinePointerInfo::getFixedStack(MF, FI), + Flag, MFI.getObjectSize(FI), Align); +} + +//===----------------------------------------------------------------------===// +// Branch Analysis +//===----------------------------------------------------------------------===// + +void MipsInstrInfo::AnalyzeCondBr(const MachineInstr *Inst, unsigned Opc, + MachineBasicBlock *&BB, + SmallVectorImpl<MachineOperand> &Cond) const { + assert(getAnalyzableBrOpc(Opc) && "Not an analyzable branch"); + int NumOp = Inst->getNumExplicitOperands(); + + // for both int and fp branches, the last explicit operand is the + // MBB. + BB = Inst->getOperand(NumOp-1).getMBB(); + Cond.push_back(MachineOperand::CreateImm(Opc)); + + for (int i=0; i<NumOp-1; i++) + Cond.push_back(Inst->getOperand(i)); +} + +bool MipsInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const { + SmallVector<MachineInstr*, 2> BranchInstrs; + BranchType BT = AnalyzeBranch(MBB, TBB, FBB, Cond, AllowModify, BranchInstrs); + + return (BT == BT_None) || (BT == BT_Indirect); +} + +void +MipsInstrInfo::BuildCondBr(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + DebugLoc DL, ArrayRef<MachineOperand> Cond) const { + unsigned Opc = Cond[0].getImm(); + const MCInstrDesc &MCID = get(Opc); + MachineInstrBuilder MIB = BuildMI(&MBB, DL, MCID); + + for (unsigned i = 1; i < Cond.size(); ++i) { + if (Cond[i].isReg()) + MIB.addReg(Cond[i].getReg()); + else if (Cond[i].isImm()) + MIB.addImm(Cond[i].getImm()); + else + assert(true && "Cannot copy operand"); + } + MIB.addMBB(TBB); +} + +unsigned MipsInstrInfo::InsertBranch( + MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, + ArrayRef<MachineOperand> Cond, DebugLoc DL) const { + // Shouldn't be a fall through. + assert(TBB && "InsertBranch must not be told to insert a fallthrough"); + + // # of condition operands: + // Unconditional branches: 0 + // Floating point branches: 1 (opc) + // Int BranchZero: 2 (opc, reg) + // Int Branch: 3 (opc, reg0, reg1) + assert((Cond.size() <= 3) && + "# of Mips branch conditions must be <= 3!"); + + // Two-way Conditional branch. + if (FBB) { + BuildCondBr(MBB, TBB, DL, Cond); + BuildMI(&MBB, DL, get(UncondBrOpc)).addMBB(FBB); + return 2; + } + + // One way branch. + // Unconditional branch. + if (Cond.empty()) + BuildMI(&MBB, DL, get(UncondBrOpc)).addMBB(TBB); + else // Conditional branch. + BuildCondBr(MBB, TBB, DL, Cond); + return 1; +} + +unsigned MipsInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const { + MachineBasicBlock::reverse_iterator I = MBB.rbegin(), REnd = MBB.rend(); + MachineBasicBlock::reverse_iterator FirstBr; + unsigned removed; + + // Skip all the debug instructions. + while (I != REnd && I->isDebugValue()) + ++I; + + FirstBr = I; + + // Up to 2 branches are removed. + // Note that indirect branches are not removed. + for (removed = 0; I != REnd && removed < 2; ++I, ++removed) + if (!getAnalyzableBrOpc(I->getOpcode())) + break; + + MBB.erase(I.base(), FirstBr.base()); + + return removed; +} + +/// ReverseBranchCondition - Return the inverse opcode of the +/// specified Branch instruction. +bool MipsInstrInfo::ReverseBranchCondition( + SmallVectorImpl<MachineOperand> &Cond) const { + assert( (Cond.size() && Cond.size() <= 3) && + "Invalid Mips branch condition!"); + Cond[0].setImm(getOppositeBranchOpc(Cond[0].getImm())); + return false; +} + +MipsInstrInfo::BranchType MipsInstrInfo::AnalyzeBranch( + MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, bool AllowModify, + SmallVectorImpl<MachineInstr *> &BranchInstrs) const { + + MachineBasicBlock::reverse_iterator I = MBB.rbegin(), REnd = MBB.rend(); + + // Skip all the debug instructions. + while (I != REnd && I->isDebugValue()) + ++I; + + if (I == REnd || !isUnpredicatedTerminator(&*I)) { + // This block ends with no branches (it just falls through to its succ). + // Leave TBB/FBB null. + TBB = FBB = nullptr; + return BT_NoBranch; + } + + MachineInstr *LastInst = &*I; + unsigned LastOpc = LastInst->getOpcode(); + BranchInstrs.push_back(LastInst); + + // Not an analyzable branch (e.g., indirect jump). + if (!getAnalyzableBrOpc(LastOpc)) + return LastInst->isIndirectBranch() ? BT_Indirect : BT_None; + + // Get the second to last instruction in the block. + unsigned SecondLastOpc = 0; + MachineInstr *SecondLastInst = nullptr; + + if (++I != REnd) { + SecondLastInst = &*I; + SecondLastOpc = getAnalyzableBrOpc(SecondLastInst->getOpcode()); + + // Not an analyzable branch (must be an indirect jump). + if (isUnpredicatedTerminator(SecondLastInst) && !SecondLastOpc) + return BT_None; + } + + // If there is only one terminator instruction, process it. + if (!SecondLastOpc) { + // Unconditional branch. + if (LastOpc == UncondBrOpc) { + TBB = LastInst->getOperand(0).getMBB(); + return BT_Uncond; + } + + // Conditional branch + AnalyzeCondBr(LastInst, LastOpc, TBB, Cond); + return BT_Cond; + } + + // If we reached here, there are two branches. + // If there are three terminators, we don't know what sort of block this is. + if (++I != REnd && isUnpredicatedTerminator(&*I)) + return BT_None; + + BranchInstrs.insert(BranchInstrs.begin(), SecondLastInst); + + // If second to last instruction is an unconditional branch, + // analyze it and remove the last instruction. + if (SecondLastOpc == UncondBrOpc) { + // Return if the last instruction cannot be removed. + if (!AllowModify) + return BT_None; + + TBB = SecondLastInst->getOperand(0).getMBB(); + LastInst->eraseFromParent(); + BranchInstrs.pop_back(); + return BT_Uncond; + } + + // Conditional branch followed by an unconditional branch. + // The last one must be unconditional. + if (LastOpc != UncondBrOpc) + return BT_None; + + AnalyzeCondBr(SecondLastInst, SecondLastOpc, TBB, Cond); + FBB = LastInst->getOperand(0).getMBB(); + + return BT_CondUncond; +} + +/// Return the number of bytes of code the specified instruction may be. +unsigned MipsInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const { + switch (MI->getOpcode()) { + default: + return MI->getDesc().getSize(); + case TargetOpcode::INLINEASM: { // Inline Asm: Variable size. + const MachineFunction *MF = MI->getParent()->getParent(); + const char *AsmStr = MI->getOperand(0).getSymbolName(); + return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo()); + } + case Mips::CONSTPOOL_ENTRY: + // If this machine instr is a constant pool entry, its size is recorded as + // operand #2. + return MI->getOperand(2).getImm(); + } +} + +MachineInstrBuilder +MipsInstrInfo::genInstrWithNewOpc(unsigned NewOpc, + MachineBasicBlock::iterator I) const { + MachineInstrBuilder MIB; + MIB = BuildMI(*I->getParent(), I, I->getDebugLoc(), get(NewOpc)); + + for (unsigned J = 0, E = I->getDesc().getNumOperands(); J < E; ++J) + MIB.addOperand(I->getOperand(J)); + + MIB.setMemRefs(I->memoperands_begin(), I->memoperands_end()); + return MIB; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrInfo.h b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.h new file mode 100644 index 0000000..08efc35 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.h @@ -0,0 +1,151 @@ +//===-- MipsInstrInfo.h - Mips Instruction Information ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips implementation of the TargetInstrInfo class. +// +// FIXME: We need to override TargetInstrInfo::getInlineAsmLength method in +// order for MipsLongBranch pass to work correctly when the code has inline +// assembly. The returned value doesn't have to be the asm instruction's exact +// size in bytes; MipsLongBranch only expects it to be the correct upper bound. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSINSTRINFO_H +#define LLVM_LIB_TARGET_MIPS_MIPSINSTRINFO_H + +#include "Mips.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsRegisterInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetInstrInfo.h" + +#define GET_INSTRINFO_HEADER +#include "MipsGenInstrInfo.inc" + +namespace llvm { +class MipsSubtarget; +class MipsInstrInfo : public MipsGenInstrInfo { + virtual void anchor(); +protected: + const MipsSubtarget &Subtarget; + unsigned UncondBrOpc; + +public: + enum BranchType { + BT_None, // Couldn't analyze branch. + BT_NoBranch, // No branches found. + BT_Uncond, // One unconditional branch. + BT_Cond, // One conditional branch. + BT_CondUncond, // A conditional branch followed by an unconditional branch. + BT_Indirect // One indirct branch. + }; + + explicit MipsInstrInfo(const MipsSubtarget &STI, unsigned UncondBrOpc); + + static const MipsInstrInfo *create(MipsSubtarget &STI); + + /// Branch Analysis + bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const override; + + unsigned RemoveBranch(MachineBasicBlock &MBB) const override; + + unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond, + DebugLoc DL) const override; + + bool + ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override; + + BranchType AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify, + SmallVectorImpl<MachineInstr*> &BranchInstrs) const; + + /// Insert nop instruction when hazard condition is found + void insertNoop(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const override; + + /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As + /// such, whenever a client has an instance of instruction info, it should + /// always be able to get register info as well (through this method). + /// + virtual const MipsRegisterInfo &getRegisterInfo() const = 0; + + virtual unsigned getOppositeBranchOpc(unsigned Opc) const = 0; + + /// Return the number of bytes of code the specified instruction may be. + unsigned GetInstSizeInBytes(const MachineInstr *MI) const; + + void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const override { + storeRegToStack(MBB, MBBI, SrcReg, isKill, FrameIndex, RC, TRI, 0); + } + + void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const override { + loadRegFromStack(MBB, MBBI, DestReg, FrameIndex, RC, TRI, 0); + } + + virtual void storeRegToStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const = 0; + + virtual void loadRegFromStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const = 0; + + virtual void adjustStackPtr(unsigned SP, int64_t Amount, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const = 0; + + /// Create an instruction which has the same operands and memory operands + /// as MI but has a new opcode. + MachineInstrBuilder genInstrWithNewOpc(unsigned NewOpc, + MachineBasicBlock::iterator I) const; + +protected: + bool isZeroImm(const MachineOperand &op) const; + + MachineMemOperand *GetMemOperand(MachineBasicBlock &MBB, int FI, + unsigned Flag) const; + +private: + virtual unsigned getAnalyzableBrOpc(unsigned Opc) const = 0; + + void AnalyzeCondBr(const MachineInstr *Inst, unsigned Opc, + MachineBasicBlock *&BB, + SmallVectorImpl<MachineOperand> &Cond) const; + + void BuildCondBr(MachineBasicBlock &MBB, MachineBasicBlock *TBB, DebugLoc DL, + ArrayRef<MachineOperand> Cond) const; +}; + +/// Create MipsInstrInfo objects. +const MipsInstrInfo *createMips16InstrInfo(const MipsSubtarget &STI); +const MipsInstrInfo *createMipsSEInstrInfo(const MipsSubtarget &STI); + +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrInfo.td b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.td new file mode 100644 index 0000000..d9fb8c8 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.td @@ -0,0 +1,2300 @@ +//===- MipsInstrInfo.td - Target Description for Mips Target -*- tablegen -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + + +//===----------------------------------------------------------------------===// +// Mips profiles and nodes +//===----------------------------------------------------------------------===// + +def SDT_MipsJmpLink : SDTypeProfile<0, 1, [SDTCisVT<0, iPTR>]>; +def SDT_MipsCMov : SDTypeProfile<1, 4, [SDTCisSameAs<0, 1>, + SDTCisSameAs<1, 2>, + SDTCisSameAs<3, 4>, + SDTCisInt<4>]>; +def SDT_MipsCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>]>; +def SDT_MipsCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; +def SDT_MFLOHI : SDTypeProfile<1, 1, [SDTCisInt<0>, SDTCisVT<1, untyped>]>; +def SDT_MTLOHI : SDTypeProfile<1, 2, [SDTCisVT<0, untyped>, + SDTCisInt<1>, SDTCisSameAs<1, 2>]>; +def SDT_MipsMultDiv : SDTypeProfile<1, 2, [SDTCisVT<0, untyped>, SDTCisInt<1>, + SDTCisSameAs<1, 2>]>; +def SDT_MipsMAddMSub : SDTypeProfile<1, 3, + [SDTCisVT<0, untyped>, SDTCisSameAs<0, 3>, + SDTCisVT<1, i32>, SDTCisSameAs<1, 2>]>; +def SDT_MipsDivRem16 : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisSameAs<0, 1>]>; + +def SDT_MipsThreadPointer : SDTypeProfile<1, 0, [SDTCisPtrTy<0>]>; + +def SDT_Sync : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>; + +def SDT_Ext : SDTypeProfile<1, 3, [SDTCisInt<0>, SDTCisSameAs<0, 1>, + SDTCisVT<2, i32>, SDTCisSameAs<2, 3>]>; +def SDT_Ins : SDTypeProfile<1, 4, [SDTCisInt<0>, SDTCisSameAs<0, 1>, + SDTCisVT<2, i32>, SDTCisSameAs<2, 3>, + SDTCisSameAs<0, 4>]>; + +def SDTMipsLoadLR : SDTypeProfile<1, 2, + [SDTCisInt<0>, SDTCisPtrTy<1>, + SDTCisSameAs<0, 2>]>; + +// Call +def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink, + [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, + SDNPVariadic]>; + +// Tail call +def MipsTailCall : SDNode<"MipsISD::TailCall", SDT_MipsJmpLink, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; + +// Hi and Lo nodes are used to handle global addresses. Used on +// MipsISelLowering to lower stuff like GlobalAddress, ExternalSymbol +// static model. (nothing to do with Mips Registers Hi and Lo) +def MipsHi : SDNode<"MipsISD::Hi", SDTIntUnaryOp>; +def MipsLo : SDNode<"MipsISD::Lo", SDTIntUnaryOp>; +def MipsGPRel : SDNode<"MipsISD::GPRel", SDTIntUnaryOp>; + +// TlsGd node is used to handle General Dynamic TLS +def MipsTlsGd : SDNode<"MipsISD::TlsGd", SDTIntUnaryOp>; + +// TprelHi and TprelLo nodes are used to handle Local Exec TLS +def MipsTprelHi : SDNode<"MipsISD::TprelHi", SDTIntUnaryOp>; +def MipsTprelLo : SDNode<"MipsISD::TprelLo", SDTIntUnaryOp>; + +// Thread pointer +def MipsThreadPointer: SDNode<"MipsISD::ThreadPointer", SDT_MipsThreadPointer>; + +// Return +def MipsRet : SDNode<"MipsISD::Ret", SDTNone, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; + +def MipsERet : SDNode<"MipsISD::ERet", SDTNone, + [SDNPHasChain, SDNPOptInGlue, SDNPSideEffect]>; + +// These are target-independent nodes, but have target-specific formats. +def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_MipsCallSeqStart, + [SDNPHasChain, SDNPSideEffect, SDNPOutGlue]>; +def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_MipsCallSeqEnd, + [SDNPHasChain, SDNPSideEffect, + SDNPOptInGlue, SDNPOutGlue]>; + +// Nodes used to extract LO/HI registers. +def MipsMFHI : SDNode<"MipsISD::MFHI", SDT_MFLOHI>; +def MipsMFLO : SDNode<"MipsISD::MFLO", SDT_MFLOHI>; + +// Node used to insert 32-bit integers to LOHI register pair. +def MipsMTLOHI : SDNode<"MipsISD::MTLOHI", SDT_MTLOHI>; + +// Mult nodes. +def MipsMult : SDNode<"MipsISD::Mult", SDT_MipsMultDiv>; +def MipsMultu : SDNode<"MipsISD::Multu", SDT_MipsMultDiv>; + +// MAdd*/MSub* nodes +def MipsMAdd : SDNode<"MipsISD::MAdd", SDT_MipsMAddMSub>; +def MipsMAddu : SDNode<"MipsISD::MAddu", SDT_MipsMAddMSub>; +def MipsMSub : SDNode<"MipsISD::MSub", SDT_MipsMAddMSub>; +def MipsMSubu : SDNode<"MipsISD::MSubu", SDT_MipsMAddMSub>; + +// DivRem(u) nodes +def MipsDivRem : SDNode<"MipsISD::DivRem", SDT_MipsMultDiv>; +def MipsDivRemU : SDNode<"MipsISD::DivRemU", SDT_MipsMultDiv>; +def MipsDivRem16 : SDNode<"MipsISD::DivRem16", SDT_MipsDivRem16, + [SDNPOutGlue]>; +def MipsDivRemU16 : SDNode<"MipsISD::DivRemU16", SDT_MipsDivRem16, + [SDNPOutGlue]>; + +// Target constant nodes that are not part of any isel patterns and remain +// unchanged can cause instructions with illegal operands to be emitted. +// Wrapper node patterns give the instruction selector a chance to replace +// target constant nodes that would otherwise remain unchanged with ADDiu +// nodes. Without these wrapper node patterns, the following conditional move +// instruction is emitted when function cmov2 in test/CodeGen/Mips/cmov.ll is +// compiled: +// movn %got(d)($gp), %got(c)($gp), $4 +// This instruction is illegal since movn can take only register operands. + +def MipsWrapper : SDNode<"MipsISD::Wrapper", SDTIntBinOp>; + +def MipsSync : SDNode<"MipsISD::Sync", SDT_Sync, [SDNPHasChain,SDNPSideEffect]>; + +def MipsExt : SDNode<"MipsISD::Ext", SDT_Ext>; +def MipsIns : SDNode<"MipsISD::Ins", SDT_Ins>; + +def MipsLWL : SDNode<"MipsISD::LWL", SDTMipsLoadLR, + [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; +def MipsLWR : SDNode<"MipsISD::LWR", SDTMipsLoadLR, + [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; +def MipsSWL : SDNode<"MipsISD::SWL", SDTStore, + [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; +def MipsSWR : SDNode<"MipsISD::SWR", SDTStore, + [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; +def MipsLDL : SDNode<"MipsISD::LDL", SDTMipsLoadLR, + [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; +def MipsLDR : SDNode<"MipsISD::LDR", SDTMipsLoadLR, + [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; +def MipsSDL : SDNode<"MipsISD::SDL", SDTStore, + [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; +def MipsSDR : SDNode<"MipsISD::SDR", SDTStore, + [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; + +//===----------------------------------------------------------------------===// +// Mips Instruction Predicate Definitions. +//===----------------------------------------------------------------------===// +def HasMips2 : Predicate<"Subtarget->hasMips2()">, + AssemblerPredicate<"FeatureMips2">; +def HasMips3_32 : Predicate<"Subtarget->hasMips3_32()">, + AssemblerPredicate<"FeatureMips3_32">; +def HasMips3_32r2 : Predicate<"Subtarget->hasMips3_32r2()">, + AssemblerPredicate<"FeatureMips3_32r2">; +def HasMips3 : Predicate<"Subtarget->hasMips3()">, + AssemblerPredicate<"FeatureMips3">; +def HasMips4_32 : Predicate<"Subtarget->hasMips4_32()">, + AssemblerPredicate<"FeatureMips4_32">; +def NotMips4_32 : Predicate<"!Subtarget->hasMips4_32()">, + AssemblerPredicate<"!FeatureMips4_32">; +def HasMips4_32r2 : Predicate<"Subtarget->hasMips4_32r2()">, + AssemblerPredicate<"FeatureMips4_32r2">; +def HasMips5_32r2 : Predicate<"Subtarget->hasMips5_32r2()">, + AssemblerPredicate<"FeatureMips5_32r2">; +def HasMips32 : Predicate<"Subtarget->hasMips32()">, + AssemblerPredicate<"FeatureMips32">; +def HasMips32r2 : Predicate<"Subtarget->hasMips32r2()">, + AssemblerPredicate<"FeatureMips32r2">; +def HasMips32r5 : Predicate<"Subtarget->hasMips32r5()">, + AssemblerPredicate<"FeatureMips32r5">; +def HasMips32r6 : Predicate<"Subtarget->hasMips32r6()">, + AssemblerPredicate<"FeatureMips32r6">; +def NotMips32r6 : Predicate<"!Subtarget->hasMips32r6()">, + AssemblerPredicate<"!FeatureMips32r6">; +def IsGP64bit : Predicate<"Subtarget->isGP64bit()">, + AssemblerPredicate<"FeatureGP64Bit">; +def IsGP32bit : Predicate<"!Subtarget->isGP64bit()">, + AssemblerPredicate<"!FeatureGP64Bit">; +def HasMips64 : Predicate<"Subtarget->hasMips64()">, + AssemblerPredicate<"FeatureMips64">; +def NotMips64 : Predicate<"!Subtarget->hasMips64()">, + AssemblerPredicate<"!FeatureMips64">; +def HasMips64r2 : Predicate<"Subtarget->hasMips64r2()">, + AssemblerPredicate<"FeatureMips64r2">; +def HasMips64r6 : Predicate<"Subtarget->hasMips64r6()">, + AssemblerPredicate<"FeatureMips64r6">; +def NotMips64r6 : Predicate<"!Subtarget->hasMips64r6()">, + AssemblerPredicate<"!FeatureMips64r6">; +def HasMicroMips32r6 : Predicate<"Subtarget->inMicroMips32r6Mode()">, + AssemblerPredicate<"FeatureMicroMips,FeatureMips32r6">; +def HasMicroMips64r6 : Predicate<"Subtarget->inMicroMips64r6Mode()">, + AssemblerPredicate<"FeatureMicroMips,FeatureMips64r6">; +def InMips16Mode : Predicate<"Subtarget->inMips16Mode()">, + AssemblerPredicate<"FeatureMips16">; +def HasCnMips : Predicate<"Subtarget->hasCnMips()">, + AssemblerPredicate<"FeatureCnMips">; +def RelocStatic : Predicate<"TM.getRelocationModel() == Reloc::Static">; +def RelocPIC : Predicate<"TM.getRelocationModel() == Reloc::PIC_">; +def NoNaNsFPMath : Predicate<"TM.Options.NoNaNsFPMath">; +def HasStdEnc : Predicate<"Subtarget->hasStandardEncoding()">, + AssemblerPredicate<"!FeatureMips16">; +def NotDSP : Predicate<"!Subtarget->hasDSP()">; +def InMicroMips : Predicate<"Subtarget->inMicroMipsMode()">, + AssemblerPredicate<"FeatureMicroMips">; +def NotInMicroMips : Predicate<"!Subtarget->inMicroMipsMode()">, + AssemblerPredicate<"!FeatureMicroMips">; +def IsLE : Predicate<"Subtarget->isLittle()">; +def IsBE : Predicate<"!Subtarget->isLittle()">; +def IsNotNaCl : Predicate<"!Subtarget->isTargetNaCl()">; +def UseTCCInDIV : AssemblerPredicate<"FeatureUseTCCInDIV">; +def HasEVA : Predicate<"Subtarget->hasEVA()">, + AssemblerPredicate<"FeatureEVA,FeatureMips32r2">; +def HasMSA : Predicate<"Subtarget->hasMSA()">, + AssemblerPredicate<"FeatureMSA">; + + +//===----------------------------------------------------------------------===// +// Mips GPR size adjectives. +// They are mutually exclusive. +//===----------------------------------------------------------------------===// + +class GPR_32 { list<Predicate> GPRPredicates = [IsGP32bit]; } +class GPR_64 { list<Predicate> GPRPredicates = [IsGP64bit]; } + +//===----------------------------------------------------------------------===// +// Mips ISA/ASE membership and instruction group membership adjectives. +// They are mutually exclusive. +//===----------------------------------------------------------------------===// + +// FIXME: I'd prefer to use additive predicates to build the instruction sets +// but we are short on assembler feature bits at the moment. Using a +// subtractive predicate will hopefully keep us under the 32 predicate +// limit long enough to develop an alternative way to handle P1||P2 +// predicates. +class ISA_MIPS1_NOT_4_32 { + list<Predicate> InsnPredicates = [NotMips4_32]; +} +class ISA_MIPS1_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [NotMips32r6, NotMips64r6]; +} +class ISA_MIPS2 { list<Predicate> InsnPredicates = [HasMips2]; } +class ISA_MIPS2_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips2, NotMips32r6, NotMips64r6]; +} +class ISA_MIPS3 { list<Predicate> InsnPredicates = [HasMips3]; } +class ISA_MIPS3_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips3, NotMips32r6, NotMips64r6]; +} +class ISA_MIPS32 { list<Predicate> InsnPredicates = [HasMips32]; } +class ISA_MIPS32_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips32, NotMips32r6, NotMips64r6]; +} +class ISA_MIPS32R2 { list<Predicate> InsnPredicates = [HasMips32r2]; } +class ISA_MIPS32R2_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips32r2, NotMips32r6, NotMips64r6]; +} +class ISA_MIPS32R5 { list<Predicate> InsnPredicates = [HasMips32r5]; } +class ISA_MIPS64 { list<Predicate> InsnPredicates = [HasMips64]; } +class ISA_MIPS64_NOT_64R6 { + list<Predicate> InsnPredicates = [HasMips64, NotMips64r6]; +} +class ISA_MIPS64R2 { list<Predicate> InsnPredicates = [HasMips64r2]; } +class ISA_MIPS32R6 { list<Predicate> InsnPredicates = [HasMips32r6]; } +class ISA_MIPS64R6 { list<Predicate> InsnPredicates = [HasMips64r6]; } +class ISA_MICROMIPS { list<Predicate> InsnPredicates = [InMicroMips]; } +class ISA_MICROMIPS32R6 { + list<Predicate> InsnPredicates = [HasMicroMips32r6]; +} +class ISA_MICROMIPS64R6 { + list<Predicate> InsnPredicates = [HasMicroMips64r6]; +} +class ISA_MICROMIPS32_NOT_MIPS32R6 { + list<Predicate> InsnPredicates = [InMicroMips, NotMips32r6]; +} + +class INSN_EVA { list<Predicate> InsnPredicates = [HasEVA]; } +class INSN_EVA_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [NotMips32r6, NotMips64r6, HasEVA]; +} + +// The portions of MIPS-III that were also added to MIPS32 +class INSN_MIPS3_32 { list<Predicate> InsnPredicates = [HasMips3_32]; } + +// The portions of MIPS-III that were also added to MIPS32 but were removed in +// MIPS32r6 and MIPS64r6. +class INSN_MIPS3_32_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips3_32, NotMips32r6, NotMips64r6]; +} + +// The portions of MIPS-III that were also added to MIPS32 +class INSN_MIPS3_32R2 { list<Predicate> InsnPredicates = [HasMips3_32r2]; } + +// The portions of MIPS-IV that were also added to MIPS32 but were removed in +// MIPS32r6 and MIPS64r6. +class INSN_MIPS4_32_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips4_32, NotMips32r6, NotMips64r6]; +} + +// The portions of MIPS-IV that were also added to MIPS32r2 but were removed in +// MIPS32r6 and MIPS64r6. +class INSN_MIPS4_32R2_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips4_32r2, NotMips32r6, NotMips64r6]; +} + +// The portions of MIPS-V that were also added to MIPS32r2 but were removed in +// MIPS32r6 and MIPS64r6. +class INSN_MIPS5_32R2_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips5_32r2, NotMips32r6, NotMips64r6]; +} + +class ASE_CNMIPS { + list<Predicate> InsnPredicates = [HasCnMips]; +} + +class ASE_MSA { + list<Predicate> InsnPredicates = [HasMSA]; +} + +class ASE_MSA_NOT_MSA64 { + list<Predicate> InsnPredicates = [HasMSA, NotMips64]; +} + +class ASE_MSA64 { + list<Predicate> InsnPredicates = [HasMSA, HasMips64]; +} + +// Class used for separating microMIPSr6 and microMIPS (r3) instruction. +// It can be used only on instructions that doesn't inherit PredicateControl. +class ISA_MICROMIPS_NOT_32R6_64R6 : PredicateControl { + let InsnPredicates = [InMicroMips, NotMips32r6, NotMips64r6]; +} + +//===----------------------------------------------------------------------===// + +class MipsPat<dag pattern, dag result> : Pat<pattern, result>, PredicateControl { + let EncodingPredicates = [HasStdEnc]; +} + +class MipsInstAlias<string Asm, dag Result, bit Emit = 0b1> : + InstAlias<Asm, Result, Emit>, PredicateControl; + +class IsCommutable { + bit isCommutable = 1; +} + +class IsBranch { + bit isBranch = 1; +} + +class IsReturn { + bit isReturn = 1; +} + +class IsCall { + bit isCall = 1; +} + +class IsTailCall { + bit isCall = 1; + bit isTerminator = 1; + bit isReturn = 1; + bit isBarrier = 1; + bit hasExtraSrcRegAllocReq = 1; + bit isCodeGenOnly = 1; +} + +class IsAsCheapAsAMove { + bit isAsCheapAsAMove = 1; +} + +class NeverHasSideEffects { + bit hasSideEffects = 0; +} + +//===----------------------------------------------------------------------===// +// Instruction format superclass +//===----------------------------------------------------------------------===// + +include "MipsInstrFormats.td" + +//===----------------------------------------------------------------------===// +// Mips Operand, Complex Patterns and Transformations Definitions. +//===----------------------------------------------------------------------===// + +class ConstantSImmAsmOperandClass<int Bits, list<AsmOperandClass> Supers = []> + : AsmOperandClass { + let Name = "ConstantSImm" # Bits; + let RenderMethod = "addImmOperands"; + let PredicateMethod = "isConstantSImm<" # Bits # ">"; + let SuperClasses = Supers; + let DiagnosticType = "SImm" # Bits; +} + +class ConstantUImmAsmOperandClass<int Bits, list<AsmOperandClass> Supers = [], + int Offset = 0> : AsmOperandClass { + let Name = "ConstantUImm" # Bits # "_" # Offset; + let RenderMethod = "addConstantUImmOperands<" # Bits # ", " # Offset # ">"; + let PredicateMethod = "isConstantUImm<" # Bits # ", " # Offset # ">"; + let SuperClasses = Supers; + let DiagnosticType = "UImm" # Bits # "_" # Offset; +} + +def ConstantUImm10AsmOperandClass + : ConstantUImmAsmOperandClass<10, []>; +def ConstantUImm8AsmOperandClass + : ConstantUImmAsmOperandClass<8, [ConstantUImm10AsmOperandClass]>; +def ConstantUImm7AsmOperandClass + : ConstantUImmAsmOperandClass<7, [ConstantUImm8AsmOperandClass]>; +def ConstantUImm6AsmOperandClass + : ConstantUImmAsmOperandClass<6, [ConstantUImm7AsmOperandClass]>; +def ConstantSImm6AsmOperandClass + : ConstantSImmAsmOperandClass<6, [ConstantUImm7AsmOperandClass]>; +def ConstantUImm5Plus1AsmOperandClass + : ConstantUImmAsmOperandClass<5, [ConstantUImm6AsmOperandClass], 1>; +def ConstantUImm5Plus32AsmOperandClass + : ConstantUImmAsmOperandClass<5, [ConstantUImm6AsmOperandClass], 32>; +def ConstantUImm5Plus33AsmOperandClass + : ConstantUImmAsmOperandClass<5, [ConstantUImm6AsmOperandClass], 33>; +def ConstantUImm5Plus32NormalizeAsmOperandClass + : ConstantUImmAsmOperandClass<5, [ConstantUImm6AsmOperandClass], 32> { + let Name = "ConstantUImm5_32_Norm"; + // We must also subtract 32 when we render the operand. + let RenderMethod = "addConstantUImmOperands<5, 32, -32>"; +} +def ConstantUImm5Lsl2AsmOperandClass : AsmOperandClass { + let Name = "UImm5Lsl2"; + let RenderMethod = "addImmOperands"; + let PredicateMethod = "isScaledUImm<5, 2>"; + let SuperClasses = [ConstantUImm6AsmOperandClass]; + let DiagnosticType = "UImm5_Lsl2"; +} +def ConstantUImm5ReportUImm6AsmOperandClass + : ConstantUImmAsmOperandClass<5, [ConstantUImm6AsmOperandClass]> { + let Name = "ConstantUImm5_0_Report_UImm6"; + let DiagnosticType = "UImm5_0_Report_UImm6"; +} +def ConstantUImm5AsmOperandClass + : ConstantUImmAsmOperandClass<5, [ConstantUImm6AsmOperandClass]>; +def ConstantUImm4AsmOperandClass + : ConstantUImmAsmOperandClass< + 4, [ConstantUImm5AsmOperandClass, + ConstantUImm5Plus32AsmOperandClass, + ConstantUImm5Plus32NormalizeAsmOperandClass]>; +def ConstantUImm3AsmOperandClass + : ConstantUImmAsmOperandClass<3, [ConstantUImm4AsmOperandClass]>; +def ConstantUImm2Plus1AsmOperandClass + : ConstantUImmAsmOperandClass<2, [ConstantUImm3AsmOperandClass], 1>; +def ConstantUImm2AsmOperandClass + : ConstantUImmAsmOperandClass<2, [ConstantUImm3AsmOperandClass]>; +def ConstantUImm1AsmOperandClass + : ConstantUImmAsmOperandClass<1, [ConstantUImm2AsmOperandClass]>; +def ConstantImmzAsmOperandClass : AsmOperandClass { + let Name = "ConstantImmz"; + let RenderMethod = "addConstantUImmOperands<1>"; + let PredicateMethod = "isConstantImmz"; + let SuperClasses = [ConstantUImm1AsmOperandClass]; + let DiagnosticType = "Immz"; +} + +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 imm64: Operand<i64>; + +def simm6 : Operand<i32> { + let ParserMatchClass = ConstantSImm6AsmOperandClass; + let OperandType = "OPERAND_IMMEDIATE"; +} +def simm9 : Operand<i32>; +def simm10 : Operand<i32>; +def simm11 : Operand<i32>; + +def simm16 : Operand<i32> { + let DecoderMethod= "DecodeSimm16"; +} + +def simm19_lsl2 : Operand<i32> { + let EncoderMethod = "getSimm19Lsl2Encoding"; + let DecoderMethod = "DecodeSimm19Lsl2"; + let ParserMatchClass = MipsJumpTargetAsmOperand; +} + +def simm18_lsl3 : Operand<i32> { + let EncoderMethod = "getSimm18Lsl3Encoding"; + let DecoderMethod = "DecodeSimm18Lsl3"; + let ParserMatchClass = MipsJumpTargetAsmOperand; +} + +def simm20 : Operand<i32>; +def simm32 : Operand<i32>; + +def uimm20 : Operand<i32> { +} + +def simm16_64 : Operand<i64> { + let DecoderMethod = "DecodeSimm16"; +} + +// Zero +def uimmz : Operand<i32> { + let PrintMethod = "printUnsignedImm"; + let ParserMatchClass = ConstantImmzAsmOperandClass; +} + +// Unsigned Operands +foreach I = {1, 2, 3, 4, 5, 6, 7, 8, 10} in + def uimm # I : Operand<i32> { + let PrintMethod = "printUnsignedImm"; + let ParserMatchClass = + !cast<AsmOperandClass>("ConstantUImm" # I # "AsmOperandClass"); + } + +def uimm2_plus1 : Operand<i32> { + let PrintMethod = "printUnsignedImm"; + let EncoderMethod = "getUImmWithOffsetEncoding<2, 1>"; + let DecoderMethod = "DecodeUImmWithOffset<2, 1>"; + let ParserMatchClass = ConstantUImm2Plus1AsmOperandClass; +} + +def uimm5_plus1 : Operand<i32> { + let PrintMethod = "printUnsignedImm"; + let EncoderMethod = "getUImmWithOffsetEncoding<5, 1>"; + let DecoderMethod = "DecodeUImmWithOffset<5, 1>"; + let ParserMatchClass = ConstantUImm5Plus1AsmOperandClass; +} + +def uimm5_plus32 : Operand<i32> { + let PrintMethod = "printUnsignedImm"; + let ParserMatchClass = ConstantUImm5Plus32AsmOperandClass; +} + +def uimm5_plus33 : Operand<i32> { + let PrintMethod = "printUnsignedImm"; + let EncoderMethod = "getUImmWithOffsetEncoding<5, 1>"; + let DecoderMethod = "DecodeUImmWithOffset<5, 1>"; + let ParserMatchClass = ConstantUImm5Plus33AsmOperandClass; +} + +def uimm5_plus32_normalize : Operand<i32> { + let PrintMethod = "printUnsignedImm"; + let ParserMatchClass = ConstantUImm5Plus32NormalizeAsmOperandClass; +} + +def uimm5_lsl2 : Operand<OtherVT> { + let EncoderMethod = "getUImm5Lsl2Encoding"; + let DecoderMethod = "DecodeUImm5lsl2"; + let ParserMatchClass = ConstantUImm5Lsl2AsmOperandClass; +} + +def uimm5_plus32_normalize_64 : Operand<i64> { + let PrintMethod = "printUnsignedImm"; + let ParserMatchClass = ConstantUImm5Plus32NormalizeAsmOperandClass; +} + +foreach I = {5} in + def uimm # I # _64 : Operand<i64> { + let PrintMethod = "printUnsignedImm"; + let ParserMatchClass = + !cast<AsmOperandClass>("ConstantUImm" # I # "AsmOperandClass"); + } + +// Like uimm5_64 but reports a less confusing error for 32-63 when +// an instruction alias permits that. +def uimm5_64_report_uimm6 : Operand<i64> { + let PrintMethod = "printUnsignedImm"; + let ParserMatchClass = ConstantUImm5ReportUImm6AsmOperandClass; +} + +def uimm16 : Operand<i32> { + let PrintMethod = "printUnsignedImm"; +} + +def pcrel16 : Operand<i32> { +} + +def MipsMemAsmOperand : AsmOperandClass { + let Name = "Mem"; + let ParserMethod = "parseMemOperand"; +} + +def MipsMemSimm9AsmOperand : AsmOperandClass { + let Name = "MemOffsetSimm9"; + let SuperClasses = [MipsMemAsmOperand]; + let RenderMethod = "addMemOperands"; + let ParserMethod = "parseMemOperand"; + let PredicateMethod = "isMemWithSimmOffset<9>"; +} + +def MipsMemSimm9GPRAsmOperand : AsmOperandClass { + let Name = "MemOffsetSimm9GPR"; + let SuperClasses = [MipsMemAsmOperand]; + let RenderMethod = "addMemOperands"; + let ParserMethod = "parseMemOperand"; + let PredicateMethod = "isMemWithSimmOffsetGPR<9>"; +} + +def MipsMemSimm11AsmOperand : AsmOperandClass { + let Name = "MemOffsetSimm11"; + let SuperClasses = [MipsMemAsmOperand]; + let RenderMethod = "addMemOperands"; + let ParserMethod = "parseMemOperand"; + let PredicateMethod = "isMemWithSimmOffset<11>"; +} + +def MipsMemSimm16AsmOperand : AsmOperandClass { + let Name = "MemOffsetSimm16"; + let SuperClasses = [MipsMemAsmOperand]; + let RenderMethod = "addMemOperands"; + let ParserMethod = "parseMemOperand"; + let PredicateMethod = "isMemWithSimmOffset<16>"; +} + +def MipsInvertedImmoperand : AsmOperandClass { + let Name = "InvNum"; + let RenderMethod = "addImmOperands"; + let ParserMethod = "parseInvNum"; +} + +def InvertedImOperand : Operand<i32> { + let ParserMatchClass = MipsInvertedImmoperand; +} + +def InvertedImOperand64 : Operand<i64> { + let ParserMatchClass = MipsInvertedImmoperand; +} + +class mem_generic : Operand<iPTR> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops ptr_rc, simm16); + let EncoderMethod = "getMemEncoding"; + let ParserMatchClass = MipsMemAsmOperand; + let OperandType = "OPERAND_MEMORY"; +} + +// Address operand +def mem : mem_generic; + +// MSA specific address operand +def mem_msa : mem_generic { + let MIOperandInfo = (ops ptr_rc, simm10); + let EncoderMethod = "getMSAMemEncoding"; +} + +def mem_simm9 : mem_generic { + let MIOperandInfo = (ops ptr_rc, simm9); + let EncoderMethod = "getMemEncoding"; + let ParserMatchClass = MipsMemSimm9AsmOperand; +} + +def mem_simm9gpr : mem_generic { + let MIOperandInfo = (ops ptr_rc, simm9); + let EncoderMethod = "getMemEncoding"; + let ParserMatchClass = MipsMemSimm9GPRAsmOperand; +} + +def mem_simm11 : mem_generic { + let MIOperandInfo = (ops ptr_rc, simm11); + let EncoderMethod = "getMemEncoding"; + let ParserMatchClass = MipsMemSimm11AsmOperand; +} + +def mem_simm16 : mem_generic { + let MIOperandInfo = (ops ptr_rc, simm16); + let EncoderMethod = "getMemEncoding"; + let ParserMatchClass = MipsMemSimm16AsmOperand; +} + +def mem_ea : Operand<iPTR> { + let PrintMethod = "printMemOperandEA"; + let MIOperandInfo = (ops ptr_rc, simm16); + let EncoderMethod = "getMemEncoding"; + let OperandType = "OPERAND_MEMORY"; +} + +def PtrRC : Operand<iPTR> { + let MIOperandInfo = (ops ptr_rc); + let DecoderMethod = "DecodePtrRegisterClass"; + let ParserMatchClass = GPR32AsmOperand; +} + +// size operand of ins instruction +def size_ins : Operand<i32> { + let EncoderMethod = "getSizeInsEncoding"; + let DecoderMethod = "DecodeInsSize"; +} + +// Transformation Function - get the lower 16 bits. +def LO16 : SDNodeXForm<imm, [{ + return getImm(N, N->getZExtValue() & 0xFFFF); +}]>; + +// Transformation Function - get the higher 16 bits. +def HI16 : SDNodeXForm<imm, [{ + return getImm(N, (N->getZExtValue() >> 16) & 0xFFFF); +}]>; + +// Plus 1. +def Plus1 : SDNodeXForm<imm, [{ return getImm(N, N->getSExtValue() + 1); }]>; + +// Node immediate 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()); }]>; + +// Node immediate fits as 16-bit sign extended on target immediate. +// e.g. addi, andi +def immSExt16 : PatLeaf<(imm), [{ return isInt<16>(N->getSExtValue()); }]>; + +// Node immediate fits as 15-bit sign extended on target immediate. +// e.g. addi, andi +def immSExt15 : PatLeaf<(imm), [{ return isInt<15>(N->getSExtValue()); }]>; + +// Node immediate fits as 16-bit zero extended on target immediate. +// The LO16 param means that only the lower 16 bits of the node +// immediate are caught. +// e.g. addiu, sltiu +def immZExt16 : PatLeaf<(imm), [{ + if (N->getValueType(0) == MVT::i32) + return (uint32_t)N->getZExtValue() == (unsigned short)N->getZExtValue(); + else + return (uint64_t)N->getZExtValue() == (unsigned short)N->getZExtValue(); +}], LO16>; + +// Immediate can be loaded with LUi (32-bit int with lower 16-bit cleared). +def immLow16Zero : PatLeaf<(imm), [{ + int64_t Val = N->getSExtValue(); + return isInt<32>(Val) && !(Val & 0xffff); +}]>; + +// shamt field must fit in 5 bits. +def immZExt5 : ImmLeaf<i32, [{return Imm == (Imm & 0x1f);}]>; + +// True if (N + 1) fits in 16-bit field. +def immSExt16Plus1 : PatLeaf<(imm), [{ + return isInt<17>(N->getSExtValue()) && isInt<16>(N->getSExtValue() + 1); +}]>; + +// Mips Address Mode! SDNode frameindex could possibily be a match +// since load and store instructions from stack used it. +def addr : + ComplexPattern<iPTR, 2, "selectIntAddr", [frameindex]>; + +def addrRegImm : + ComplexPattern<iPTR, 2, "selectAddrRegImm", [frameindex]>; + +def addrRegReg : + ComplexPattern<iPTR, 2, "selectAddrRegReg", [frameindex]>; + +def addrDefault : + ComplexPattern<iPTR, 2, "selectAddrDefault", [frameindex]>; + +def addrimm10 : ComplexPattern<iPTR, 2, "selectIntAddrMSA", [frameindex]>; + +//===----------------------------------------------------------------------===// +// Instructions specific format +//===----------------------------------------------------------------------===// + +// Arithmetic and logical instructions with 3 register operands. +class ArithLogicR<string opstr, RegisterOperand RO, bit isComm = 0, + InstrItinClass Itin = NoItinerary, + SDPatternOperator OpNode = null_frag>: + InstSE<(outs RO:$rd), (ins RO:$rs, RO:$rt), + !strconcat(opstr, "\t$rd, $rs, $rt"), + [(set RO:$rd, (OpNode RO:$rs, RO:$rt))], Itin, FrmR, opstr> { + let isCommutable = isComm; + let isReMaterializable = 1; + let TwoOperandAliasConstraint = "$rd = $rs"; +} + +// Arithmetic and logical instructions with 2 register operands. +class ArithLogicI<string opstr, Operand Od, RegisterOperand RO, + InstrItinClass Itin = NoItinerary, + SDPatternOperator imm_type = null_frag, + SDPatternOperator OpNode = null_frag> : + InstSE<(outs RO:$rt), (ins RO:$rs, Od:$imm16), + !strconcat(opstr, "\t$rt, $rs, $imm16"), + [(set RO:$rt, (OpNode RO:$rs, imm_type:$imm16))], + Itin, FrmI, opstr> { + let isReMaterializable = 1; + let TwoOperandAliasConstraint = "$rs = $rt"; +} + +// Arithmetic Multiply ADD/SUB +class MArithR<string opstr, InstrItinClass itin, bit isComm = 0> : + InstSE<(outs), (ins GPR32Opnd:$rs, GPR32Opnd:$rt), + !strconcat(opstr, "\t$rs, $rt"), [], itin, FrmR, opstr> { + let Defs = [HI0, LO0]; + let Uses = [HI0, LO0]; + let isCommutable = isComm; +} + +// Logical +class LogicNOR<string opstr, RegisterOperand RO>: + InstSE<(outs RO:$rd), (ins RO:$rs, RO:$rt), + !strconcat(opstr, "\t$rd, $rs, $rt"), + [(set RO:$rd, (not (or RO:$rs, RO:$rt)))], II_NOR, FrmR, opstr> { + let isCommutable = 1; +} + +// Shifts +class shift_rotate_imm<string opstr, Operand ImmOpnd, + 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))], itin, FrmR, opstr> { + let TwoOperandAliasConstraint = "$rt = $rd"; +} + +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))], itin, FrmR, + opstr>; + +// Load Upper Immediate +class LoadUpper<string opstr, RegisterOperand RO, Operand Imm>: + InstSE<(outs RO:$rt), (ins Imm:$imm16), !strconcat(opstr, "\t$rt, $imm16"), + [], II_LUI, FrmI, opstr>, IsAsCheapAsAMove { + let hasSideEffects = 0; + let isReMaterializable = 1; +} + +// Memory Load/Store +class Load<string opstr, DAGOperand RO, SDPatternOperator OpNode = null_frag, + InstrItinClass Itin = NoItinerary, ComplexPattern Addr = addr> : + InstSE<(outs RO:$rt), (ins mem:$addr), !strconcat(opstr, "\t$rt, $addr"), + [(set RO:$rt, (OpNode Addr:$addr))], Itin, FrmI, opstr> { + let DecoderMethod = "DecodeMem"; + let canFoldAsLoad = 1; + let mayLoad = 1; +} + +class StoreMemory<string opstr, DAGOperand RO, DAGOperand MO, + SDPatternOperator OpNode = null_frag, + InstrItinClass Itin = NoItinerary, ComplexPattern Addr = addr> : + InstSE<(outs), (ins RO:$rt, MO:$addr), !strconcat(opstr, "\t$rt, $addr"), + [(OpNode RO:$rt, Addr:$addr)], Itin, FrmI, opstr> { + let DecoderMethod = "DecodeMem"; + let mayStore = 1; +} + +class Store<string opstr, DAGOperand RO, SDPatternOperator OpNode = null_frag, + InstrItinClass Itin = NoItinerary, ComplexPattern Addr = addr> : + StoreMemory<opstr, RO, mem, OpNode, Itin, Addr>; + +// Load/Store Left/Right +let canFoldAsLoad = 1 in +class LoadLeftRight<string opstr, SDNode OpNode, RegisterOperand RO, + InstrItinClass Itin> : + InstSE<(outs RO:$rt), (ins mem:$addr, RO:$src), + !strconcat(opstr, "\t$rt, $addr"), + [(set RO:$rt, (OpNode addr:$addr, RO:$src))], Itin, FrmI> { + let DecoderMethod = "DecodeMem"; + string Constraints = "$src = $rt"; +} + +class StoreLeftRight<string opstr, SDNode OpNode, RegisterOperand RO, + InstrItinClass Itin> : + InstSE<(outs), (ins RO:$rt, mem:$addr), !strconcat(opstr, "\t$rt, $addr"), + [(OpNode RO:$rt, addr:$addr)], Itin, FrmI> { + let DecoderMethod = "DecodeMem"; +} + +// COP2 Load/Store +class LW_FT2<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, opstr> { + let DecoderMethod = "DecodeFMem2"; + let mayLoad = 1; +} + +class SW_FT2<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, opstr> { + let DecoderMethod = "DecodeFMem2"; + let mayStore = 1; +} + +// COP3 Load/Store +class LW_FT3<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, opstr> { + let DecoderMethod = "DecodeFMem3"; + let mayLoad = 1; +} + +class SW_FT3<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, opstr> { + let DecoderMethod = "DecodeFMem3"; + let mayStore = 1; +} + +// Conditional Branch +class CBranch<string opstr, DAGOperand opnd, PatFrag cond_op, + RegisterOperand RO, bit DelaySlot = 1> : + InstSE<(outs), (ins RO:$rs, RO:$rt, opnd:$offset), + !strconcat(opstr, "\t$rs, $rt, $offset"), + [(brcond (i32 (cond_op RO:$rs, RO:$rt)), bb:$offset)], II_BCC, + FrmI, opstr> { + let isBranch = 1; + let isTerminator = 1; + let hasDelaySlot = DelaySlot; + let Defs = [AT]; +} + +class CBranchZero<string opstr, DAGOperand opnd, PatFrag cond_op, + RegisterOperand RO, bit DelaySlot = 1> : + InstSE<(outs), (ins RO:$rs, opnd:$offset), + !strconcat(opstr, "\t$rs, $offset"), + [(brcond (i32 (cond_op RO:$rs, 0)), bb:$offset)], II_BCCZ, + FrmI, opstr> { + let isBranch = 1; + let isTerminator = 1; + let hasDelaySlot = DelaySlot; + let Defs = [AT]; +} + +// SetCC +class SetCC_R<string opstr, PatFrag cond_op, RegisterOperand RO> : + InstSE<(outs GPR32Opnd:$rd), (ins RO:$rs, RO:$rt), + !strconcat(opstr, "\t$rd, $rs, $rt"), + [(set GPR32Opnd:$rd, (cond_op RO:$rs, RO:$rt))], + 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))], + II_SLTI_SLTIU, FrmI, opstr>; + +// Jump +class JumpFJ<DAGOperand opnd, string opstr, SDPatternOperator operator, + SDPatternOperator targetoperator, string bopstr> : + InstSE<(outs), (ins opnd:$target), !strconcat(opstr, "\t$target"), + [(operator targetoperator:$target)], II_J, FrmJ, bopstr> { + let isTerminator=1; + let isBarrier=1; + let hasDelaySlot = 1; + let DecoderMethod = "DecodeJumpTarget"; + let Defs = [AT]; +} + +// Unconditional branch +class UncondBranch<Instruction BEQInst> : + PseudoSE<(outs), (ins brtarget:$offset), [(br bb:$offset)], II_B>, + PseudoInstExpansion<(BEQInst ZERO, ZERO, brtarget:$offset)> { + let isBranch = 1; + let isTerminator = 1; + let isBarrier = 1; + let hasDelaySlot = 1; + let AdditionalPredicates = [RelocPIC]; + let Defs = [AT]; +} + +// Base class for indirect branch and return instruction classes. +let isTerminator=1, isBarrier=1, hasDelaySlot = 1 in +class JumpFR<string opstr, RegisterOperand RO, + SDPatternOperator operator = null_frag>: + InstSE<(outs), (ins RO:$rs), "jr\t$rs", [(operator RO:$rs)], II_JR, + FrmR, opstr>; + +// Indirect branch +class IndirectBranch<string opstr, RegisterOperand RO> : JumpFR<opstr, RO> { + let isBranch = 1; + let isIndirectBranch = 1; +} + +// Jump and Link (Call) +let isCall=1, hasDelaySlot=1, Defs = [RA] in { + class JumpLink<string opstr, DAGOperand opnd> : + InstSE<(outs), (ins opnd:$target), !strconcat(opstr, "\t$target"), + [(MipsJmpLink imm:$target)], II_JAL, FrmJ, opstr> { + let DecoderMethod = "DecodeJumpTarget"; + } + + class JumpLinkRegPseudo<RegisterOperand RO, Instruction JALRInst, + Register RetReg, RegisterOperand ResRO = RO>: + PseudoSE<(outs), (ins RO:$rs), [(MipsJmpLink RO:$rs)], II_JALR>, + PseudoInstExpansion<(JALRInst RetReg, ResRO:$rs)>; + + class JumpLinkReg<string opstr, RegisterOperand RO>: + InstSE<(outs RO:$rd), (ins RO:$rs), !strconcat(opstr, "\t$rd, $rs"), + [], II_JALR, FrmR, opstr>; + + class BGEZAL_FT<string opstr, DAGOperand opnd, + RegisterOperand RO, bit DelaySlot = 1> : + InstSE<(outs), (ins RO:$rs, opnd:$offset), + !strconcat(opstr, "\t$rs, $offset"), [], II_BCCZAL, FrmI, opstr> { + let hasDelaySlot = DelaySlot; + } + +} + +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), [], II_J>, + PseudoInstExpansion<(JumpInst jmptarget:$target)>; + + class TailCallReg<RegisterOperand RO, Instruction JRInst, + RegisterOperand ResRO = RO> : + PseudoSE<(outs), (ins RO:$rs), [(MipsTailCall RO:$rs)], II_JR>, + PseudoInstExpansion<(JRInst ResRO:$rs)>; +} + +class BAL_BR_Pseudo<Instruction RealInst> : + PseudoSE<(outs), (ins brtarget:$offset), [], II_BCCZAL>, + PseudoInstExpansion<(RealInst ZERO, brtarget:$offset)> { + let isBranch = 1; + let isTerminator = 1; + let isBarrier = 1; + let hasDelaySlot = 1; + let Defs = [RA]; +} + +// Syscall +class SYS_FT<string opstr> : + InstSE<(outs), (ins uimm20:$code_), + !strconcat(opstr, "\t$code_"), [], NoItinerary, FrmI, 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, opstr>; + +// (D)Eret +class ER_FT<string opstr> : + InstSE<(outs), (ins), + opstr, [], NoItinerary, FrmOther, opstr>; + +// Interrupts +class DEI_FT<string opstr, RegisterOperand RO> : + InstSE<(outs RO:$rt), (ins), + !strconcat(opstr, "\t$rt"), [], NoItinerary, FrmOther, opstr>; + +// Wait +class WAIT_FT<string opstr> : + InstSE<(outs), (ins), opstr, [], NoItinerary, FrmOther, opstr>; + +// Sync +let hasSideEffects = 1 in +class SYNC_FT<string opstr> : + InstSE<(outs), (ins i32imm:$stype), "sync $stype", [(MipsSync imm:$stype)], + NoItinerary, FrmOther, opstr>; + +class SYNCI_FT<string opstr> : + InstSE<(outs), (ins mem_simm16:$addr), !strconcat(opstr, "\t$addr"), [], + NoItinerary, FrmOther, opstr> { + let hasSideEffects = 1; + let DecoderMethod = "DecodeSyncI"; +} + +let hasSideEffects = 1 in +class TEQ_FT<string opstr, RegisterOperand RO> : + InstSE<(outs), (ins RO:$rs, RO:$rt, uimm16:$code_), + !strconcat(opstr, "\t$rs, $rt, $code_"), [], NoItinerary, + FrmI, opstr>; + +class TEQI_FT<string opstr, RegisterOperand RO> : + InstSE<(outs), (ins RO:$rs, uimm16:$imm16), + !strconcat(opstr, "\t$rs, $imm16"), [], NoItinerary, FrmOther, opstr>; +// Mul, Div +class Mult<string opstr, InstrItinClass itin, RegisterOperand RO, + list<Register> DefRegs> : + InstSE<(outs), (ins RO:$rs, RO:$rt), !strconcat(opstr, "\t$rs, $rt"), [], + itin, FrmR, opstr> { + let isCommutable = 1; + let Defs = DefRegs; + let hasSideEffects = 0; +} + +// Pseudo multiply/divide instruction with explicit accumulator register +// operands. +class MultDivPseudo<Instruction RealInst, RegisterClass R0, RegisterOperand R1, + SDPatternOperator OpNode, InstrItinClass Itin, + bit IsComm = 1, bit HasSideEffects = 0, + bit UsesCustomInserter = 0> : + PseudoSE<(outs R0:$ac), (ins R1:$rs, R1:$rt), + [(set R0:$ac, (OpNode R1:$rs, R1:$rt))], Itin>, + PseudoInstExpansion<(RealInst R1:$rs, R1:$rt)> { + let isCommutable = IsComm; + let hasSideEffects = HasSideEffects; + let usesCustomInserter = UsesCustomInserter; +} + +// Pseudo multiply add/sub instruction with explicit accumulator register +// operands. +class MAddSubPseudo<Instruction RealInst, SDPatternOperator OpNode, + InstrItinClass itin> + : PseudoSE<(outs ACC64:$ac), + (ins GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64:$acin), + [(set ACC64:$ac, + (OpNode GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64:$acin))], + itin>, + PseudoInstExpansion<(RealInst GPR32Opnd:$rs, GPR32Opnd:$rt)> { + string Constraints = "$acin = $ac"; +} + +class Div<string opstr, InstrItinClass itin, RegisterOperand RO, + list<Register> DefRegs> : + InstSE<(outs), (ins RO:$rs, RO:$rt), !strconcat(opstr, "\t$$zero, $rs, $rt"), + [], itin, FrmR, opstr> { + let Defs = DefRegs; +} + +// Move from Hi/Lo +class PseudoMFLOHI<RegisterClass DstRC, RegisterClass SrcRC, SDNode OpNode> + : PseudoSE<(outs DstRC:$rd), (ins SrcRC:$hilo), + [(set DstRC:$rd, (OpNode SrcRC:$hilo))], II_MFHI_MFLO>; + +class MoveFromLOHI<string opstr, RegisterOperand RO, Register UseReg>: + InstSE<(outs RO:$rd), (ins), !strconcat(opstr, "\t$rd"), [], II_MFHI_MFLO, + FrmR, opstr> { + let Uses = [UseReg]; + let hasSideEffects = 0; +} + +class PseudoMTLOHI<RegisterClass DstRC, RegisterClass SrcRC> + : PseudoSE<(outs DstRC:$lohi), (ins SrcRC:$lo, SrcRC:$hi), + [(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"), [], II_MTHI_MTLO, + FrmR, opstr> { + let Defs = DefRegs; + let hasSideEffects = 0; +} + +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, + !strconcat(opstr, "_lea")> { + let isCodeGenOnly = 1; + let DecoderMethod = "DecodeMem"; +} + +// Count Leading Ones/Zeros in Word +class CountLeading0<string opstr, RegisterOperand RO>: + InstSE<(outs RO:$rd), (ins RO:$rs), !strconcat(opstr, "\t$rd, $rs"), + [(set RO:$rd, (ctlz RO:$rs))], II_CLZ, FrmR, opstr>; + +class CountLeading1<string opstr, RegisterOperand RO>: + InstSE<(outs RO:$rd), (ins RO:$rs), !strconcat(opstr, "\t$rd, $rs"), + [(set RO:$rd, (ctlz (not RO:$rs)))], II_CLO, FrmR, opstr>; + +// Sign Extend in Register. +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))], itin, FrmR, opstr>; + +// Subword Swap +class SubwordSwap<string opstr, RegisterOperand RO, + InstrItinClass itin = NoItinerary>: + InstSE<(outs RO:$rd), (ins RO:$rt), !strconcat(opstr, "\t$rd, $rt"), [], itin, + FrmR, opstr> { + let hasSideEffects = 0; +} + +// Read Hardware +class ReadHardware<RegisterOperand CPURegOperand, RegisterOperand RO> : + InstSE<(outs CPURegOperand:$rt), (ins RO:$rd), "rdhwr\t$rt, $rd", [], + II_RDHWR, FrmR, "rdhwr">; + +// Ext and Ins +class ExtBase<string opstr, RegisterOperand RO, Operand PosOpnd, + Operand SizeOpnd, SDPatternOperator Op = null_frag> : + InstSE<(outs RO:$rt), (ins RO:$rs, PosOpnd:$pos, SizeOpnd:$size), + !strconcat(opstr, " $rt, $rs, $pos, $size"), + [(set RO:$rt, (Op RO:$rs, imm:$pos, imm:$size))], II_EXT, + FrmR, opstr>, ISA_MIPS32R2; + +class InsBase<string opstr, RegisterOperand RO, Operand PosOpnd, + SDPatternOperator Op = null_frag>: + InstSE<(outs RO:$rt), (ins RO:$rs, PosOpnd:$pos, size_ins:$size, RO:$src), + !strconcat(opstr, " $rt, $rs, $pos, $size"), + [(set RO:$rt, (Op RO:$rs, imm:$pos, imm:$size, RO:$src))], + II_INS, FrmR, opstr>, ISA_MIPS32R2 { + let Constraints = "$src = $rt"; +} + +// Atomic instructions with 2 source operands (ATOMIC_SWAP & ATOMIC_LOAD_*). +class Atomic2Ops<PatFrag Op, RegisterClass DRC> : + PseudoSE<(outs DRC:$dst), (ins PtrRC:$ptr, DRC:$incr), + [(set DRC:$dst, (Op iPTR:$ptr, DRC:$incr))]>; + +// Atomic Compare & Swap. +class AtomicCmpSwap<PatFrag Op, RegisterClass DRC> : + PseudoSE<(outs DRC:$dst), (ins PtrRC:$ptr, DRC:$cmp, DRC:$swap), + [(set DRC:$dst, (Op iPTR:$ptr, DRC:$cmp, DRC:$swap))]>; + +class LLBase<string opstr, RegisterOperand RO> : + InstSE<(outs RO:$rt), (ins mem:$addr), !strconcat(opstr, "\t$rt, $addr"), + [], NoItinerary, FrmI> { + let DecoderMethod = "DecodeMem"; + let mayLoad = 1; +} + +class SCBase<string opstr, RegisterOperand RO> : + InstSE<(outs RO:$dst), (ins RO:$rt, mem:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], NoItinerary, FrmI> { + let DecoderMethod = "DecodeMem"; + let mayStore = 1; + let Constraints = "$rt = $dst"; +} + +class MFC3OP<string asmstr, RegisterOperand RO, RegisterOperand RD> : + InstSE<(outs RO:$rt), (ins RD:$rd, uimm16:$sel), + !strconcat(asmstr, "\t$rt, $rd, $sel"), [], NoItinerary, FrmFR>; + +class MTC3OP<string asmstr, RegisterOperand RO, RegisterOperand RD> : + InstSE<(outs RO:$rd), (ins RD:$rt, uimm16:$sel), + !strconcat(asmstr, "\t$rt, $rd, $sel"), [], NoItinerary, FrmFR>; + +class TrapBase<Instruction RealInst> + : PseudoSE<(outs), (ins), [(trap)], NoItinerary>, + PseudoInstExpansion<(RealInst 0, 0)> { + let isBarrier = 1; + let isTerminator = 1; + let isCodeGenOnly = 1; +} + +//===----------------------------------------------------------------------===// +// Pseudo instructions +//===----------------------------------------------------------------------===// + +// Return RA. +let isReturn=1, isTerminator=1, hasDelaySlot=1, isBarrier=1, hasCtrlDep=1 in +def RetRA : PseudoSE<(outs), (ins), [(MipsRet)]>; + +let isReturn=1, isTerminator=1, isBarrier=1, hasCtrlDep=1, hasSideEffects=1 in +def ERet : PseudoSE<(outs), (ins), [(MipsERet)]>; + +let Defs = [SP], Uses = [SP], hasSideEffects = 1 in { +def ADJCALLSTACKDOWN : MipsPseudo<(outs), (ins i32imm:$amt), + [(callseq_start timm:$amt)]>; +def ADJCALLSTACKUP : MipsPseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), + [(callseq_end timm:$amt1, timm:$amt2)]>; +} + +let usesCustomInserter = 1 in { + def ATOMIC_LOAD_ADD_I8 : Atomic2Ops<atomic_load_add_8, GPR32>; + def ATOMIC_LOAD_ADD_I16 : Atomic2Ops<atomic_load_add_16, GPR32>; + def ATOMIC_LOAD_ADD_I32 : Atomic2Ops<atomic_load_add_32, GPR32>; + def ATOMIC_LOAD_SUB_I8 : Atomic2Ops<atomic_load_sub_8, GPR32>; + def ATOMIC_LOAD_SUB_I16 : Atomic2Ops<atomic_load_sub_16, GPR32>; + def ATOMIC_LOAD_SUB_I32 : Atomic2Ops<atomic_load_sub_32, GPR32>; + def ATOMIC_LOAD_AND_I8 : Atomic2Ops<atomic_load_and_8, GPR32>; + def ATOMIC_LOAD_AND_I16 : Atomic2Ops<atomic_load_and_16, GPR32>; + def ATOMIC_LOAD_AND_I32 : Atomic2Ops<atomic_load_and_32, GPR32>; + def ATOMIC_LOAD_OR_I8 : Atomic2Ops<atomic_load_or_8, GPR32>; + def ATOMIC_LOAD_OR_I16 : Atomic2Ops<atomic_load_or_16, GPR32>; + def ATOMIC_LOAD_OR_I32 : Atomic2Ops<atomic_load_or_32, GPR32>; + def ATOMIC_LOAD_XOR_I8 : Atomic2Ops<atomic_load_xor_8, GPR32>; + def ATOMIC_LOAD_XOR_I16 : Atomic2Ops<atomic_load_xor_16, GPR32>; + def ATOMIC_LOAD_XOR_I32 : Atomic2Ops<atomic_load_xor_32, GPR32>; + def ATOMIC_LOAD_NAND_I8 : Atomic2Ops<atomic_load_nand_8, GPR32>; + def ATOMIC_LOAD_NAND_I16 : Atomic2Ops<atomic_load_nand_16, GPR32>; + def ATOMIC_LOAD_NAND_I32 : Atomic2Ops<atomic_load_nand_32, GPR32>; + + def ATOMIC_SWAP_I8 : Atomic2Ops<atomic_swap_8, GPR32>; + def ATOMIC_SWAP_I16 : Atomic2Ops<atomic_swap_16, GPR32>; + def ATOMIC_SWAP_I32 : Atomic2Ops<atomic_swap_32, GPR32>; + + def ATOMIC_CMP_SWAP_I8 : AtomicCmpSwap<atomic_cmp_swap_8, GPR32>; + def ATOMIC_CMP_SWAP_I16 : AtomicCmpSwap<atomic_cmp_swap_16, GPR32>; + def ATOMIC_CMP_SWAP_I32 : AtomicCmpSwap<atomic_cmp_swap_32, GPR32>; +} + +/// Pseudo instructions for loading and storing accumulator registers. +let isPseudo = 1, isCodeGenOnly = 1 in { + def LOAD_ACC64 : Load<"", ACC64>; + def STORE_ACC64 : Store<"", ACC64>; +} + +// We need these two pseudo instructions to avoid offset calculation for long +// branches. See the comment in file MipsLongBranch.cpp for detailed +// explanation. + +// Expands to: lui $dst, %hi($tgt - $baltgt) +def LONG_BRANCH_LUi : PseudoSE<(outs GPR32Opnd:$dst), + (ins brtarget:$tgt, brtarget:$baltgt), []>; + +// Expands to: addiu $dst, $src, %lo($tgt - $baltgt) +def LONG_BRANCH_ADDiu : PseudoSE<(outs GPR32Opnd:$dst), + (ins GPR32Opnd:$src, brtarget:$tgt, brtarget:$baltgt), []>; + +//===----------------------------------------------------------------------===// +// Instruction definition +//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// +// MipsI Instructions +//===----------------------------------------------------------------------===// + +/// Arithmetic Instructions (ALU Immediate) +let AdditionalPredicates = [NotInMicroMips] in { +def ADDiu : MMRel, StdMMR6Rel, ArithLogicI<"addiu", simm16, GPR32Opnd, + II_ADDIU, immSExt16, add>, + ADDI_FM<0x9>, IsAsCheapAsAMove; +} +def ADDi : MMRel, ArithLogicI<"addi", simm16, GPR32Opnd>, ADDI_FM<0x8>, + ISA_MIPS1_NOT_32R6_64R6; +def SLTi : MMRel, SetCC_I<"slti", setlt, simm16, immSExt16, GPR32Opnd>, + SLTI_FM<0xa>; +def SLTiu : MMRel, SetCC_I<"sltiu", setult, simm16, immSExt16, GPR32Opnd>, + SLTI_FM<0xb>; +let AdditionalPredicates = [NotInMicroMips] in { +def ANDi : MMRel, StdMMR6Rel, + ArithLogicI<"andi", uimm16, GPR32Opnd, II_ANDI, immZExt16, and>, + ADDI_FM<0xc>; +} +def ORi : MMRel, StdMMR6Rel, + ArithLogicI<"ori", uimm16, GPR32Opnd, II_ORI, immZExt16, or>, + ADDI_FM<0xd>; +def XORi : MMRel, StdMMR6Rel, + ArithLogicI<"xori", uimm16, GPR32Opnd, II_XORI, immZExt16, xor>, + ADDI_FM<0xe>; +def LUi : MMRel, LoadUpper<"lui", GPR32Opnd, uimm16>, LUI_FM; +let AdditionalPredicates = [NotInMicroMips] in { +/// Arithmetic Instructions (3-Operand, R-Type) +def ADDu : MMRel, StdMMR6Rel, ArithLogicR<"addu", GPR32Opnd, 1, II_ADDU, add>, + ADD_FM<0, 0x21>; +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, II_MUL, mul>, + ADD_FM<0x1c, 2>, ISA_MIPS32_NOT_32R6_64R6; +def ADD : MMRel, StdMMR6Rel, 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>; +let AdditionalPredicates = [NotInMicroMips] in { +def AND : MMRel, StdMMR6Rel, ArithLogicR<"and", GPR32Opnd, 1, II_AND, and>, + ADD_FM<0, 0x24>; +def OR : MMRel, StdMMR6Rel, ArithLogicR<"or", GPR32Opnd, 1, II_OR, or>, + ADD_FM<0, 0x25>; +def XOR : MMRel, StdMMR6Rel, ArithLogicR<"xor", GPR32Opnd, 1, II_XOR, xor>, + ADD_FM<0, 0x26>; +} +def NOR : MMRel, StdMMR6Rel, LogicNOR<"nor", GPR32Opnd>, ADD_FM<0, 0x27>; + +/// Shift Instructions +let AdditionalPredicates = [NotInMicroMips] in { +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 +def ROTR : MMRel, shift_rotate_imm<"rotr", uimm5, GPR32Opnd, II_ROTR, rotr, + immZExt5>, + SRA_FM<2, 1>, ISA_MIPS32R2; +def ROTRV : MMRel, shift_rotate_reg<"rotrv", GPR32Opnd, II_ROTRV, rotr>, + SRLV_FM<6, 1>, ISA_MIPS32R2; + +/// Load and Store Instructions +/// aligned +def LB : Load<"lb", GPR32Opnd, sextloadi8, 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, II_LH, addrDefault>, MMRel, + LW_FM<0x21>; +def LHu : Load<"lhu", GPR32Opnd, zextloadi16, II_LHU>, MMRel, LW_FM<0x25>; +let AdditionalPredicates = [NotInMicroMips] in { +def LW : StdMMR6Rel, Load<"lw", GPR32Opnd, load, II_LW, addrDefault>, MMRel, + LW_FM<0x23>; +} +def SB : StdMMR6Rel, Store<"sb", GPR32Opnd, truncstorei8, II_SB>, MMRel, + LW_FM<0x28>; +def SH : Store<"sh", GPR32Opnd, truncstorei16, II_SH>, MMRel, LW_FM<0x29>; +let AdditionalPredicates = [NotInMicroMips] in { +def SW : Store<"sw", GPR32Opnd, store, II_SW>, MMRel, LW_FM<0x2b>; +} + +/// load/store left/right +let EncodingPredicates = []<Predicate>, // FIXME: Lack of HasStdEnc is probably a bug + AdditionalPredicates = [NotInMicroMips] in { +def LWL : LoadLeftRight<"lwl", MipsLWL, GPR32Opnd, II_LWL>, LW_FM<0x22>, + ISA_MIPS1_NOT_32R6_64R6; +def LWR : LoadLeftRight<"lwr", MipsLWR, GPR32Opnd, II_LWR>, LW_FM<0x26>, + ISA_MIPS1_NOT_32R6_64R6; +def SWL : StoreLeftRight<"swl", MipsSWL, GPR32Opnd, II_SWL>, LW_FM<0x2a>, + ISA_MIPS1_NOT_32R6_64R6; +def SWR : StoreLeftRight<"swr", MipsSWR, GPR32Opnd, II_SWR>, LW_FM<0x2e>, + ISA_MIPS1_NOT_32R6_64R6; +} + +let AdditionalPredicates = [NotInMicroMips] in { +// COP2 Memory Instructions +def LWC2 : LW_FT2<"lwc2", COP2Opnd, NoItinerary, load>, LW_FM<0x32>, + ISA_MIPS1_NOT_32R6_64R6; +def SWC2 : SW_FT2<"swc2", COP2Opnd, NoItinerary, store>, LW_FM<0x3a>, + ISA_MIPS1_NOT_32R6_64R6; +def LDC2 : LW_FT2<"ldc2", COP2Opnd, NoItinerary, load>, LW_FM<0x36>, + ISA_MIPS2_NOT_32R6_64R6; +def SDC2 : SW_FT2<"sdc2", COP2Opnd, NoItinerary, store>, LW_FM<0x3e>, + ISA_MIPS2_NOT_32R6_64R6; + +// COP3 Memory Instructions +let DecoderNamespace = "COP3_" in { + def LWC3 : LW_FT3<"lwc3", COP3Opnd, NoItinerary, load>, LW_FM<0x33>; + def SWC3 : SW_FT3<"swc3", COP3Opnd, NoItinerary, store>, LW_FM<0x3b>; + def LDC3 : LW_FT3<"ldc3", COP3Opnd, NoItinerary, load>, LW_FM<0x37>, + ISA_MIPS2; + def SDC3 : SW_FT3<"sdc3", COP3Opnd, NoItinerary, store>, LW_FM<0x3f>, + ISA_MIPS2; +} +} + +def SYNC : MMRel, StdMMR6Rel, SYNC_FT<"sync">, SYNC_FM, ISA_MIPS32; +def SYNCI : MMRel, StdMMR6Rel, SYNCI_FT<"synci">, SYNCI_FM, ISA_MIPS32R2; + +let AdditionalPredicates = [NotInMicroMips] in { + def TEQ : MMRel, TEQ_FT<"teq", GPR32Opnd>, TEQ_FM<0x34>, ISA_MIPS2; + def TGE : MMRel, TEQ_FT<"tge", GPR32Opnd>, TEQ_FM<0x30>, ISA_MIPS2; + def TGEU : MMRel, TEQ_FT<"tgeu", GPR32Opnd>, TEQ_FM<0x31>, ISA_MIPS2; + def TLT : MMRel, TEQ_FT<"tlt", GPR32Opnd>, TEQ_FM<0x32>, ISA_MIPS2; + def TLTU : MMRel, TEQ_FT<"tltu", GPR32Opnd>, TEQ_FM<0x33>, ISA_MIPS2; + def TNE : MMRel, TEQ_FT<"tne", GPR32Opnd>, TEQ_FM<0x36>, ISA_MIPS2; +} + +def TEQI : MMRel, TEQI_FT<"teqi", GPR32Opnd>, TEQI_FM<0xc>, + ISA_MIPS2_NOT_32R6_64R6; +def TGEI : MMRel, TEQI_FT<"tgei", GPR32Opnd>, TEQI_FM<0x8>, + ISA_MIPS2_NOT_32R6_64R6; +def TGEIU : MMRel, TEQI_FT<"tgeiu", GPR32Opnd>, TEQI_FM<0x9>, + ISA_MIPS2_NOT_32R6_64R6; +def TLTI : MMRel, TEQI_FT<"tlti", GPR32Opnd>, TEQI_FM<0xa>, + ISA_MIPS2_NOT_32R6_64R6; +def TTLTIU : MMRel, TEQI_FT<"tltiu", GPR32Opnd>, TEQI_FM<0xb>, + ISA_MIPS2_NOT_32R6_64R6; +def TNEI : MMRel, TEQI_FT<"tnei", GPR32Opnd>, TEQI_FM<0xe>, + ISA_MIPS2_NOT_32R6_64R6; + +let AdditionalPredicates = [NotInMicroMips] in { +def BREAK : MMRel, StdMMR6Rel, BRK_FT<"break">, BRK_FM<0xd>; +} +def SYSCALL : MMRel, SYS_FT<"syscall">, SYS_FM<0xc>; +def TRAP : TrapBase<BREAK>; +def SDBBP : MMRel, SYS_FT<"sdbbp">, SDBBP_FM, ISA_MIPS32_NOT_32R6_64R6; + +let AdditionalPredicates = [NotInMicroMips] in { + def ERET : MMRel, ER_FT<"eret">, ER_FM<0x18, 0x0>, INSN_MIPS3_32; + def ERETNC : MMRel, ER_FT<"eretnc">, ER_FM<0x18, 0x1>, ISA_MIPS32R5; + def DERET : MMRel, ER_FT<"deret">, ER_FM<0x1f, 0x0>, ISA_MIPS32; +} + +let AdditionalPredicates = [NotInMicroMips] in { + def EI : MMRel, StdMMR6Rel, DEI_FT<"ei", GPR32Opnd>, EI_FM<1>, ISA_MIPS32R2; + def DI : MMRel, StdMMR6Rel, DEI_FT<"di", GPR32Opnd>, EI_FM<0>, ISA_MIPS32R2; +} + +let EncodingPredicates = []<Predicate>, // FIXME: Lack of HasStdEnc is probably a bug + AdditionalPredicates = [NotInMicroMips] in { +def WAIT : WAIT_FT<"wait">, WAIT_FM; + +/// Load-linked, Store-conditional +def LL : LLBase<"ll", GPR32Opnd>, LW_FM<0x30>, ISA_MIPS2_NOT_32R6_64R6; +def SC : SCBase<"sc", GPR32Opnd>, LW_FM<0x38>, ISA_MIPS2_NOT_32R6_64R6; +} + +/// Jump and Branch Instructions +def J : MMRel, JumpFJ<jmptarget, "j", br, bb, "j">, FJ<2>, + AdditionalRequires<[RelocStatic]>, IsBranch; +def JR : MMRel, IndirectBranch<"jr", GPR32Opnd>, MTLO_FM<8>; +def BEQ : MMRel, CBranch<"beq", brtarget, seteq, GPR32Opnd>, BEQ_FM<4>; +def BEQL : MMRel, CBranch<"beql", brtarget, seteq, GPR32Opnd, 0>, + BEQ_FM<20>, ISA_MIPS2_NOT_32R6_64R6; +def BNE : MMRel, CBranch<"bne", brtarget, setne, GPR32Opnd>, BEQ_FM<5>; +def BNEL : MMRel, CBranch<"bnel", brtarget, setne, GPR32Opnd, 0>, + BEQ_FM<21>, ISA_MIPS2_NOT_32R6_64R6; +def BGEZ : MMRel, CBranchZero<"bgez", brtarget, setge, GPR32Opnd>, + BGEZ_FM<1, 1>; +def BGEZL : MMRel, CBranchZero<"bgezl", brtarget, setge, GPR32Opnd, 0>, + BGEZ_FM<1, 3>, ISA_MIPS2_NOT_32R6_64R6; +def BGTZ : MMRel, CBranchZero<"bgtz", brtarget, setgt, GPR32Opnd>, + BGEZ_FM<7, 0>; +def BGTZL : MMRel, CBranchZero<"bgtzl", brtarget, setgt, GPR32Opnd, 0>, + BGEZ_FM<23, 0>, ISA_MIPS2_NOT_32R6_64R6; +def BLEZ : MMRel, CBranchZero<"blez", brtarget, setle, GPR32Opnd>, + BGEZ_FM<6, 0>; +def BLEZL : MMRel, CBranchZero<"blezl", brtarget, setle, GPR32Opnd, 0>, + BGEZ_FM<22, 0>, ISA_MIPS2_NOT_32R6_64R6; +def BLTZ : MMRel, CBranchZero<"bltz", brtarget, setlt, GPR32Opnd>, + BGEZ_FM<1, 0>; +def BLTZL : MMRel, CBranchZero<"bltzl", brtarget, setlt, GPR32Opnd, 0>, + BGEZ_FM<1, 2>, ISA_MIPS2_NOT_32R6_64R6; +def B : UncondBranch<BEQ>; + +def JAL : MMRel, JumpLink<"jal", calltarget>, FJ<3>; +let AdditionalPredicates = [NotInMicroMips] in { + def JALR : JumpLinkReg<"jalr", GPR32Opnd>, JALR_FM; + def JALRPseudo : JumpLinkRegPseudo<GPR32Opnd, JALR, RA>; +} + +def JALX : MMRel, JumpLink<"jalx", calltarget>, FJ<0x1D>, + ISA_MIPS32_NOT_32R6_64R6; +def BGEZAL : MMRel, BGEZAL_FT<"bgezal", brtarget, GPR32Opnd>, BGEZAL_FM<0x11>, + ISA_MIPS1_NOT_32R6_64R6; +def BGEZALL : MMRel, BGEZAL_FT<"bgezall", brtarget, GPR32Opnd, 0>, + BGEZAL_FM<0x13>, ISA_MIPS2_NOT_32R6_64R6; +def BLTZAL : MMRel, BGEZAL_FT<"bltzal", brtarget, GPR32Opnd>, BGEZAL_FM<0x10>, + ISA_MIPS1_NOT_32R6_64R6; +def BLTZALL : MMRel, BGEZAL_FT<"bltzall", brtarget, GPR32Opnd, 0>, + BGEZAL_FM<0x12>, ISA_MIPS2_NOT_32R6_64R6; +def BAL_BR : BAL_BR_Pseudo<BGEZAL>; +def TAILCALL : TailCall<J>; +def TAILCALL_R : TailCallReg<GPR32Opnd, JR>; + +// Indirect branches are matched as PseudoIndirectBranch/PseudoIndirectBranch64 +// then are expanded to JR, JR64, JALR, or JALR64 depending on the ISA. +class PseudoIndirectBranchBase<RegisterOperand RO> : + MipsPseudo<(outs), (ins RO:$rs), [(brind RO:$rs)], + II_IndirectBranchPseudo> { + let isTerminator=1; + let isBarrier=1; + let hasDelaySlot = 1; + let isBranch = 1; + let isIndirectBranch = 1; +} + +def PseudoIndirectBranch : PseudoIndirectBranchBase<GPR32Opnd>; + +// Return instructions are matched as a RetRA instruction, then are expanded +// into PseudoReturn/PseudoReturn64 after register allocation. Finally, +// MipsAsmPrinter expands this into JR, JR64, JALR, or JALR64 depending on the +// ISA. +class PseudoReturnBase<RegisterOperand RO> : MipsPseudo<(outs), (ins RO:$rs), + [], II_ReturnPseudo> { + let isTerminator = 1; + let isBarrier = 1; + let hasDelaySlot = 1; + let isReturn = 1; + let isCodeGenOnly = 1; + let hasCtrlDep = 1; + let hasExtraSrcRegAllocReq = 1; +} + +def PseudoReturn : PseudoReturnBase<GPR32Opnd>; + +// Exception handling related node and instructions. +// The conversion sequence is: +// ISD::EH_RETURN -> MipsISD::EH_RETURN -> +// MIPSeh_return -> (stack change + indirect branch) +// +// MIPSeh_return takes the place of regular return instruction +// but takes two arguments (V1, V0) which are used for storing +// the offset and return address respectively. +def SDT_MipsEHRET : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisPtrTy<1>]>; + +def MIPSehret : SDNode<"MipsISD::EH_RETURN", SDT_MipsEHRET, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; + +let Uses = [V0, V1], isTerminator = 1, isReturn = 1, isBarrier = 1 in { + def MIPSeh_return32 : MipsPseudo<(outs), (ins GPR32:$spoff, GPR32:$dst), + [(MIPSehret GPR32:$spoff, GPR32:$dst)]>; + def MIPSeh_return64 : MipsPseudo<(outs), (ins GPR64:$spoff, + GPR64:$dst), + [(MIPSehret GPR64:$spoff, GPR64:$dst)]>; +} + +/// Multiply and Divide Instructions. +def MULT : MMRel, Mult<"mult", II_MULT, GPR32Opnd, [HI0, LO0]>, + MULT_FM<0, 0x18>, ISA_MIPS1_NOT_32R6_64R6; +def MULTu : MMRel, Mult<"multu", II_MULTU, GPR32Opnd, [HI0, LO0]>, + MULT_FM<0, 0x19>, ISA_MIPS1_NOT_32R6_64R6; +def SDIV : MMRel, Div<"div", II_DIV, GPR32Opnd, [HI0, LO0]>, + MULT_FM<0, 0x1a>, ISA_MIPS1_NOT_32R6_64R6; +def UDIV : MMRel, Div<"divu", II_DIVU, GPR32Opnd, [HI0, LO0]>, + MULT_FM<0, 0x1b>, ISA_MIPS1_NOT_32R6_64R6; + +def MTHI : MMRel, MoveToLOHI<"mthi", GPR32Opnd, [HI0]>, MTLO_FM<0x11>, + ISA_MIPS1_NOT_32R6_64R6; +def MTLO : MMRel, MoveToLOHI<"mtlo", GPR32Opnd, [LO0]>, MTLO_FM<0x13>, + ISA_MIPS1_NOT_32R6_64R6; +let EncodingPredicates = []<Predicate>, // FIXME: Lack of HasStdEnc is probably a bug + AdditionalPredicates = [NotInMicroMips] in { +def MFHI : MMRel, MoveFromLOHI<"mfhi", GPR32Opnd, AC0>, MFLO_FM<0x10>, + ISA_MIPS1_NOT_32R6_64R6; +def MFLO : MMRel, MoveFromLOHI<"mflo", GPR32Opnd, AC0>, MFLO_FM<0x12>, + ISA_MIPS1_NOT_32R6_64R6; +} + +/// Sign Ext In Register Instructions. +def SEB : MMRel, StdMMR6Rel, SignExtInReg<"seb", i8, GPR32Opnd, II_SEB>, + SEB_FM<0x10, 0x20>, ISA_MIPS32R2; +def SEH : MMRel, StdMMR6Rel, SignExtInReg<"seh", i16, GPR32Opnd, II_SEH>, + SEB_FM<0x18, 0x20>, ISA_MIPS32R2; + +/// Count Leading +def CLZ : MMRel, CountLeading0<"clz", GPR32Opnd>, CLO_FM<0x20>, + ISA_MIPS32_NOT_32R6_64R6; +def CLO : MMRel, CountLeading1<"clo", GPR32Opnd>, CLO_FM<0x21>, + ISA_MIPS32_NOT_32R6_64R6; + +let AdditionalPredicates = [NotInMicroMips] in { + /// Word Swap Bytes Within Halfwords + def WSBH : MMRel, SubwordSwap<"wsbh", GPR32Opnd, II_WSBH>, SEB_FM<2, 0x20>, + ISA_MIPS32R2; +} + +/// No operation. +def NOP : PseudoSE<(outs), (ins), []>, PseudoInstExpansion<(SLL ZERO, ZERO, 0)>; + +// FrameIndexes are legalized when they are operands from load/store +// instructions. The same not happens for stack address copies, so an +// add op with mem ComplexPattern is used and the stack address copy +// can be matched. It's similar to Sparc LEA_ADDRi +def LEA_ADDiu : MMRel, EffectiveAddress<"addiu", GPR32Opnd>, LW_FM<9>; + +// MADD*/MSUB* +def MADD : MMRel, MArithR<"madd", II_MADD, 1>, MULT_FM<0x1c, 0>, + ISA_MIPS32_NOT_32R6_64R6; +def MADDU : MMRel, MArithR<"maddu", II_MADDU, 1>, MULT_FM<0x1c, 1>, + ISA_MIPS32_NOT_32R6_64R6; +def MSUB : MMRel, MArithR<"msub", II_MSUB>, MULT_FM<0x1c, 4>, + ISA_MIPS32_NOT_32R6_64R6; +def MSUBU : MMRel, MArithR<"msubu", II_MSUBU>, MULT_FM<0x1c, 5>, + ISA_MIPS32_NOT_32R6_64R6; + +let AdditionalPredicates = [NotDSP] in { +def PseudoMULT : MultDivPseudo<MULT, ACC64, GPR32Opnd, MipsMult, II_MULT>, + ISA_MIPS1_NOT_32R6_64R6; +def PseudoMULTu : MultDivPseudo<MULTu, ACC64, GPR32Opnd, MipsMultu, II_MULTU>, + ISA_MIPS1_NOT_32R6_64R6; +def PseudoMFHI : PseudoMFLOHI<GPR32, ACC64, MipsMFHI>, ISA_MIPS1_NOT_32R6_64R6; +def PseudoMFLO : PseudoMFLOHI<GPR32, ACC64, MipsMFLO>, ISA_MIPS1_NOT_32R6_64R6; +def PseudoMTLOHI : PseudoMTLOHI<ACC64, GPR32>, ISA_MIPS1_NOT_32R6_64R6; +def PseudoMADD : MAddSubPseudo<MADD, MipsMAdd, II_MADD>, + ISA_MIPS32_NOT_32R6_64R6; +def PseudoMADDU : MAddSubPseudo<MADDU, MipsMAddu, II_MADDU>, + ISA_MIPS32_NOT_32R6_64R6; +def PseudoMSUB : MAddSubPseudo<MSUB, MipsMSub, II_MSUB>, + ISA_MIPS32_NOT_32R6_64R6; +def PseudoMSUBU : MAddSubPseudo<MSUBU, MipsMSubu, II_MSUBU>, + ISA_MIPS32_NOT_32R6_64R6; +} + +def PseudoSDIV : MultDivPseudo<SDIV, ACC64, GPR32Opnd, MipsDivRem, II_DIV, + 0, 1, 1>, ISA_MIPS1_NOT_32R6_64R6; +def PseudoUDIV : MultDivPseudo<UDIV, ACC64, GPR32Opnd, MipsDivRemU, II_DIVU, + 0, 1, 1>, ISA_MIPS1_NOT_32R6_64R6; +let AdditionalPredicates = [NotInMicroMips] in { +def RDHWR : MMRel, ReadHardware<GPR32Opnd, HWRegsOpnd>, RDHWR_FM; +} +// TODO: Add '0 < pos+size <= 32' constraint check to ext instruction +def EXT : MMRel, ExtBase<"ext", GPR32Opnd, uimm5, uimm5_plus1, MipsExt>, + EXT_FM<0>; +def INS : MMRel, InsBase<"ins", GPR32Opnd, uimm5, MipsIns>, EXT_FM<4>; + +/// Move Control Registers From/To CPU Registers +def MFC0 : MFC3OP<"mfc0", GPR32Opnd, COP0Opnd>, MFC3OP_FM<0x10, 0>, ISA_MIPS32; +def MTC0 : MTC3OP<"mtc0", COP0Opnd, GPR32Opnd>, MFC3OP_FM<0x10, 4>, ISA_MIPS32; +def MFC2 : MFC3OP<"mfc2", GPR32Opnd, COP2Opnd>, MFC3OP_FM<0x12, 0>; +def MTC2 : MTC3OP<"mtc2", COP2Opnd, GPR32Opnd>, MFC3OP_FM<0x12, 4>; + +class Barrier<string asmstr> : InstSE<(outs), (ins), asmstr, [], NoItinerary, + FrmOther, asmstr>; +def SSNOP : MMRel, StdMMR6Rel, Barrier<"ssnop">, BARRIER_FM<1>; +def EHB : MMRel, Barrier<"ehb">, BARRIER_FM<3>; +def PAUSE : MMRel, StdMMR6Rel, Barrier<"pause">, BARRIER_FM<5>, ISA_MIPS32R2; + +// JR_HB and JALR_HB are defined here using the new style naming +// scheme because some of this code is shared with Mips32r6InstrInfo.td +// and because of that it doesn't follow the naming convention of the +// rest of the file. To avoid a mixture of old vs new style, the new +// style was chosen. +class JR_HB_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs); + dag InOperandList = (ins GPROpnd:$rs); + string AsmString = !strconcat(instr_asm, "\t$rs"); + list<dag> Pattern = []; +} + +class JALR_HB_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs"); + list<dag> Pattern = []; +} + +class JR_HB_DESC : InstSE<(outs), (ins), "", [], NoItinerary, FrmJ>, + JR_HB_DESC_BASE<"jr.hb", GPR32Opnd> { + let isBranch=1; + let isIndirectBranch=1; + let hasDelaySlot=1; + let isTerminator=1; + let isBarrier=1; +} + +class JALR_HB_DESC : InstSE<(outs), (ins), "", [], NoItinerary, FrmJ>, + JALR_HB_DESC_BASE<"jalr.hb", GPR32Opnd> { + let isIndirectBranch=1; + let hasDelaySlot=1; +} + +class JR_HB_ENC : JR_HB_FM<8>; +class JALR_HB_ENC : JALR_HB_FM<9>; + +def JR_HB : JR_HB_DESC, JR_HB_ENC, ISA_MIPS32_NOT_32R6_64R6; +def JALR_HB : JALR_HB_DESC, JALR_HB_ENC, ISA_MIPS32; + +class TLB<string asmstr> : InstSE<(outs), (ins), asmstr, [], NoItinerary, + FrmOther, asmstr>; +def TLBP : MMRel, TLB<"tlbp">, COP0_TLB_FM<0x08>; +def TLBR : MMRel, TLB<"tlbr">, COP0_TLB_FM<0x01>; +def TLBWI : MMRel, TLB<"tlbwi">, COP0_TLB_FM<0x02>; +def TLBWR : MMRel, TLB<"tlbwr">, COP0_TLB_FM<0x06>; + +class CacheOp<string instr_asm, Operand MemOpnd> : + InstSE<(outs), (ins MemOpnd:$addr, uimm5:$hint), + !strconcat(instr_asm, "\t$hint, $addr"), [], NoItinerary, FrmOther, + instr_asm> { + let DecoderMethod = "DecodeCacheOp"; +} + +def CACHE : MMRel, CacheOp<"cache", mem>, CACHEOP_FM<0b101111>, + INSN_MIPS3_32_NOT_32R6_64R6; +def PREF : MMRel, CacheOp<"pref", mem>, CACHEOP_FM<0b110011>, + INSN_MIPS3_32_NOT_32R6_64R6; + +def ROL : MipsAsmPseudoInst<(outs), + (ins GPR32Opnd:$rs, GPR32Opnd:$rt, GPR32Opnd:$rd), + "rol\t$rs, $rt, $rd">; +def ROLImm : MipsAsmPseudoInst<(outs), + (ins GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), + "rol\t$rs, $rt, $imm">; +def : MipsInstAlias<"rol $rd, $rs", + (ROL GPR32Opnd:$rd, GPR32Opnd:$rd, GPR32Opnd:$rs), 0>; +def : MipsInstAlias<"rol $rd, $imm", + (ROLImm GPR32Opnd:$rd, GPR32Opnd:$rd, simm16:$imm), 0>; + +def ROR : MipsAsmPseudoInst<(outs), + (ins GPR32Opnd:$rs, GPR32Opnd:$rt, GPR32Opnd:$rd), + "ror\t$rs, $rt, $rd">; +def RORImm : MipsAsmPseudoInst<(outs), + (ins GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), + "ror\t$rs, $rt, $imm">; +def : MipsInstAlias<"ror $rd, $rs", + (ROR GPR32Opnd:$rd, GPR32Opnd:$rd, GPR32Opnd:$rs), 0>; +def : MipsInstAlias<"ror $rd, $imm", + (RORImm GPR32Opnd:$rd, GPR32Opnd:$rd, simm16:$imm), 0>; + +def DROL : MipsAsmPseudoInst<(outs), + (ins GPR32Opnd:$rs, GPR32Opnd:$rt, GPR32Opnd:$rd), + "drol\t$rs, $rt, $rd">, ISA_MIPS64; +def DROLImm : MipsAsmPseudoInst<(outs), + (ins GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), + "drol\t$rs, $rt, $imm">, ISA_MIPS64; +def : MipsInstAlias<"drol $rd, $rs", + (DROL GPR32Opnd:$rd, GPR32Opnd:$rd, GPR32Opnd:$rs), 0>, ISA_MIPS64; +def : MipsInstAlias<"drol $rd, $imm", + (DROLImm GPR32Opnd:$rd, GPR32Opnd:$rd, simm16:$imm), 0>, ISA_MIPS64; + +def DROR : MipsAsmPseudoInst<(outs), + (ins GPR32Opnd:$rs, GPR32Opnd:$rt, GPR32Opnd:$rd), + "dror\t$rs, $rt, $rd">, ISA_MIPS64; +def DRORImm : MipsAsmPseudoInst<(outs), + (ins GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), + "dror\t$rs, $rt, $imm">, ISA_MIPS64; +def : MipsInstAlias<"dror $rd, $rs", + (DROR GPR32Opnd:$rd, GPR32Opnd:$rd, GPR32Opnd:$rs), 0>, ISA_MIPS64; +def : MipsInstAlias<"dror $rd, $imm", + (DRORImm GPR32Opnd:$rd, GPR32Opnd:$rd, simm16:$imm), 0>, ISA_MIPS64; + +//===----------------------------------------------------------------------===// +// Instruction aliases +//===----------------------------------------------------------------------===// +def : MipsInstAlias<"move $dst, $src", + (OR GPR32Opnd:$dst, GPR32Opnd:$src, ZERO), 1>, + GPR_32 { + let AdditionalPredicates = [NotInMicroMips]; +} +def : MipsInstAlias<"move $dst, $src", + (ADDu GPR32Opnd:$dst, GPR32Opnd:$src, ZERO), 1>, + GPR_32 { + let AdditionalPredicates = [NotInMicroMips]; +} +def : MipsInstAlias<"bal $offset", (BGEZAL ZERO, brtarget:$offset), 0>, + ISA_MIPS1_NOT_32R6_64R6; +def : MipsInstAlias<"addu $rs, $rt, $imm", + (ADDiu GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), 0>; +def : MipsInstAlias<"addu $rs, $imm", + (ADDiu GPR32Opnd:$rs, GPR32Opnd:$rs, simm16:$imm), 0>; +def : MipsInstAlias<"add $rs, $rt, $imm", + (ADDi GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), 0>, + ISA_MIPS1_NOT_32R6_64R6; +def : MipsInstAlias<"add $rs, $imm", + (ADDi GPR32Opnd:$rs, GPR32Opnd:$rs, simm16:$imm), 0>, + ISA_MIPS1_NOT_32R6_64R6; +def : MipsInstAlias<"and $rs, $rt, $imm", + (ANDi GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), 0>; +def : MipsInstAlias<"and $rs, $imm", + (ANDi GPR32Opnd:$rs, GPR32Opnd:$rs, simm16:$imm), 0>; +def : MipsInstAlias<"j $rs", (JR GPR32Opnd:$rs), 0>; +let Predicates = [NotInMicroMips] in { +def : MipsInstAlias<"jalr $rs", (JALR RA, GPR32Opnd:$rs), 0>; +} +def : MipsInstAlias<"jalr.hb $rs", (JALR_HB RA, GPR32Opnd:$rs), 1>, ISA_MIPS32; +def : MipsInstAlias<"not $rt, $rs", + (NOR GPR32Opnd:$rt, GPR32Opnd:$rs, ZERO), 0>; +def : MipsInstAlias<"neg $rt, $rs", + (SUB GPR32Opnd:$rt, ZERO, GPR32Opnd:$rs), 1>; +def : MipsInstAlias<"negu $rt", + (SUBu GPR32Opnd:$rt, ZERO, GPR32Opnd:$rt), 0>; +def : MipsInstAlias<"negu $rt, $rs", + (SUBu GPR32Opnd:$rt, ZERO, GPR32Opnd:$rs), 1>; +def : MipsInstAlias<"slt $rs, $rt, $imm", + (SLTi GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), 0>; +def : MipsInstAlias<"sltu $rt, $rs, $imm", + (SLTiu GPR32Opnd:$rt, GPR32Opnd:$rs, simm16:$imm), 0>; +def : MipsInstAlias<"xor $rs, $rt, $imm", + (XORi GPR32Opnd:$rs, GPR32Opnd:$rt, uimm16:$imm), 0>; +def : MipsInstAlias<"xor $rs, $imm", + (XORi GPR32Opnd:$rs, GPR32Opnd:$rs, uimm16:$imm), 0>; +def : MipsInstAlias<"or $rs, $rt, $imm", + (ORi GPR32Opnd:$rs, GPR32Opnd:$rt, uimm16:$imm), 0>; +def : MipsInstAlias<"or $rs, $imm", + (ORi GPR32Opnd:$rs, GPR32Opnd:$rs, uimm16:$imm), 0>; +let AdditionalPredicates = [NotInMicroMips] in { +def : MipsInstAlias<"nop", (SLL ZERO, ZERO, 0), 1>; +} +def : MipsInstAlias<"mfc0 $rt, $rd", (MFC0 GPR32Opnd:$rt, COP0Opnd:$rd, 0), 0>; +def : MipsInstAlias<"mtc0 $rt, $rd", (MTC0 COP0Opnd:$rd, GPR32Opnd:$rt, 0), 0>; +def : MipsInstAlias<"mfc2 $rt, $rd", (MFC2 GPR32Opnd:$rt, COP2Opnd:$rd, 0), 0>; +def : MipsInstAlias<"mtc2 $rt, $rd", (MTC2 COP2Opnd:$rd, GPR32Opnd:$rt, 0), 0>; +let AdditionalPredicates = [NotInMicroMips] in { +def : MipsInstAlias<"b $offset", (BEQ ZERO, ZERO, brtarget:$offset), 0>; +} +def : MipsInstAlias<"bnez $rs,$offset", + (BNE GPR32Opnd:$rs, ZERO, brtarget:$offset), 0>; +def : MipsInstAlias<"bnezl $rs,$offset", + (BNEL GPR32Opnd:$rs, ZERO, brtarget:$offset), 0>; +def : MipsInstAlias<"beqz $rs,$offset", + (BEQ GPR32Opnd:$rs, ZERO, brtarget:$offset), 0>; +def : MipsInstAlias<"beqzl $rs,$offset", + (BEQL GPR32Opnd:$rs, ZERO, brtarget:$offset), 0>; +def : MipsInstAlias<"syscall", (SYSCALL 0), 1>; + +def : MipsInstAlias<"break", (BREAK 0, 0), 1>; +def : MipsInstAlias<"break $imm", (BREAK uimm10:$imm, 0), 1>; +let AdditionalPredicates = [NotInMicroMips] in { + def : MipsInstAlias<"ei", (EI ZERO), 1>, ISA_MIPS32R2; + def : MipsInstAlias<"di", (DI ZERO), 1>, ISA_MIPS32R2; +} +let AdditionalPredicates = [NotInMicroMips] in { + def : MipsInstAlias<"teq $rs, $rt", + (TEQ GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>, ISA_MIPS2; + def : MipsInstAlias<"tge $rs, $rt", + (TGE GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>, ISA_MIPS2; + def : MipsInstAlias<"tgeu $rs, $rt", + (TGEU GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>, ISA_MIPS2; + def : MipsInstAlias<"tlt $rs, $rt", + (TLT GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>, ISA_MIPS2; + def : MipsInstAlias<"tltu $rs, $rt", + (TLTU GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>, ISA_MIPS2; + def : MipsInstAlias<"tne $rs, $rt", + (TNE GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>, ISA_MIPS2; +} +def : MipsInstAlias<"sll $rd, $rt, $rs", + (SLLV GPR32Opnd:$rd, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>; +def : MipsInstAlias<"sub, $rd, $rs, $imm", + (ADDi GPR32Opnd:$rd, GPR32Opnd:$rs, + InvertedImOperand:$imm), 0>, ISA_MIPS1_NOT_32R6_64R6; +def : MipsInstAlias<"sub $rs, $imm", + (ADDi GPR32Opnd:$rs, GPR32Opnd:$rs, InvertedImOperand:$imm), + 0>, ISA_MIPS1_NOT_32R6_64R6; +def : MipsInstAlias<"subu, $rd, $rs, $imm", + (ADDiu GPR32Opnd:$rd, GPR32Opnd:$rs, + InvertedImOperand:$imm), 0>; +def : MipsInstAlias<"subu $rs, $imm", (ADDiu GPR32Opnd:$rs, GPR32Opnd:$rs, + InvertedImOperand:$imm), 0>; +def : MipsInstAlias<"sra $rd, $rt, $rs", + (SRAV GPR32Opnd:$rd, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>; +def : MipsInstAlias<"srl $rd, $rt, $rs", + (SRLV GPR32Opnd:$rd, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>; +def : MipsInstAlias<"sdbbp", (SDBBP 0)>, ISA_MIPS32_NOT_32R6_64R6; +def : MipsInstAlias<"sync", + (SYNC 0), 1>, ISA_MIPS2; +//===----------------------------------------------------------------------===// +// Assembler Pseudo Instructions +//===----------------------------------------------------------------------===// + +class LoadImmediate32<string instr_asm, Operand Od, RegisterOperand RO> : + MipsAsmPseudoInst<(outs RO:$rt), (ins Od:$imm32), + !strconcat(instr_asm, "\t$rt, $imm32")> ; +def LoadImm32 : LoadImmediate32<"li", simm32, GPR32Opnd>; + +class LoadAddressFromReg32<string instr_asm, Operand MemOpnd, + RegisterOperand RO> : + MipsAsmPseudoInst<(outs RO:$rt), (ins MemOpnd:$addr), + !strconcat(instr_asm, "\t$rt, $addr")> ; +def LoadAddrReg32 : LoadAddressFromReg32<"la", mem, GPR32Opnd>; + +class LoadAddressFromImm32<string instr_asm, Operand Od, RegisterOperand RO> : + MipsAsmPseudoInst<(outs RO:$rt), (ins Od:$imm32), + !strconcat(instr_asm, "\t$rt, $imm32")> ; +def LoadAddrImm32 : LoadAddressFromImm32<"la", simm32, GPR32Opnd>; + +def JalTwoReg : MipsAsmPseudoInst<(outs GPR32Opnd:$rd), (ins GPR32Opnd:$rs), + "jal\t$rd, $rs"> ; +def JalOneReg : MipsAsmPseudoInst<(outs), (ins GPR32Opnd:$rs), + "jal\t$rs"> ; + +def NORImm : MipsAsmPseudoInst<(outs), (ins GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), + "nor\t$rs, $rt, $imm"> ; + +let hasDelaySlot = 1 in { +def BneImm : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), + (ins imm64:$imm64, brtarget:$offset), + "bne\t$rt, $imm64, $offset">; +def BeqImm : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), + (ins imm64:$imm64, brtarget:$offset), + "beq\t$rt, $imm64, $offset">; + +class CondBranchPseudo<string instr_asm> : + MipsAsmPseudoInst<(outs), (ins GPR32Opnd:$rs, GPR32Opnd:$rt, + brtarget:$offset), + !strconcat(instr_asm, "\t$rs, $rt, $offset")>; +} + +def BLT : CondBranchPseudo<"blt">; +def BLE : CondBranchPseudo<"ble">; +def BGE : CondBranchPseudo<"bge">; +def BGT : CondBranchPseudo<"bgt">; +def BLTU : CondBranchPseudo<"bltu">; +def BLEU : CondBranchPseudo<"bleu">; +def BGEU : CondBranchPseudo<"bgeu">; +def BGTU : CondBranchPseudo<"bgtu">; +def BLTL : CondBranchPseudo<"bltl">, ISA_MIPS2_NOT_32R6_64R6; +def BLEL : CondBranchPseudo<"blel">, ISA_MIPS2_NOT_32R6_64R6; +def BGEL : CondBranchPseudo<"bgel">, ISA_MIPS2_NOT_32R6_64R6; +def BGTL : CondBranchPseudo<"bgtl">, ISA_MIPS2_NOT_32R6_64R6; +def BLTUL: CondBranchPseudo<"bltul">, ISA_MIPS2_NOT_32R6_64R6; +def BLEUL: CondBranchPseudo<"bleul">, ISA_MIPS2_NOT_32R6_64R6; +def BGEUL: CondBranchPseudo<"bgeul">, ISA_MIPS2_NOT_32R6_64R6; +def BGTUL: CondBranchPseudo<"bgtul">, ISA_MIPS2_NOT_32R6_64R6; + +class CondBranchImmPseudo<string instr_asm> : + MipsAsmPseudoInst<(outs), (ins GPR32Opnd:$rs, imm64:$imm, brtarget:$offset), + !strconcat(instr_asm, "\t$rs, $imm, $offset")>; + +def BLTImmMacro : CondBranchImmPseudo<"blt">; +def BLEImmMacro : CondBranchImmPseudo<"ble">; +def BGEImmMacro : CondBranchImmPseudo<"bge">; +def BGTImmMacro : CondBranchImmPseudo<"bgt">; +def BLTUImmMacro : CondBranchImmPseudo<"bltu">; +def BLEUImmMacro : CondBranchImmPseudo<"bleu">; +def BGEUImmMacro : CondBranchImmPseudo<"bgeu">; +def BGTUImmMacro : CondBranchImmPseudo<"bgtu">; +def BLTLImmMacro : CondBranchImmPseudo<"bltl">, ISA_MIPS2_NOT_32R6_64R6; +def BLELImmMacro : CondBranchImmPseudo<"blel">, ISA_MIPS2_NOT_32R6_64R6; +def BGELImmMacro : CondBranchImmPseudo<"bgel">, ISA_MIPS2_NOT_32R6_64R6; +def BGTLImmMacro : CondBranchImmPseudo<"bgtl">, ISA_MIPS2_NOT_32R6_64R6; +def BLTULImmMacro : CondBranchImmPseudo<"bltul">, ISA_MIPS2_NOT_32R6_64R6; +def BLEULImmMacro : CondBranchImmPseudo<"bleul">, ISA_MIPS2_NOT_32R6_64R6; +def BGEULImmMacro : CondBranchImmPseudo<"bgeul">, ISA_MIPS2_NOT_32R6_64R6; +def BGTULImmMacro : CondBranchImmPseudo<"bgtul">, ISA_MIPS2_NOT_32R6_64R6; + +// FIXME: Predicates are removed because instructions are matched regardless of +// predicates, because PredicateControl was not in the hierarchy. This was +// done to emit more precise error message from expansion function. +// Once the tablegen-erated errors are made better, this needs to be fixed and +// predicates needs to be restored. + +def SDivMacro : MipsAsmPseudoInst<(outs), (ins GPR32Opnd:$rs, GPR32Opnd:$rt), + "div\t$rs, $rt">; //, ISA_MIPS1_NOT_32R6_64R6; + +def UDivMacro : MipsAsmPseudoInst<(outs), (ins GPR32Opnd:$rs, GPR32Opnd:$rt), + "divu\t$rs, $rt">; //, ISA_MIPS1_NOT_32R6_64R6; + +def DSDivMacro : MipsAsmPseudoInst<(outs), (ins GPR32Opnd:$rs, GPR32Opnd:$rt), + "ddiv\t$rs, $rt">; //, ISA_MIPS64_NOT_64R6; + +def DUDivMacro : MipsAsmPseudoInst<(outs), (ins GPR32Opnd:$rs, GPR32Opnd:$rt), + "ddivu\t$rs, $rt">; //, ISA_MIPS64_NOT_64R6; + +def Ulh : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins mem:$addr), + "ulh\t$rt, $addr">; //, ISA_MIPS1_NOT_32R6_64R6; + +def Ulhu : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins mem:$addr), + "ulhu\t$rt, $addr">; //, ISA_MIPS1_NOT_32R6_64R6; + +def Ulw : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins mem:$addr), + "ulw\t$rt, $addr">; //, ISA_MIPS1_NOT_32R6_64R6; + +//===----------------------------------------------------------------------===// +// Arbitrary patterns that map to one or more instructions +//===----------------------------------------------------------------------===// + +// Load/store pattern templates. +class LoadRegImmPat<Instruction LoadInst, ValueType ValTy, PatFrag Node> : + MipsPat<(ValTy (Node addrRegImm:$a)), (LoadInst addrRegImm:$a)>; + +class StoreRegImmPat<Instruction StoreInst, ValueType ValTy> : + MipsPat<(store ValTy:$v, addrRegImm:$a), (StoreInst ValTy:$v, addrRegImm:$a)>; + +// Small immediates +let AdditionalPredicates = [NotInMicroMips] in { +def : MipsPat<(i32 immSExt16:$in), + (ADDiu ZERO, imm:$in)>; +def : MipsPat<(i32 immZExt16:$in), + (ORi ZERO, imm:$in)>; +} +def : MipsPat<(i32 immLow16Zero:$in), + (LUi (HI16 imm:$in))>; + +// Arbitrary immediates +def : MipsPat<(i32 imm:$imm), + (ORi (LUi (HI16 imm:$imm)), (LO16 imm:$imm))>; + +// Carry MipsPatterns +def : MipsPat<(subc GPR32:$lhs, GPR32:$rhs), + (SUBu GPR32:$lhs, GPR32:$rhs)>; +let AdditionalPredicates = [NotDSP] in { + def : MipsPat<(addc GPR32:$lhs, GPR32:$rhs), + (ADDu GPR32:$lhs, GPR32:$rhs)>; + def : MipsPat<(addc GPR32:$src, immSExt16:$imm), + (ADDiu GPR32:$src, imm:$imm)>; +} + +// Support multiplication for pre-Mips32 targets that don't have +// the MUL instruction. +def : MipsPat<(mul GPR32:$lhs, GPR32:$rhs), + (PseudoMFLO (PseudoMULT GPR32:$lhs, GPR32:$rhs))>, + ISA_MIPS1_NOT_32R6_64R6; + +// SYNC +def : MipsPat<(MipsSync (i32 immz)), + (SYNC 0)>, ISA_MIPS2; + +// Call +def : MipsPat<(MipsJmpLink (i32 tglobaladdr:$dst)), + (JAL tglobaladdr:$dst)>; +def : MipsPat<(MipsJmpLink (i32 texternalsym:$dst)), + (JAL texternalsym:$dst)>; +//def : MipsPat<(MipsJmpLink GPR32:$dst), +// (JALR GPR32:$dst)>; + +// Tail call +def : MipsPat<(MipsTailCall (iPTR tglobaladdr:$dst)), + (TAILCALL tglobaladdr:$dst)>; +def : MipsPat<(MipsTailCall (iPTR texternalsym:$dst)), + (TAILCALL texternalsym:$dst)>; +// hi/lo relocs +def : MipsPat<(MipsHi tglobaladdr:$in), (LUi tglobaladdr:$in)>; +def : MipsPat<(MipsHi tblockaddress:$in), (LUi tblockaddress:$in)>; +def : MipsPat<(MipsHi tjumptable:$in), (LUi tjumptable:$in)>; +def : MipsPat<(MipsHi tconstpool:$in), (LUi tconstpool:$in)>; +def : MipsPat<(MipsHi tglobaltlsaddr:$in), (LUi tglobaltlsaddr:$in)>; +def : MipsPat<(MipsHi texternalsym:$in), (LUi texternalsym:$in)>; + +def : MipsPat<(MipsLo tglobaladdr:$in), (ADDiu ZERO, tglobaladdr:$in)>; +def : MipsPat<(MipsLo tblockaddress:$in), (ADDiu ZERO, tblockaddress:$in)>; +def : MipsPat<(MipsLo tjumptable:$in), (ADDiu ZERO, tjumptable:$in)>; +def : MipsPat<(MipsLo tconstpool:$in), (ADDiu ZERO, tconstpool:$in)>; +def : MipsPat<(MipsLo tglobaltlsaddr:$in), (ADDiu ZERO, tglobaltlsaddr:$in)>; +def : MipsPat<(MipsLo texternalsym:$in), (ADDiu ZERO, texternalsym:$in)>; + +def : MipsPat<(add GPR32:$hi, (MipsLo tglobaladdr:$lo)), + (ADDiu GPR32:$hi, tglobaladdr:$lo)>; +def : MipsPat<(add GPR32:$hi, (MipsLo tblockaddress:$lo)), + (ADDiu GPR32:$hi, tblockaddress:$lo)>; +def : MipsPat<(add GPR32:$hi, (MipsLo tjumptable:$lo)), + (ADDiu GPR32:$hi, tjumptable:$lo)>; +def : MipsPat<(add GPR32:$hi, (MipsLo tconstpool:$lo)), + (ADDiu GPR32:$hi, tconstpool:$lo)>; +def : MipsPat<(add GPR32:$hi, (MipsLo tglobaltlsaddr:$lo)), + (ADDiu GPR32:$hi, tglobaltlsaddr:$lo)>; + +// gp_rel relocs +def : MipsPat<(add GPR32:$gp, (MipsGPRel tglobaladdr:$in)), + (ADDiu GPR32:$gp, tglobaladdr:$in)>; +def : MipsPat<(add GPR32:$gp, (MipsGPRel tconstpool:$in)), + (ADDiu GPR32:$gp, tconstpool:$in)>; + +// wrapper_pic +class WrapperPat<SDNode node, Instruction ADDiuOp, RegisterClass RC>: + MipsPat<(MipsWrapper RC:$gp, node:$in), + (ADDiuOp RC:$gp, node:$in)>; + +def : WrapperPat<tglobaladdr, ADDiu, GPR32>; +def : WrapperPat<tconstpool, ADDiu, GPR32>; +def : WrapperPat<texternalsym, ADDiu, GPR32>; +def : WrapperPat<tblockaddress, ADDiu, GPR32>; +def : WrapperPat<tjumptable, ADDiu, GPR32>; +def : WrapperPat<tglobaltlsaddr, ADDiu, GPR32>; + +let AdditionalPredicates = [NotInMicroMips] in { +// Mips does not have "not", so we expand our way +def : MipsPat<(not GPR32:$in), + (NOR GPR32Opnd:$in, ZERO)>; +} + +// extended loads +def : MipsPat<(i32 (extloadi1 addr:$src)), (LBu addr:$src)>; +def : MipsPat<(i32 (extloadi8 addr:$src)), (LBu addr:$src)>; +def : MipsPat<(i32 (extloadi16 addr:$src)), (LHu addr:$src)>; + +// peepholes +def : MipsPat<(store (i32 0), addr:$dst), (SW ZERO, addr:$dst)>; + +// brcond patterns +multiclass BrcondPats<RegisterClass RC, Instruction BEQOp, Instruction BNEOp, + Instruction SLTOp, Instruction SLTuOp, Instruction SLTiOp, + Instruction SLTiuOp, Register ZEROReg> { +def : MipsPat<(brcond (i32 (setne RC:$lhs, 0)), bb:$dst), + (BNEOp RC:$lhs, ZEROReg, bb:$dst)>; +def : MipsPat<(brcond (i32 (seteq RC:$lhs, 0)), bb:$dst), + (BEQOp RC:$lhs, ZEROReg, bb:$dst)>; + +def : MipsPat<(brcond (i32 (setge RC:$lhs, RC:$rhs)), bb:$dst), + (BEQ (SLTOp RC:$lhs, RC:$rhs), ZERO, bb:$dst)>; +def : MipsPat<(brcond (i32 (setuge RC:$lhs, RC:$rhs)), bb:$dst), + (BEQ (SLTuOp RC:$lhs, RC:$rhs), ZERO, bb:$dst)>; +def : MipsPat<(brcond (i32 (setge RC:$lhs, immSExt16:$rhs)), bb:$dst), + (BEQ (SLTiOp RC:$lhs, immSExt16:$rhs), ZERO, bb:$dst)>; +def : MipsPat<(brcond (i32 (setuge RC:$lhs, immSExt16:$rhs)), bb:$dst), + (BEQ (SLTiuOp RC:$lhs, immSExt16:$rhs), ZERO, bb:$dst)>; +def : MipsPat<(brcond (i32 (setgt RC:$lhs, immSExt16Plus1:$rhs)), bb:$dst), + (BEQ (SLTiOp RC:$lhs, (Plus1 imm:$rhs)), ZERO, bb:$dst)>; +def : MipsPat<(brcond (i32 (setugt RC:$lhs, immSExt16Plus1:$rhs)), bb:$dst), + (BEQ (SLTiuOp RC:$lhs, (Plus1 imm:$rhs)), ZERO, bb:$dst)>; + +def : MipsPat<(brcond (i32 (setle RC:$lhs, RC:$rhs)), bb:$dst), + (BEQ (SLTOp RC:$rhs, RC:$lhs), ZERO, bb:$dst)>; +def : MipsPat<(brcond (i32 (setule RC:$lhs, RC:$rhs)), bb:$dst), + (BEQ (SLTuOp RC:$rhs, RC:$lhs), ZERO, bb:$dst)>; + +def : MipsPat<(brcond RC:$cond, bb:$dst), + (BNEOp RC:$cond, ZEROReg, bb:$dst)>; +} + +defm : BrcondPats<GPR32, BEQ, BNE, SLT, SLTu, SLTi, SLTiu, ZERO>; + +def : MipsPat<(brcond (i32 (setlt i32:$lhs, 1)), bb:$dst), + (BLEZ i32:$lhs, bb:$dst)>; +def : MipsPat<(brcond (i32 (setgt i32:$lhs, -1)), bb:$dst), + (BGEZ i32:$lhs, bb:$dst)>; + +// setcc patterns +multiclass SeteqPats<RegisterClass RC, Instruction SLTiuOp, Instruction XOROp, + Instruction SLTuOp, Register ZEROReg> { + def : MipsPat<(seteq RC:$lhs, 0), + (SLTiuOp RC:$lhs, 1)>; + def : MipsPat<(setne RC:$lhs, 0), + (SLTuOp ZEROReg, RC:$lhs)>; + def : MipsPat<(seteq RC:$lhs, RC:$rhs), + (SLTiuOp (XOROp RC:$lhs, RC:$rhs), 1)>; + def : MipsPat<(setne RC:$lhs, RC:$rhs), + (SLTuOp ZEROReg, (XOROp RC:$lhs, RC:$rhs))>; +} + +multiclass SetlePats<RegisterClass RC, Instruction SLTOp, Instruction SLTuOp> { + def : MipsPat<(setle RC:$lhs, RC:$rhs), + (XORi (SLTOp RC:$rhs, RC:$lhs), 1)>; + def : MipsPat<(setule RC:$lhs, RC:$rhs), + (XORi (SLTuOp RC:$rhs, RC:$lhs), 1)>; +} + +multiclass SetgtPats<RegisterClass RC, Instruction SLTOp, Instruction SLTuOp> { + def : MipsPat<(setgt RC:$lhs, RC:$rhs), + (SLTOp RC:$rhs, RC:$lhs)>; + def : MipsPat<(setugt RC:$lhs, RC:$rhs), + (SLTuOp RC:$rhs, RC:$lhs)>; +} + +multiclass SetgePats<RegisterClass RC, Instruction SLTOp, Instruction SLTuOp> { + def : MipsPat<(setge RC:$lhs, RC:$rhs), + (XORi (SLTOp RC:$lhs, RC:$rhs), 1)>; + def : MipsPat<(setuge RC:$lhs, RC:$rhs), + (XORi (SLTuOp RC:$lhs, RC:$rhs), 1)>; +} + +multiclass SetgeImmPats<RegisterClass RC, Instruction SLTiOp, + Instruction SLTiuOp> { + def : MipsPat<(setge RC:$lhs, immSExt16:$rhs), + (XORi (SLTiOp RC:$lhs, immSExt16:$rhs), 1)>; + def : MipsPat<(setuge RC:$lhs, immSExt16:$rhs), + (XORi (SLTiuOp RC:$lhs, immSExt16:$rhs), 1)>; +} + +defm : SeteqPats<GPR32, SLTiu, XOR, SLTu, ZERO>; +defm : SetlePats<GPR32, SLT, SLTu>; +defm : SetgtPats<GPR32, SLT, SLTu>; +defm : SetgePats<GPR32, SLT, SLTu>; +defm : SetgeImmPats<GPR32, SLTi, SLTiu>; + +// bswap pattern +def : MipsPat<(bswap GPR32:$rt), (ROTR (WSBH GPR32:$rt), 16)>; + +// Load halfword/word patterns. +let AddedComplexity = 40 in { + def : LoadRegImmPat<LBu, i32, zextloadi8>; + def : LoadRegImmPat<LH, i32, sextloadi16>; + let AdditionalPredicates = [NotInMicroMips] in { + def : LoadRegImmPat<LW, i32, load>; + } +} + +// Atomic load patterns. +def : MipsPat<(atomic_load_8 addr:$a), (LB addr:$a)>; +def : MipsPat<(atomic_load_16 addr:$a), (LH addr:$a)>; +def : MipsPat<(atomic_load_32 addr:$a), (LW addr:$a)>; + +// Atomic store patterns. +def : MipsPat<(atomic_store_8 addr:$a, GPR32:$v), (SB GPR32:$v, addr:$a)>; +def : MipsPat<(atomic_store_16 addr:$a, GPR32:$v), (SH GPR32:$v, addr:$a)>; +def : MipsPat<(atomic_store_32 addr:$a, GPR32:$v), (SW GPR32:$v, addr:$a)>; + +//===----------------------------------------------------------------------===// +// Floating Point Support +//===----------------------------------------------------------------------===// + +include "MipsInstrFPU.td" +include "Mips64InstrInfo.td" +include "MipsCondMov.td" + +include "Mips32r6InstrInfo.td" +include "Mips64r6InstrInfo.td" + +// +// Mips16 + +include "Mips16InstrFormats.td" +include "Mips16InstrInfo.td" + +// DSP +include "MipsDSPInstrFormats.td" +include "MipsDSPInstrInfo.td" + +// MSA +include "MipsMSAInstrFormats.td" +include "MipsMSAInstrInfo.td" + +// EVA +include "MipsEVAInstrFormats.td" +include "MipsEVAInstrInfo.td" + +// Micromips +include "MicroMipsInstrFormats.td" +include "MicroMipsInstrInfo.td" +include "MicroMipsInstrFPU.td" + +// Micromips r6 +include "MicroMips32r6InstrFormats.td" +include "MicroMips32r6InstrInfo.td" + +// Micromips64 r6 +include "MicroMips64r6InstrFormats.td" +include "MicroMips64r6InstrInfo.td" + +// Micromips DSP +include "MicroMipsDSPInstrFormats.td" +include "MicroMipsDSPInstrInfo.td" diff --git a/contrib/llvm/lib/Target/Mips/MipsLongBranch.cpp b/contrib/llvm/lib/Target/Mips/MipsLongBranch.cpp new file mode 100644 index 0000000..49fb99a --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsLongBranch.cpp @@ -0,0 +1,524 @@ +//===-- MipsLongBranch.cpp - Emit long branches ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass expands a branch or jump instruction into a long branch if its +// offset is too large to fit into its immediate field. +// +// FIXME: Fix pc-region jump instructions which cross 256MB segment boundaries. +//===----------------------------------------------------------------------===// + +#include "Mips.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MCTargetDesc/MipsMCNaCl.h" +#include "MipsMachineFunction.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegisterInfo.h" + +using namespace llvm; + +#define DEBUG_TYPE "mips-long-branch" + +STATISTIC(LongBranches, "Number of long branches."); + +static cl::opt<bool> SkipLongBranch( + "skip-mips-long-branch", + cl::init(false), + cl::desc("MIPS: Skip long branch pass."), + cl::Hidden); + +static cl::opt<bool> ForceLongBranch( + "force-mips-long-branch", + cl::init(false), + cl::desc("MIPS: Expand all branches to long format."), + cl::Hidden); + +namespace { + typedef MachineBasicBlock::iterator Iter; + typedef MachineBasicBlock::reverse_iterator ReverseIter; + + struct MBBInfo { + uint64_t Size, Address; + bool HasLongBranch; + MachineInstr *Br; + + MBBInfo() : Size(0), HasLongBranch(false), Br(nullptr) {} + }; + + class MipsLongBranch : public MachineFunctionPass { + + public: + static char ID; + MipsLongBranch(TargetMachine &tm) + : MachineFunctionPass(ID), TM(tm), + IsPIC(TM.getRelocationModel() == Reloc::PIC_), + ABI(static_cast<const MipsTargetMachine &>(TM).getABI()) {} + + const char *getPassName() const override { + return "Mips Long Branch"; + } + + bool runOnMachineFunction(MachineFunction &F) override; + + private: + void splitMBB(MachineBasicBlock *MBB); + void initMBBInfo(); + int64_t computeOffset(const MachineInstr *Br); + void replaceBranch(MachineBasicBlock &MBB, Iter Br, DebugLoc DL, + MachineBasicBlock *MBBOpnd); + void expandToLongBranch(MBBInfo &Info); + + const TargetMachine &TM; + MachineFunction *MF; + SmallVector<MBBInfo, 16> MBBInfos; + bool IsPIC; + MipsABIInfo ABI; + unsigned LongBranchSeqSize; + }; + + char MipsLongBranch::ID = 0; +} // end of anonymous namespace + +/// createMipsLongBranchPass - Returns a pass that converts branches to long +/// branches. +FunctionPass *llvm::createMipsLongBranchPass(MipsTargetMachine &tm) { + return new MipsLongBranch(tm); +} + +/// Iterate over list of Br's operands and search for a MachineBasicBlock +/// operand. +static MachineBasicBlock *getTargetMBB(const MachineInstr &Br) { + for (unsigned I = 0, E = Br.getDesc().getNumOperands(); I < E; ++I) { + const MachineOperand &MO = Br.getOperand(I); + + if (MO.isMBB()) + return MO.getMBB(); + } + + llvm_unreachable("This instruction does not have an MBB operand."); +} + +// Traverse the list of instructions backwards until a non-debug instruction is +// found or it reaches E. +static ReverseIter getNonDebugInstr(ReverseIter B, ReverseIter E) { + for (; B != E; ++B) + if (!B->isDebugValue()) + return B; + + return E; +} + +// Split MBB if it has two direct jumps/branches. +void MipsLongBranch::splitMBB(MachineBasicBlock *MBB) { + ReverseIter End = MBB->rend(); + ReverseIter LastBr = getNonDebugInstr(MBB->rbegin(), End); + + // Return if MBB has no branch instructions. + if ((LastBr == End) || + (!LastBr->isConditionalBranch() && !LastBr->isUnconditionalBranch())) + return; + + ReverseIter FirstBr = getNonDebugInstr(std::next(LastBr), End); + + // MBB has only one branch instruction if FirstBr is not a branch + // instruction. + if ((FirstBr == End) || + (!FirstBr->isConditionalBranch() && !FirstBr->isUnconditionalBranch())) + return; + + assert(!FirstBr->isIndirectBranch() && "Unexpected indirect branch found."); + + // Create a new MBB. Move instructions in MBB to the newly created MBB. + MachineBasicBlock *NewMBB = + MF->CreateMachineBasicBlock(MBB->getBasicBlock()); + + // Insert NewMBB and fix control flow. + MachineBasicBlock *Tgt = getTargetMBB(*FirstBr); + NewMBB->transferSuccessors(MBB); + NewMBB->removeSuccessor(Tgt, true); + MBB->addSuccessor(NewMBB); + MBB->addSuccessor(Tgt); + MF->insert(std::next(MachineFunction::iterator(MBB)), NewMBB); + + NewMBB->splice(NewMBB->end(), MBB, (++LastBr).base(), MBB->end()); +} + +// Fill MBBInfos. +void MipsLongBranch::initMBBInfo() { + // Split the MBBs if they have two branches. Each basic block should have at + // most one branch after this loop is executed. + for (MachineFunction::iterator I = MF->begin(), E = MF->end(); I != E;) + splitMBB(&*I++); + + MF->RenumberBlocks(); + MBBInfos.clear(); + MBBInfos.resize(MF->size()); + + const MipsInstrInfo *TII = + static_cast<const MipsInstrInfo *>(MF->getSubtarget().getInstrInfo()); + for (unsigned I = 0, E = MBBInfos.size(); I < E; ++I) { + MachineBasicBlock *MBB = MF->getBlockNumbered(I); + + // Compute size of MBB. + for (MachineBasicBlock::instr_iterator MI = MBB->instr_begin(); + MI != MBB->instr_end(); ++MI) + MBBInfos[I].Size += TII->GetInstSizeInBytes(&*MI); + + // Search for MBB's branch instruction. + ReverseIter End = MBB->rend(); + ReverseIter Br = getNonDebugInstr(MBB->rbegin(), End); + + if ((Br != End) && !Br->isIndirectBranch() && + (Br->isConditionalBranch() || + (Br->isUnconditionalBranch() && + TM.getRelocationModel() == Reloc::PIC_))) + MBBInfos[I].Br = (++Br).base(); + } +} + +// Compute offset of branch in number of bytes. +int64_t MipsLongBranch::computeOffset(const MachineInstr *Br) { + int64_t Offset = 0; + int ThisMBB = Br->getParent()->getNumber(); + int TargetMBB = getTargetMBB(*Br)->getNumber(); + + // Compute offset of a forward branch. + if (ThisMBB < TargetMBB) { + for (int N = ThisMBB + 1; N < TargetMBB; ++N) + Offset += MBBInfos[N].Size; + + return Offset + 4; + } + + // Compute offset of a backward branch. + for (int N = ThisMBB; N >= TargetMBB; --N) + Offset += MBBInfos[N].Size; + + return -Offset + 4; +} + +// Replace Br with a branch which has the opposite condition code and a +// MachineBasicBlock operand MBBOpnd. +void MipsLongBranch::replaceBranch(MachineBasicBlock &MBB, Iter Br, + DebugLoc DL, MachineBasicBlock *MBBOpnd) { + const MipsInstrInfo *TII = static_cast<const MipsInstrInfo *>( + MBB.getParent()->getSubtarget().getInstrInfo()); + unsigned NewOpc = TII->getOppositeBranchOpc(Br->getOpcode()); + const MCInstrDesc &NewDesc = TII->get(NewOpc); + + MachineInstrBuilder MIB = BuildMI(MBB, Br, DL, NewDesc); + + for (unsigned I = 0, E = Br->getDesc().getNumOperands(); I < E; ++I) { + MachineOperand &MO = Br->getOperand(I); + + if (!MO.isReg()) { + assert(MO.isMBB() && "MBB operand expected."); + break; + } + + MIB.addReg(MO.getReg()); + } + + MIB.addMBB(MBBOpnd); + + if (Br->hasDelaySlot()) { + // Bundle the instruction in the delay slot to the newly created branch + // and erase the original branch. + assert(Br->isBundledWithSucc()); + MachineBasicBlock::instr_iterator II(Br); + MIBundleBuilder(&*MIB).append((++II)->removeFromBundle()); + } + Br->eraseFromParent(); +} + +// Expand branch instructions to long branches. +// TODO: This function has to be fixed for beqz16 and bnez16, because it +// currently assumes that all branches have 16-bit offsets, and will produce +// wrong code if branches whose allowed offsets are [-128, -126, ..., 126] +// are present. +void MipsLongBranch::expandToLongBranch(MBBInfo &I) { + MachineBasicBlock::iterator Pos; + MachineBasicBlock *MBB = I.Br->getParent(), *TgtMBB = getTargetMBB(*I.Br); + DebugLoc DL = I.Br->getDebugLoc(); + const BasicBlock *BB = MBB->getBasicBlock(); + MachineFunction::iterator FallThroughMBB = ++MachineFunction::iterator(MBB); + MachineBasicBlock *LongBrMBB = MF->CreateMachineBasicBlock(BB); + const MipsSubtarget &Subtarget = + static_cast<const MipsSubtarget &>(MF->getSubtarget()); + const MipsInstrInfo *TII = + static_cast<const MipsInstrInfo *>(Subtarget.getInstrInfo()); + + MF->insert(FallThroughMBB, LongBrMBB); + MBB->replaceSuccessor(TgtMBB, LongBrMBB); + + if (IsPIC) { + MachineBasicBlock *BalTgtMBB = MF->CreateMachineBasicBlock(BB); + MF->insert(FallThroughMBB, BalTgtMBB); + LongBrMBB->addSuccessor(BalTgtMBB); + BalTgtMBB->addSuccessor(TgtMBB); + + // We must select between the MIPS32r6/MIPS64r6 BAL (which is a normal + // instruction) and the pre-MIPS32r6/MIPS64r6 definition (which is an + // pseudo-instruction wrapping BGEZAL). + unsigned BalOp = Subtarget.hasMips32r6() ? Mips::BAL : Mips::BAL_BR; + + if (!ABI.IsN64()) { + // $longbr: + // addiu $sp, $sp, -8 + // sw $ra, 0($sp) + // lui $at, %hi($tgt - $baltgt) + // bal $baltgt + // addiu $at, $at, %lo($tgt - $baltgt) + // $baltgt: + // addu $at, $ra, $at + // lw $ra, 0($sp) + // jr $at + // addiu $sp, $sp, 8 + // $fallthrough: + // + + Pos = LongBrMBB->begin(); + + BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::SP) + .addReg(Mips::SP).addImm(-8); + BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::SW)).addReg(Mips::RA) + .addReg(Mips::SP).addImm(0); + + // LUi and ADDiu instructions create 32-bit offset of the target basic + // block from the target of BAL instruction. We cannot use immediate + // value for this offset because it cannot be determined accurately when + // the program has inline assembly statements. We therefore use the + // relocation expressions %hi($tgt-$baltgt) and %lo($tgt-$baltgt) which + // are resolved during the fixup, so the values will always be correct. + // + // Since we cannot create %hi($tgt-$baltgt) and %lo($tgt-$baltgt) + // expressions at this point (it is possible only at the MC layer), + // we replace LUi and ADDiu with pseudo instructions + // LONG_BRANCH_LUi and LONG_BRANCH_ADDiu, and add both basic + // blocks as operands to these instructions. When lowering these pseudo + // instructions to LUi and ADDiu in the MC layer, we will create + // %hi($tgt-$baltgt) and %lo($tgt-$baltgt) expressions and add them as + // operands to lowered instructions. + + BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_LUi), Mips::AT) + .addMBB(TgtMBB).addMBB(BalTgtMBB); + MIBundleBuilder(*LongBrMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(BalOp)).addMBB(BalTgtMBB)) + .append(BuildMI(*MF, DL, TII->get(Mips::LONG_BRANCH_ADDiu), Mips::AT) + .addReg(Mips::AT) + .addMBB(TgtMBB) + .addMBB(BalTgtMBB)); + + Pos = BalTgtMBB->begin(); + + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDu), Mips::AT) + .addReg(Mips::RA).addReg(Mips::AT); + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::LW), Mips::RA) + .addReg(Mips::SP).addImm(0); + + if (!Subtarget.isTargetNaCl()) { + MIBundleBuilder(*BalTgtMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(Mips::JR)).addReg(Mips::AT)) + .append(BuildMI(*MF, DL, TII->get(Mips::ADDiu), Mips::SP) + .addReg(Mips::SP).addImm(8)); + } else { + // In NaCl, modifying the sp is not allowed in branch delay slot. + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::SP) + .addReg(Mips::SP).addImm(8); + + MIBundleBuilder(*BalTgtMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(Mips::JR)).addReg(Mips::AT)) + .append(BuildMI(*MF, DL, TII->get(Mips::NOP))); + + // Bundle-align the target of indirect branch JR. + TgtMBB->setAlignment(MIPS_NACL_BUNDLE_ALIGN); + } + } else { + // $longbr: + // daddiu $sp, $sp, -16 + // sd $ra, 0($sp) + // daddiu $at, $zero, %hi($tgt - $baltgt) + // dsll $at, $at, 16 + // bal $baltgt + // daddiu $at, $at, %lo($tgt - $baltgt) + // $baltgt: + // daddu $at, $ra, $at + // ld $ra, 0($sp) + // jr64 $at + // daddiu $sp, $sp, 16 + // $fallthrough: + // + + // We assume the branch is within-function, and that offset is within + // +/- 2GB. High 32 bits will therefore always be zero. + + // Note that this will work even if the offset is negative, because + // of the +1 modification that's added in that case. For example, if the + // offset is -1MB (0xFFFFFFFFFFF00000), the computation for %higher is + // + // 0xFFFFFFFFFFF00000 + 0x80008000 = 0x000000007FF08000 + // + // and the bits [47:32] are zero. For %highest + // + // 0xFFFFFFFFFFF00000 + 0x800080008000 = 0x000080007FF08000 + // + // and the bits [63:48] are zero. + + Pos = LongBrMBB->begin(); + + BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DADDiu), Mips::SP_64) + .addReg(Mips::SP_64).addImm(-16); + BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::SD)).addReg(Mips::RA_64) + .addReg(Mips::SP_64).addImm(0); + BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_DADDiu), + Mips::AT_64).addReg(Mips::ZERO_64) + .addMBB(TgtMBB, MipsII::MO_ABS_HI).addMBB(BalTgtMBB); + BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DSLL), Mips::AT_64) + .addReg(Mips::AT_64).addImm(16); + + MIBundleBuilder(*LongBrMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(BalOp)).addMBB(BalTgtMBB)) + .append( + BuildMI(*MF, DL, TII->get(Mips::LONG_BRANCH_DADDiu), Mips::AT_64) + .addReg(Mips::AT_64) + .addMBB(TgtMBB, MipsII::MO_ABS_LO) + .addMBB(BalTgtMBB)); + + Pos = BalTgtMBB->begin(); + + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::DADDu), Mips::AT_64) + .addReg(Mips::RA_64).addReg(Mips::AT_64); + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::LD), Mips::RA_64) + .addReg(Mips::SP_64).addImm(0); + + MIBundleBuilder(*BalTgtMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(Mips::JR64)).addReg(Mips::AT_64)) + .append(BuildMI(*MF, DL, TII->get(Mips::DADDiu), Mips::SP_64) + .addReg(Mips::SP_64).addImm(16)); + } + + assert(LongBrMBB->size() + BalTgtMBB->size() == LongBranchSeqSize); + } else { + // $longbr: + // j $tgt + // nop + // $fallthrough: + // + Pos = LongBrMBB->begin(); + LongBrMBB->addSuccessor(TgtMBB); + MIBundleBuilder(*LongBrMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(Mips::J)).addMBB(TgtMBB)) + .append(BuildMI(*MF, DL, TII->get(Mips::NOP))); + + assert(LongBrMBB->size() == LongBranchSeqSize); + } + + if (I.Br->isUnconditionalBranch()) { + // Change branch destination. + assert(I.Br->getDesc().getNumOperands() == 1); + I.Br->RemoveOperand(0); + I.Br->addOperand(MachineOperand::CreateMBB(LongBrMBB)); + } else + // Change branch destination and reverse condition. + replaceBranch(*MBB, I.Br, DL, &*FallThroughMBB); +} + +static void emitGPDisp(MachineFunction &F, const MipsInstrInfo *TII) { + MachineBasicBlock &MBB = F.front(); + MachineBasicBlock::iterator I = MBB.begin(); + DebugLoc DL = MBB.findDebugLoc(MBB.begin()); + BuildMI(MBB, I, DL, TII->get(Mips::LUi), Mips::V0) + .addExternalSymbol("_gp_disp", MipsII::MO_ABS_HI); + BuildMI(MBB, I, DL, TII->get(Mips::ADDiu), Mips::V0) + .addReg(Mips::V0).addExternalSymbol("_gp_disp", MipsII::MO_ABS_LO); + MBB.removeLiveIn(Mips::V0); +} + +bool MipsLongBranch::runOnMachineFunction(MachineFunction &F) { + const MipsSubtarget &STI = + static_cast<const MipsSubtarget &>(F.getSubtarget()); + const MipsInstrInfo *TII = + static_cast<const MipsInstrInfo *>(STI.getInstrInfo()); + LongBranchSeqSize = + !IsPIC ? 2 : (ABI.IsN64() ? 10 : (!STI.isTargetNaCl() ? 9 : 10)); + + if (STI.inMips16Mode() || !STI.enableLongBranchPass()) + return false; + if ((TM.getRelocationModel() == Reloc::PIC_) && + static_cast<const MipsTargetMachine &>(TM).getABI().IsO32() && + F.getInfo<MipsFunctionInfo>()->globalBaseRegSet()) + emitGPDisp(F, TII); + + if (SkipLongBranch) + return true; + + MF = &F; + initMBBInfo(); + + SmallVectorImpl<MBBInfo>::iterator I, E = MBBInfos.end(); + bool EverMadeChange = false, MadeChange = true; + + while (MadeChange) { + MadeChange = false; + + for (I = MBBInfos.begin(); I != E; ++I) { + // Skip if this MBB doesn't have a branch or the branch has already been + // converted to a long branch. + if (!I->Br || I->HasLongBranch) + continue; + + int ShVal = STI.inMicroMipsMode() ? 2 : 4; + int64_t Offset = computeOffset(I->Br) / ShVal; + + if (STI.isTargetNaCl()) { + // The offset calculation does not include sandboxing instructions + // that will be added later in the MC layer. Since at this point we + // don't know the exact amount of code that "sandboxing" will add, we + // conservatively estimate that code will not grow more than 100%. + Offset *= 2; + } + + // Check if offset fits into 16-bit immediate field of branches. + if (!ForceLongBranch && isInt<16>(Offset)) + continue; + + I->HasLongBranch = true; + I->Size += LongBranchSeqSize * 4; + ++LongBranches; + EverMadeChange = MadeChange = true; + } + } + + if (!EverMadeChange) + return true; + + // Compute basic block addresses. + if (TM.getRelocationModel() == Reloc::PIC_) { + uint64_t Address = 0; + + for (I = MBBInfos.begin(); I != E; Address += I->Size, ++I) + I->Address = Address; + } + + // Do the expansion. + for (I = MBBInfos.begin(); I != E; ++I) + if (I->HasLongBranch) + expandToLongBranch(*I); + + MF->RenumberBlocks(); + + return true; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsMCInstLower.cpp b/contrib/llvm/lib/Target/Mips/MipsMCInstLower.cpp new file mode 100644 index 0000000..80d9b75 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsMCInstLower.cpp @@ -0,0 +1,240 @@ +//===-- MipsMCInstLower.cpp - Convert Mips MachineInstr to MCInst ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code to lower Mips MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// +#include "MipsMCInstLower.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsAsmPrinter.h" +#include "MipsInstrInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/IR/Mangler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCStreamer.h" + +using namespace llvm; + +MipsMCInstLower::MipsMCInstLower(MipsAsmPrinter &asmprinter) + : AsmPrinter(asmprinter) {} + +void MipsMCInstLower::Initialize(MCContext *C) { + Ctx = C; +} + +MCOperand MipsMCInstLower::LowerSymbolOperand(const MachineOperand &MO, + MachineOperandType MOTy, + unsigned Offset) const { + MCSymbolRefExpr::VariantKind Kind; + const MCSymbol *Symbol; + + switch(MO.getTargetFlags()) { + default: llvm_unreachable("Invalid target flag!"); + case MipsII::MO_NO_FLAG: Kind = MCSymbolRefExpr::VK_None; break; + case MipsII::MO_GPREL: Kind = MCSymbolRefExpr::VK_Mips_GPREL; break; + case MipsII::MO_GOT_CALL: Kind = MCSymbolRefExpr::VK_Mips_GOT_CALL; break; + case MipsII::MO_GOT16: Kind = MCSymbolRefExpr::VK_Mips_GOT16; break; + case MipsII::MO_GOT: Kind = MCSymbolRefExpr::VK_Mips_GOT; break; + case MipsII::MO_ABS_HI: Kind = MCSymbolRefExpr::VK_Mips_ABS_HI; break; + case MipsII::MO_ABS_LO: Kind = MCSymbolRefExpr::VK_Mips_ABS_LO; break; + case MipsII::MO_TLSGD: Kind = MCSymbolRefExpr::VK_Mips_TLSGD; break; + case MipsII::MO_TLSLDM: Kind = MCSymbolRefExpr::VK_Mips_TLSLDM; break; + case MipsII::MO_DTPREL_HI: Kind = MCSymbolRefExpr::VK_Mips_DTPREL_HI; break; + case MipsII::MO_DTPREL_LO: Kind = MCSymbolRefExpr::VK_Mips_DTPREL_LO; break; + case MipsII::MO_GOTTPREL: Kind = MCSymbolRefExpr::VK_Mips_GOTTPREL; break; + case MipsII::MO_TPREL_HI: Kind = MCSymbolRefExpr::VK_Mips_TPREL_HI; break; + case MipsII::MO_TPREL_LO: Kind = MCSymbolRefExpr::VK_Mips_TPREL_LO; break; + case MipsII::MO_GPOFF_HI: Kind = MCSymbolRefExpr::VK_Mips_GPOFF_HI; break; + case MipsII::MO_GPOFF_LO: Kind = MCSymbolRefExpr::VK_Mips_GPOFF_LO; break; + case MipsII::MO_GOT_DISP: Kind = MCSymbolRefExpr::VK_Mips_GOT_DISP; break; + case MipsII::MO_GOT_PAGE: Kind = MCSymbolRefExpr::VK_Mips_GOT_PAGE; break; + case MipsII::MO_GOT_OFST: Kind = MCSymbolRefExpr::VK_Mips_GOT_OFST; break; + case MipsII::MO_HIGHER: Kind = MCSymbolRefExpr::VK_Mips_HIGHER; break; + case MipsII::MO_HIGHEST: Kind = MCSymbolRefExpr::VK_Mips_HIGHEST; break; + case MipsII::MO_GOT_HI16: Kind = MCSymbolRefExpr::VK_Mips_GOT_HI16; break; + case MipsII::MO_GOT_LO16: Kind = MCSymbolRefExpr::VK_Mips_GOT_LO16; break; + case MipsII::MO_CALL_HI16: Kind = MCSymbolRefExpr::VK_Mips_CALL_HI16; break; + case MipsII::MO_CALL_LO16: Kind = MCSymbolRefExpr::VK_Mips_CALL_LO16; break; + } + + switch (MOTy) { + case MachineOperand::MO_MachineBasicBlock: + Symbol = MO.getMBB()->getSymbol(); + break; + + case MachineOperand::MO_GlobalAddress: + Symbol = AsmPrinter.getSymbol(MO.getGlobal()); + Offset += MO.getOffset(); + break; + + case MachineOperand::MO_BlockAddress: + Symbol = AsmPrinter.GetBlockAddressSymbol(MO.getBlockAddress()); + Offset += MO.getOffset(); + break; + + case MachineOperand::MO_ExternalSymbol: + Symbol = AsmPrinter.GetExternalSymbolSymbol(MO.getSymbolName()); + Offset += MO.getOffset(); + break; + + case MachineOperand::MO_MCSymbol: + Symbol = MO.getMCSymbol(); + Offset += MO.getOffset(); + break; + + case MachineOperand::MO_JumpTableIndex: + Symbol = AsmPrinter.GetJTISymbol(MO.getIndex()); + break; + + case MachineOperand::MO_ConstantPoolIndex: + Symbol = AsmPrinter.GetCPISymbol(MO.getIndex()); + Offset += MO.getOffset(); + break; + + default: + llvm_unreachable("<unknown operand type>"); + } + + const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Symbol, Kind, *Ctx); + + if (!Offset) + return MCOperand::createExpr(MCSym); + + // Assume offset is never negative. + assert(Offset > 0); + + const MCConstantExpr *OffsetExpr = MCConstantExpr::create(Offset, *Ctx); + const MCBinaryExpr *Add = MCBinaryExpr::createAdd(MCSym, OffsetExpr, *Ctx); + return MCOperand::createExpr(Add); +} + +/* +static void CreateMCInst(MCInst& Inst, unsigned Opc, const MCOperand &Opnd0, + const MCOperand &Opnd1, + const MCOperand &Opnd2 = MCOperand()) { + Inst.setOpcode(Opc); + Inst.addOperand(Opnd0); + Inst.addOperand(Opnd1); + if (Opnd2.isValid()) + Inst.addOperand(Opnd2); +} +*/ + +MCOperand MipsMCInstLower::LowerOperand(const MachineOperand &MO, + unsigned offset) const { + MachineOperandType MOTy = MO.getType(); + + switch (MOTy) { + default: llvm_unreachable("unknown operand type"); + case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) break; + return MCOperand::createReg(MO.getReg()); + case MachineOperand::MO_Immediate: + return MCOperand::createImm(MO.getImm() + offset); + case MachineOperand::MO_MachineBasicBlock: + case MachineOperand::MO_GlobalAddress: + case MachineOperand::MO_ExternalSymbol: + case MachineOperand::MO_MCSymbol: + case MachineOperand::MO_JumpTableIndex: + case MachineOperand::MO_ConstantPoolIndex: + case MachineOperand::MO_BlockAddress: + return LowerSymbolOperand(MO, MOTy, offset); + case MachineOperand::MO_RegisterMask: + break; + } + + return MCOperand(); +} + +MCOperand MipsMCInstLower::createSub(MachineBasicBlock *BB1, + MachineBasicBlock *BB2, + MCSymbolRefExpr::VariantKind Kind) const { + const MCSymbolRefExpr *Sym1 = MCSymbolRefExpr::create(BB1->getSymbol(), *Ctx); + const MCSymbolRefExpr *Sym2 = MCSymbolRefExpr::create(BB2->getSymbol(), *Ctx); + const MCBinaryExpr *Sub = MCBinaryExpr::createSub(Sym1, Sym2, *Ctx); + + return MCOperand::createExpr(MipsMCExpr::create(Kind, Sub, *Ctx)); +} + +void MipsMCInstLower:: +lowerLongBranchLUi(const MachineInstr *MI, MCInst &OutMI) const { + OutMI.setOpcode(Mips::LUi); + + // Lower register operand. + OutMI.addOperand(LowerOperand(MI->getOperand(0))); + + // Create %hi($tgt-$baltgt). + OutMI.addOperand(createSub(MI->getOperand(1).getMBB(), + MI->getOperand(2).getMBB(), + MCSymbolRefExpr::VK_Mips_ABS_HI)); +} + +void MipsMCInstLower:: +lowerLongBranchADDiu(const MachineInstr *MI, MCInst &OutMI, int Opcode, + MCSymbolRefExpr::VariantKind Kind) const { + OutMI.setOpcode(Opcode); + + // Lower two register operands. + for (unsigned I = 0, E = 2; I != E; ++I) { + const MachineOperand &MO = MI->getOperand(I); + OutMI.addOperand(LowerOperand(MO)); + } + + // Create %lo($tgt-$baltgt) or %hi($tgt-$baltgt). + OutMI.addOperand(createSub(MI->getOperand(2).getMBB(), + MI->getOperand(3).getMBB(), Kind)); +} + +bool MipsMCInstLower::lowerLongBranch(const MachineInstr *MI, + MCInst &OutMI) const { + switch (MI->getOpcode()) { + default: + return false; + case Mips::LONG_BRANCH_LUi: + lowerLongBranchLUi(MI, OutMI); + return true; + case Mips::LONG_BRANCH_ADDiu: + lowerLongBranchADDiu(MI, OutMI, Mips::ADDiu, + MCSymbolRefExpr::VK_Mips_ABS_LO); + return true; + case Mips::LONG_BRANCH_DADDiu: + unsigned TargetFlags = MI->getOperand(2).getTargetFlags(); + if (TargetFlags == MipsII::MO_ABS_HI) + lowerLongBranchADDiu(MI, OutMI, Mips::DADDiu, + MCSymbolRefExpr::VK_Mips_ABS_HI); + else if (TargetFlags == MipsII::MO_ABS_LO) + lowerLongBranchADDiu(MI, OutMI, Mips::DADDiu, + MCSymbolRefExpr::VK_Mips_ABS_LO); + else + report_fatal_error("Unexpected flags for LONG_BRANCH_DADDiu"); + return true; + } +} + +void MipsMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { + if (lowerLongBranch(MI, OutMI)) + return; + + OutMI.setOpcode(MI->getOpcode()); + + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + MCOperand MCOp = LowerOperand(MO); + + if (MCOp.isValid()) + OutMI.addOperand(MCOp); + } +} + diff --git a/contrib/llvm/lib/Target/Mips/MipsMCInstLower.h b/contrib/llvm/lib/Target/Mips/MipsMCInstLower.h new file mode 100644 index 0000000..1ce27e4 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsMCInstLower.h @@ -0,0 +1,50 @@ +//===-- MipsMCInstLower.h - Lower MachineInstr to MCInst -------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSMCINSTLOWER_H +#define LLVM_LIB_TARGET_MIPS_MIPSMCINSTLOWER_H +#include "MCTargetDesc/MipsMCExpr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { + class MCContext; + class MCInst; + class MCOperand; + class MachineInstr; + class MachineFunction; + class MipsAsmPrinter; + +/// MipsMCInstLower - This class is used to lower an MachineInstr into an +// MCInst. +class LLVM_LIBRARY_VISIBILITY MipsMCInstLower { + typedef MachineOperand::MachineOperandType MachineOperandType; + MCContext *Ctx; + MipsAsmPrinter &AsmPrinter; +public: + MipsMCInstLower(MipsAsmPrinter &asmprinter); + void Initialize(MCContext *C); + void Lower(const MachineInstr *MI, MCInst &OutMI) const; + MCOperand LowerOperand(const MachineOperand& MO, unsigned offset = 0) const; + +private: + MCOperand LowerSymbolOperand(const MachineOperand &MO, + MachineOperandType MOTy, unsigned Offset) const; + MCOperand createSub(MachineBasicBlock *BB1, MachineBasicBlock *BB2, + MCSymbolRefExpr::VariantKind Kind) const; + void lowerLongBranchLUi(const MachineInstr *MI, MCInst &OutMI) const; + void lowerLongBranchADDiu(const MachineInstr *MI, MCInst &OutMI, + int Opcode, + MCSymbolRefExpr::VariantKind Kind) const; + bool lowerLongBranch(const MachineInstr *MI, MCInst &OutMI) const; +}; +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsMSAInstrFormats.td b/contrib/llvm/lib/Target/Mips/MipsMSAInstrFormats.td new file mode 100644 index 0000000..7d25ea5 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsMSAInstrFormats.td @@ -0,0 +1,455 @@ +//===- MipsMSAInstrFormats.td - Mips Instruction Formats ---*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +class MSAInst : MipsInst<(outs), (ins), "", [], NoItinerary, FrmOther>, + PredicateControl, ASE_MSA { + let EncodingPredicates = [HasStdEnc]; + let Inst{31-26} = 0b011110; +} + +class MSACBranch : MSAInst { + let Inst{31-26} = 0b010001; +} + +class MSASpecial : MSAInst { + 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]; +} + +class MSA_BIT_B_FMT<bits<3> major, bits<6> minor>: MSAInst { + bits<5> ws; + bits<5> wd; + bits<3> m; + + let Inst{25-23} = major; + let Inst{22-19} = 0b1110; + let Inst{18-16} = m; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_BIT_H_FMT<bits<3> major, bits<6> minor>: MSAInst { + bits<5> ws; + bits<5> wd; + bits<4> m; + + let Inst{25-23} = major; + let Inst{22-20} = 0b110; + let Inst{19-16} = m; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_BIT_W_FMT<bits<3> major, bits<6> minor>: MSAInst { + bits<5> ws; + bits<5> wd; + bits<5> m; + + let Inst{25-23} = major; + let Inst{22-21} = 0b10; + let Inst{20-16} = m; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_BIT_D_FMT<bits<3> major, bits<6> minor>: MSAInst { + bits<5> ws; + bits<5> wd; + bits<6> m; + + let Inst{25-23} = major; + let Inst{22} = 0b0; + let Inst{21-16} = m; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_2R_FILL_FMT<bits<8> major, bits<2> df, bits<6> minor>: MSAInst { + bits<5> rs; + bits<5> wd; + + let Inst{25-18} = major; + let Inst{17-16} = df; + let Inst{15-11} = rs; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_2R_FILL_D_FMT<bits<8> major, bits<2> df, bits<6> minor>: MSAInst { + bits<5> rs; + bits<5> wd; + + let Inst{25-18} = major; + let Inst{17-16} = df; + let Inst{15-11} = rs; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_2R_FMT<bits<8> major, bits<2> df, bits<6> minor>: MSAInst { + bits<5> ws; + bits<5> wd; + + let Inst{25-18} = major; + let Inst{17-16} = df; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_2RF_FMT<bits<9> major, bits<1> df, bits<6> minor>: MSAInst { + bits<5> ws; + bits<5> wd; + + let Inst{25-17} = major; + let Inst{16} = df; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_3R_FMT<bits<3> major, bits<2> df, bits<6> minor>: MSAInst { + bits<5> wt; + bits<5> ws; + bits<5> wd; + + let Inst{25-23} = major; + let Inst{22-21} = df; + let Inst{20-16} = wt; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_3RF_FMT<bits<4> major, bits<1> df, bits<6> minor>: MSAInst { + bits<5> wt; + bits<5> ws; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21} = df; + let Inst{20-16} = wt; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_3R_INDEX_FMT<bits<3> major, bits<2> df, bits<6> minor>: MSAInst { + bits<5> rt; + bits<5> ws; + bits<5> wd; + + let Inst{25-23} = major; + let Inst{22-21} = df; + let Inst{20-16} = rt; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_FMT<bits<10> major, bits<6> minor>: MSAInst { + bits<5> ws; + bits<5> wd; + + let Inst{25-16} = major; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_CFCMSA_FMT<bits<10> major, bits<6> minor>: MSAInst { + bits<5> rd; + bits<5> cs; + + let Inst{25-16} = major; + let Inst{15-11} = cs; + let Inst{10-6} = rd; + let Inst{5-0} = minor; +} + +class MSA_ELM_CTCMSA_FMT<bits<10> major, bits<6> minor>: MSAInst { + bits<5> rs; + bits<5> cd; + + let Inst{25-16} = major; + let Inst{15-11} = rs; + let Inst{10-6} = cd; + let Inst{5-0} = minor; +} + +class MSA_ELM_B_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<4> n; + bits<5> ws; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-20} = 0b00; + let Inst{19-16} = n{3-0}; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_H_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<4> n; + bits<5> ws; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-19} = 0b100; + let Inst{18-16} = n{2-0}; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_W_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<4> n; + bits<5> ws; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-18} = 0b1100; + let Inst{17-16} = n{1-0}; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_D_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<4> n; + bits<5> ws; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-17} = 0b11100; + let Inst{16} = n{0}; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_COPY_B_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<4> n; + bits<5> ws; + bits<5> rd; + + let Inst{25-22} = major; + let Inst{21-20} = 0b00; + let Inst{19-16} = n{3-0}; + let Inst{15-11} = ws; + let Inst{10-6} = rd; + let Inst{5-0} = minor; +} + +class MSA_ELM_COPY_H_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<4> n; + bits<5> ws; + bits<5> rd; + + let Inst{25-22} = major; + let Inst{21-19} = 0b100; + let Inst{18-16} = n{2-0}; + let Inst{15-11} = ws; + let Inst{10-6} = rd; + let Inst{5-0} = minor; +} + +class MSA_ELM_COPY_W_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<4> n; + bits<5> ws; + bits<5> rd; + + let Inst{25-22} = major; + let Inst{21-18} = 0b1100; + let Inst{17-16} = n{1-0}; + let Inst{15-11} = ws; + let Inst{10-6} = rd; + let Inst{5-0} = minor; +} + +class MSA_ELM_COPY_D_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<4> n; + bits<5> ws; + bits<5> rd; + + let Inst{25-22} = major; + let Inst{21-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; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-20} = 0b00; + let Inst{19-16} = n{3-0}; + let Inst{15-11} = rs; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_INSERT_H_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<6> n; + bits<5> rs; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-19} = 0b100; + let Inst{18-16} = n{2-0}; + let Inst{15-11} = rs; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_INSERT_W_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<6> n; + bits<5> rs; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-18} = 0b1100; + let Inst{17-16} = n{1-0}; + let Inst{15-11} = rs; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_INSERT_D_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<6> n; + bits<5> rs; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-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; + bits<5> wd; + + let Inst{25-23} = major; + let Inst{22-21} = df; + let Inst{20-16} = imm; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_I8_FMT<bits<2> major, bits<6> minor>: MSAInst { + bits<8> u8; + bits<5> ws; + bits<5> wd; + + let Inst{25-24} = major; + let Inst{23-16} = u8; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_I10_FMT<bits<3> major, bits<2> df, bits<6> minor>: MSAInst { + bits<10> s10; + bits<5> wd; + + let Inst{25-23} = major; + let Inst{22-21} = df; + let Inst{20-11} = s10; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_MI10_FMT<bits<2> df, bits<4> minor>: MSAInst { + bits<21> addr; + bits<5> wd; + + let Inst{25-16} = addr{9-0}; + let Inst{15-11} = addr{20-16}; + let Inst{10-6} = wd; + let Inst{5-2} = minor; + let Inst{1-0} = df; +} + +class MSA_VEC_FMT<bits<5> major, bits<6> minor>: MSAInst { + bits<5> wt; + bits<5> ws; + bits<5> wd; + + let Inst{25-21} = major; + let Inst{20-16} = wt; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_CBRANCH_FMT<bits<3> major, bits<2> df>: MSACBranch { + bits<16> offset; + bits<5> wt; + + let Inst{25-23} = major; + let Inst{22-21} = df; + let Inst{20-16} = wt; + let Inst{15-0} = offset; +} + +class MSA_CBRANCH_V_FMT<bits<5> major>: MSACBranch { + bits<16> offset; + bits<5> wt; + + let Inst{25-21} = major; + let Inst{20-16} = wt; + let Inst{15-0} = offset; +} + +class SPECIAL_LSA_FMT<bits<6> minor>: MSASpecial { + bits<5> rs; + bits<5> rt; + bits<5> rd; + bits<2> sa; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-8} = 0b000; + let Inst{7-6} = sa; + let Inst{5-0} = minor; +} + +class SPECIAL_DLSA_FMT<bits<6> minor>: MSASpecial { + bits<5> rs; + bits<5> rt; + bits<5> rd; + bits<2> sa; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-8} = 0b000; + let Inst{7-6} = sa; + let Inst{5-0} = minor; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsMSAInstrInfo.td b/contrib/llvm/lib/Target/Mips/MipsMSAInstrInfo.td new file mode 100644 index 0000000..eacfcec --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsMSAInstrInfo.td @@ -0,0 +1,3900 @@ +//===- MipsMSAInstrInfo.td - MSA ASE instructions -*- tablegen ------------*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes Mips MSA ASE instructions. +// +//===----------------------------------------------------------------------===// + +def SDT_MipsVecCond : SDTypeProfile<1, 1, [SDTCisInt<0>, SDTCisVec<1>]>; +def SDT_VSetCC : SDTypeProfile<1, 3, [SDTCisInt<0>, + SDTCisInt<1>, + SDTCisSameAs<1, 2>, + SDTCisVT<3, OtherVT>]>; +def SDT_VFSetCC : SDTypeProfile<1, 3, [SDTCisInt<0>, + SDTCisFP<1>, + SDTCisSameAs<1, 2>, + SDTCisVT<3, OtherVT>]>; +def SDT_VSHF : SDTypeProfile<1, 3, [SDTCisInt<0>, SDTCisVec<0>, + SDTCisInt<1>, SDTCisVec<1>, + SDTCisSameAs<0, 2>, SDTCisSameAs<2, 3>]>; +def SDT_SHF : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisVec<0>, + SDTCisVT<1, i32>, SDTCisSameAs<0, 2>]>; +def SDT_ILV : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisVec<0>, + SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>]>; +def 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>; +def MipsVAllZero : SDNode<"MipsISD::VALL_ZERO", SDT_MipsVecCond>; +def MipsVAnyZero : SDNode<"MipsISD::VANY_ZERO", SDT_MipsVecCond>; +def MipsVSMax : SDNode<"MipsISD::VSMAX", SDTIntBinOp, + [SDNPCommutative, SDNPAssociative]>; +def MipsVSMin : SDNode<"MipsISD::VSMIN", SDTIntBinOp, + [SDNPCommutative, SDNPAssociative]>; +def MipsVUMax : SDNode<"MipsISD::VUMAX", SDTIntBinOp, + [SDNPCommutative, SDNPAssociative]>; +def MipsVUMin : SDNode<"MipsISD::VUMIN", SDTIntBinOp, + [SDNPCommutative, SDNPAssociative]>; +def MipsVNOR : SDNode<"MipsISD::VNOR", SDTIntBinOp, + [SDNPCommutative, SDNPAssociative]>; +def MipsVSHF : SDNode<"MipsISD::VSHF", SDT_VSHF>; +def MipsSHF : SDNode<"MipsISD::SHF", SDT_SHF>; +def MipsILVEV : SDNode<"MipsISD::ILVEV", SDT_ILV>; +def MipsILVOD : SDNode<"MipsISD::ILVOD", SDT_ILV>; +def MipsILVL : SDNode<"MipsISD::ILVL", SDT_ILV>; +def MipsILVR : SDNode<"MipsISD::ILVR", SDT_ILV>; +def MipsPCKEV : SDNode<"MipsISD::PCKEV", SDT_ILV>; +def MipsPCKOD : SDNode<"MipsISD::PCKOD", SDT_ILV>; +def MipsINSVE : SDNode<"MipsISD::INSVE", SDT_INSVE>; + +def vsetcc : SDNode<"ISD::SETCC", SDT_VSetCC>; +def vfsetcc : SDNode<"ISD::SETCC", SDT_VFSetCC>; + +def MipsVExtractSExt : SDNode<"MipsISD::VEXTRACT_SEXT_ELT", + SDTypeProfile<1, 3, [SDTCisPtrTy<2>]>, []>; +def MipsVExtractZExt : SDNode<"MipsISD::VEXTRACT_ZEXT_ELT", + SDTypeProfile<1, 3, [SDTCisPtrTy<2>]>, []>; + +def immZExt1Ptr : ImmLeaf<iPTR, [{return isUInt<1>(Imm);}]>; +def immZExt2Ptr : ImmLeaf<iPTR, [{return isUInt<2>(Imm);}]>; +def immZExt4Ptr : ImmLeaf<iPTR, [{return isUInt<4>(Imm);}]>; +def immZExt6Ptr : ImmLeaf<iPTR, [{return isUInt<6>(Imm);}]>; + +// Operands + +def uimm4_ptr : Operand<iPTR> { + let PrintMethod = "printUnsignedImm8"; +} + +def uimm6_ptr : Operand<iPTR> { + let PrintMethod = "printUnsignedImm8"; +} + +def simm5 : Operand<i32>; + +def vsplat_uimm1 : Operand<vAny> { + let PrintMethod = "printUnsignedImm8"; +} + +def vsplat_uimm2 : Operand<vAny> { + let PrintMethod = "printUnsignedImm8"; +} + +def vsplat_uimm3 : Operand<vAny> { + let PrintMethod = "printUnsignedImm8"; +} + +def vsplat_uimm4 : Operand<vAny> { + let PrintMethod = "printUnsignedImm8"; +} + +def vsplat_uimm5 : Operand<vAny> { + let PrintMethod = "printUnsignedImm8"; +} + +def vsplat_uimm6 : Operand<vAny> { + let PrintMethod = "printUnsignedImm8"; +} + +def vsplat_uimm8 : Operand<vAny> { + let PrintMethod = "printUnsignedImm8"; +} + +def vsplat_simm5 : Operand<vAny>; + +def vsplat_simm10 : Operand<vAny>; + +def immZExt2Lsa : ImmLeaf<i32, [{return isUInt<2>(Imm - 1);}]>; + +// Pattern fragments +def vextract_sext_i8 : PatFrag<(ops node:$vec, node:$idx), + (MipsVExtractSExt node:$vec, node:$idx, i8)>; +def vextract_sext_i16 : PatFrag<(ops node:$vec, node:$idx), + (MipsVExtractSExt node:$vec, node:$idx, i16)>; +def vextract_sext_i32 : PatFrag<(ops node:$vec, node:$idx), + (MipsVExtractSExt node:$vec, node:$idx, i32)>; +def vextract_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)>; +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))>; +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), + (ResTy (vfsetcc (OpTy node:$lhs), (OpTy node:$rhs), CC))>; + +// ISD::SETFALSE cannot occur +def vfsetoeq_v4f32 : vfsetcc_type<v4i32, v4f32, SETOEQ>; +def vfsetoeq_v2f64 : vfsetcc_type<v2i64, v2f64, SETOEQ>; +def vfsetoge_v4f32 : vfsetcc_type<v4i32, v4f32, SETOGE>; +def vfsetoge_v2f64 : vfsetcc_type<v2i64, v2f64, SETOGE>; +def vfsetogt_v4f32 : vfsetcc_type<v4i32, v4f32, SETOGT>; +def vfsetogt_v2f64 : vfsetcc_type<v2i64, v2f64, SETOGT>; +def vfsetole_v4f32 : vfsetcc_type<v4i32, v4f32, SETOLE>; +def vfsetole_v2f64 : vfsetcc_type<v2i64, v2f64, SETOLE>; +def vfsetolt_v4f32 : vfsetcc_type<v4i32, v4f32, SETOLT>; +def vfsetolt_v2f64 : vfsetcc_type<v2i64, v2f64, SETOLT>; +def vfsetone_v4f32 : vfsetcc_type<v4i32, v4f32, SETONE>; +def vfsetone_v2f64 : vfsetcc_type<v2i64, v2f64, SETONE>; +def vfsetord_v4f32 : vfsetcc_type<v4i32, v4f32, SETO>; +def vfsetord_v2f64 : vfsetcc_type<v2i64, v2f64, SETO>; +def vfsetun_v4f32 : vfsetcc_type<v4i32, v4f32, SETUO>; +def vfsetun_v2f64 : vfsetcc_type<v2i64, v2f64, SETUO>; +def vfsetueq_v4f32 : vfsetcc_type<v4i32, v4f32, SETUEQ>; +def vfsetueq_v2f64 : vfsetcc_type<v2i64, v2f64, SETUEQ>; +def vfsetuge_v4f32 : vfsetcc_type<v4i32, v4f32, SETUGE>; +def vfsetuge_v2f64 : vfsetcc_type<v2i64, v2f64, SETUGE>; +def vfsetugt_v4f32 : vfsetcc_type<v4i32, v4f32, SETUGT>; +def vfsetugt_v2f64 : vfsetcc_type<v2i64, v2f64, SETUGT>; +def vfsetule_v4f32 : vfsetcc_type<v4i32, v4f32, SETULE>; +def vfsetule_v2f64 : vfsetcc_type<v2i64, v2f64, SETULE>; +def vfsetult_v4f32 : vfsetcc_type<v4i32, v4f32, SETULT>; +def vfsetult_v2f64 : vfsetcc_type<v2i64, v2f64, SETULT>; +def vfsetune_v4f32 : vfsetcc_type<v4i32, v4f32, SETUNE>; +def vfsetune_v2f64 : vfsetcc_type<v2i64, v2f64, SETUNE>; +// ISD::SETTRUE cannot occur +// ISD::SETFALSE2 cannot occur +// ISD::SETTRUE2 cannot occur + +class vsetcc_type<ValueType ResTy, CondCode CC> : + PatFrag<(ops node:$lhs, node:$rhs), + (ResTy (vsetcc node:$lhs, node:$rhs, CC))>; + +def vseteq_v16i8 : vsetcc_type<v16i8, SETEQ>; +def vseteq_v8i16 : vsetcc_type<v8i16, SETEQ>; +def vseteq_v4i32 : vsetcc_type<v4i32, SETEQ>; +def vseteq_v2i64 : vsetcc_type<v2i64, SETEQ>; +def vsetle_v16i8 : vsetcc_type<v16i8, SETLE>; +def vsetle_v8i16 : vsetcc_type<v8i16, SETLE>; +def vsetle_v4i32 : vsetcc_type<v4i32, SETLE>; +def vsetle_v2i64 : vsetcc_type<v2i64, SETLE>; +def vsetlt_v16i8 : vsetcc_type<v16i8, SETLT>; +def vsetlt_v8i16 : vsetcc_type<v8i16, SETLT>; +def vsetlt_v4i32 : vsetcc_type<v4i32, SETLT>; +def vsetlt_v2i64 : vsetcc_type<v2i64, SETLT>; +def vsetule_v16i8 : vsetcc_type<v16i8, SETULE>; +def vsetule_v8i16 : vsetcc_type<v8i16, SETULE>; +def vsetule_v4i32 : vsetcc_type<v4i32, SETULE>; +def vsetule_v2i64 : vsetcc_type<v2i64, SETULE>; +def vsetult_v16i8 : vsetcc_type<v16i8, SETULT>; +def vsetult_v8i16 : vsetcc_type<v8i16, SETULT>; +def vsetult_v4i32 : vsetcc_type<v4i32, SETULT>; +def vsetult_v2i64 : vsetcc_type<v2i64, SETULT>; + +def vsplati8 : PatFrag<(ops node:$e0), + (v16i8 (build_vector node:$e0, node:$e0, + node:$e0, node:$e0, + node:$e0, node:$e0, + node:$e0, node:$e0, + node:$e0, node:$e0, + node:$e0, node:$e0, + node:$e0, node:$e0, + node:$e0, node:$e0))>; +def vsplati16 : PatFrag<(ops node:$e0), + (v8i16 (build_vector node:$e0, node:$e0, + node:$e0, node:$e0, + node:$e0, node:$e0, + node:$e0, node:$e0))>; +def vsplati32 : PatFrag<(ops node:$e0), + (v4i32 (build_vector node:$e0, node:$e0, + node:$e0, node:$e0))>; +def vsplati64 : PatFrag<(ops node:$e0), + (v2i64 (build_vector node:$e0, node:$e0))>; +def vsplatf32 : PatFrag<(ops node:$e0), + (v4f32 (build_vector node:$e0, node:$e0, + node:$e0, node:$e0))>; +def vsplatf64 : PatFrag<(ops node:$e0), + (v2f64 (build_vector node:$e0, node:$e0))>; + +def vsplati8_elt : PatFrag<(ops node:$v, node:$i), + (MipsVSHF (vsplati8 node:$i), node:$v, node:$v)>; +def vsplati16_elt : PatFrag<(ops node:$v, node:$i), + (MipsVSHF (vsplati16 node:$i), node:$v, node:$v)>; +def vsplati32_elt : PatFrag<(ops node:$v, node:$i), + (MipsVSHF (vsplati32 node:$i), node:$v, node:$v)>; +def vsplati64_elt : PatFrag<(ops node:$v, node:$i), + (MipsVSHF (vsplati64 node:$i), node:$v, node:$v)>; + +class SplatPatLeaf<Operand opclass, dag frag, code pred = [{}], + SDNodeXForm xform = NOOP_SDNodeXForm> + : PatLeaf<frag, pred, xform> { + Operand OpClass = opclass; +} + +class SplatComplexPattern<Operand opclass, ValueType ty, int numops, string fn, + list<SDNode> roots = [], + list<SDNodeProperty> props = []> : + ComplexPattern<ty, numops, fn, roots, props> { + Operand OpClass = opclass; +} + +def vsplati8_uimm3 : SplatComplexPattern<vsplat_uimm3, v16i8, 1, + "selectVSplatUimm3", + [build_vector, bitconvert]>; + +def vsplati8_uimm4 : SplatComplexPattern<vsplat_uimm4, v16i8, 1, + "selectVSplatUimm4", + [build_vector, bitconvert]>; + +def vsplati8_uimm5 : SplatComplexPattern<vsplat_uimm5, v16i8, 1, + "selectVSplatUimm5", + [build_vector, bitconvert]>; + +def vsplati8_uimm8 : SplatComplexPattern<vsplat_uimm8, v16i8, 1, + "selectVSplatUimm8", + [build_vector, bitconvert]>; + +def vsplati8_simm5 : SplatComplexPattern<vsplat_simm5, v16i8, 1, + "selectVSplatSimm5", + [build_vector, bitconvert]>; + +def vsplati16_uimm3 : SplatComplexPattern<vsplat_uimm3, v8i16, 1, + "selectVSplatUimm3", + [build_vector, bitconvert]>; + +def vsplati16_uimm4 : SplatComplexPattern<vsplat_uimm4, v8i16, 1, + "selectVSplatUimm4", + [build_vector, bitconvert]>; + +def vsplati16_uimm5 : SplatComplexPattern<vsplat_uimm5, v8i16, 1, + "selectVSplatUimm5", + [build_vector, bitconvert]>; + +def vsplati16_simm5 : SplatComplexPattern<vsplat_simm5, v8i16, 1, + "selectVSplatSimm5", + [build_vector, bitconvert]>; + +def vsplati32_uimm2 : SplatComplexPattern<vsplat_uimm2, v4i32, 1, + "selectVSplatUimm2", + [build_vector, bitconvert]>; + +def vsplati32_uimm5 : SplatComplexPattern<vsplat_uimm5, v4i32, 1, + "selectVSplatUimm5", + [build_vector, bitconvert]>; + +def vsplati32_simm5 : SplatComplexPattern<vsplat_simm5, v4i32, 1, + "selectVSplatSimm5", + [build_vector, bitconvert]>; + +def vsplati64_uimm1 : SplatComplexPattern<vsplat_uimm1, v2i64, 1, + "selectVSplatUimm1", + [build_vector, bitconvert]>; + +def vsplati64_uimm5 : SplatComplexPattern<vsplat_uimm5, v2i64, 1, + "selectVSplatUimm5", + [build_vector, bitconvert]>; + +def vsplati64_uimm6 : SplatComplexPattern<vsplat_uimm6, v2i64, 1, + "selectVSplatUimm6", + [build_vector, bitconvert]>; + +def vsplati64_simm5 : SplatComplexPattern<vsplat_simm5, v2i64, 1, + "selectVSplatSimm5", + [build_vector, bitconvert]>; + +// Any build_vector that is a constant splat with a value that is an exact +// power of 2 +def vsplat_uimm_pow2 : ComplexPattern<vAny, 1, "selectVSplatUimmPow2", + [build_vector, bitconvert]>; + +// Any build_vector that is a constant splat with a value that is the bitwise +// inverse of an exact power of 2 +def vsplat_uimm_inv_pow2 : ComplexPattern<vAny, 1, "selectVSplatUimmInvPow2", + [build_vector, bitconvert]>; + +// Any build_vector that is a constant splat with only a consecutive sequence +// of left-most bits set. +def vsplat_maskl_bits : SplatComplexPattern<vsplat_uimm8, vAny, 1, + "selectVSplatMaskL", + [build_vector, bitconvert]>; + +// Any build_vector that is a constant splat with only a consecutive sequence +// of right-most bits set. +def vsplat_maskr_bits : SplatComplexPattern<vsplat_uimm8, vAny, 1, + "selectVSplatMaskR", + [build_vector, bitconvert]>; + +// Any build_vector that is a constant splat with a value that equals 1 +// FIXME: These should be a ComplexPattern but we can't use them because the +// ISel generator requires the uses to have a name, but providing a name +// causes other errors ("used in pattern but not operand list") +def vsplat_imm_eq_1 : PatLeaf<(build_vector), [{ + APInt Imm; + EVT EltTy = N->getValueType(0).getVectorElementType(); + + return selectVSplat(N, Imm, EltTy.getSizeInBits()) && + Imm.getBitWidth() == EltTy.getSizeInBits() && Imm == 1; +}]>; + +def vsplati64_imm_eq_1 : PatLeaf<(bitconvert (v4i32 (build_vector))), [{ + APInt Imm; + SDNode *BV = N->getOperand(0).getNode(); + EVT EltTy = N->getValueType(0).getVectorElementType(); + + return selectVSplat(BV, Imm, EltTy.getSizeInBits()) && + Imm.getBitWidth() == EltTy.getSizeInBits() && Imm == 1; +}]>; + +def vbclr_b : PatFrag<(ops node:$ws, node:$wt), + (and node:$ws, (xor (shl vsplat_imm_eq_1, node:$wt), + immAllOnesV))>; +def vbclr_h : PatFrag<(ops node:$ws, node:$wt), + (and node:$ws, (xor (shl vsplat_imm_eq_1, node:$wt), + immAllOnesV))>; +def vbclr_w : PatFrag<(ops node:$ws, node:$wt), + (and node:$ws, (xor (shl vsplat_imm_eq_1, node:$wt), + immAllOnesV))>; +def vbclr_d : PatFrag<(ops node:$ws, node:$wt), + (and node:$ws, (xor (shl (v2i64 vsplati64_imm_eq_1), + node:$wt), + (bitconvert (v4i32 immAllOnesV))))>; + +def vbneg_b : PatFrag<(ops node:$ws, node:$wt), + (xor node:$ws, (shl vsplat_imm_eq_1, node:$wt))>; +def vbneg_h : PatFrag<(ops node:$ws, node:$wt), + (xor node:$ws, (shl vsplat_imm_eq_1, node:$wt))>; +def vbneg_w : PatFrag<(ops node:$ws, node:$wt), + (xor node:$ws, (shl vsplat_imm_eq_1, node:$wt))>; +def vbneg_d : PatFrag<(ops node:$ws, node:$wt), + (xor node:$ws, (shl (v2i64 vsplati64_imm_eq_1), + node:$wt))>; + +def vbset_b : PatFrag<(ops node:$ws, node:$wt), + (or node:$ws, (shl vsplat_imm_eq_1, node:$wt))>; +def vbset_h : PatFrag<(ops node:$ws, node:$wt), + (or node:$ws, (shl vsplat_imm_eq_1, node:$wt))>; +def vbset_w : PatFrag<(ops node:$ws, node:$wt), + (or node:$ws, (shl vsplat_imm_eq_1, node:$wt))>; +def vbset_d : PatFrag<(ops node:$ws, node:$wt), + (or node:$ws, (shl (v2i64 vsplati64_imm_eq_1), + node:$wt))>; + +def fms : PatFrag<(ops node:$wd, node:$ws, node:$wt), + (fsub node:$wd, (fmul node:$ws, node:$wt))>; + +def muladd : PatFrag<(ops node:$wd, node:$ws, node:$wt), + (add node:$wd, (mul node:$ws, node:$wt))>; + +def mulsub : PatFrag<(ops node:$wd, node:$ws, node:$wt), + (sub node:$wd, (mul node:$ws, node:$wt))>; + +def mul_fexp2 : PatFrag<(ops node:$ws, node:$wt), + (fmul node:$ws, (fexp2 node:$wt))>; + +// Immediates +def immSExt5 : ImmLeaf<i32, [{return isInt<5>(Imm);}]>; +def immSExt10: ImmLeaf<i32, [{return isInt<10>(Imm);}]>; + +// Instruction encoding. +class ADD_A_B_ENC : MSA_3R_FMT<0b000, 0b00, 0b010000>; +class ADD_A_H_ENC : MSA_3R_FMT<0b000, 0b01, 0b010000>; +class ADD_A_W_ENC : MSA_3R_FMT<0b000, 0b10, 0b010000>; +class ADD_A_D_ENC : MSA_3R_FMT<0b000, 0b11, 0b010000>; + +class ADDS_A_B_ENC : MSA_3R_FMT<0b001, 0b00, 0b010000>; +class ADDS_A_H_ENC : MSA_3R_FMT<0b001, 0b01, 0b010000>; +class ADDS_A_W_ENC : MSA_3R_FMT<0b001, 0b10, 0b010000>; +class ADDS_A_D_ENC : MSA_3R_FMT<0b001, 0b11, 0b010000>; + +class ADDS_S_B_ENC : MSA_3R_FMT<0b010, 0b00, 0b010000>; +class ADDS_S_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b010000>; +class ADDS_S_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b010000>; +class ADDS_S_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b010000>; + +class ADDS_U_B_ENC : MSA_3R_FMT<0b011, 0b00, 0b010000>; +class ADDS_U_H_ENC : MSA_3R_FMT<0b011, 0b01, 0b010000>; +class ADDS_U_W_ENC : MSA_3R_FMT<0b011, 0b10, 0b010000>; +class ADDS_U_D_ENC : MSA_3R_FMT<0b011, 0b11, 0b010000>; + +class ADDV_B_ENC : MSA_3R_FMT<0b000, 0b00, 0b001110>; +class ADDV_H_ENC : MSA_3R_FMT<0b000, 0b01, 0b001110>; +class ADDV_W_ENC : MSA_3R_FMT<0b000, 0b10, 0b001110>; +class ADDV_D_ENC : MSA_3R_FMT<0b000, 0b11, 0b001110>; + +class ADDVI_B_ENC : MSA_I5_FMT<0b000, 0b00, 0b000110>; +class ADDVI_H_ENC : MSA_I5_FMT<0b000, 0b01, 0b000110>; +class ADDVI_W_ENC : MSA_I5_FMT<0b000, 0b10, 0b000110>; +class ADDVI_D_ENC : MSA_I5_FMT<0b000, 0b11, 0b000110>; + +class AND_V_ENC : MSA_VEC_FMT<0b00000, 0b011110>; + +class ANDI_B_ENC : MSA_I8_FMT<0b00, 0b000000>; + +class ASUB_S_B_ENC : MSA_3R_FMT<0b100, 0b00, 0b010001>; +class ASUB_S_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b010001>; +class ASUB_S_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b010001>; +class ASUB_S_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b010001>; + +class ASUB_U_B_ENC : MSA_3R_FMT<0b101, 0b00, 0b010001>; +class ASUB_U_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b010001>; +class ASUB_U_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b010001>; +class ASUB_U_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b010001>; + +class AVE_S_B_ENC : MSA_3R_FMT<0b100, 0b00, 0b010000>; +class AVE_S_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b010000>; +class AVE_S_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b010000>; +class AVE_S_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b010000>; + +class AVE_U_B_ENC : MSA_3R_FMT<0b101, 0b00, 0b010000>; +class AVE_U_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b010000>; +class AVE_U_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b010000>; +class AVE_U_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b010000>; + +class AVER_S_B_ENC : MSA_3R_FMT<0b110, 0b00, 0b010000>; +class AVER_S_H_ENC : MSA_3R_FMT<0b110, 0b01, 0b010000>; +class AVER_S_W_ENC : MSA_3R_FMT<0b110, 0b10, 0b010000>; +class AVER_S_D_ENC : MSA_3R_FMT<0b110, 0b11, 0b010000>; + +class AVER_U_B_ENC : MSA_3R_FMT<0b111, 0b00, 0b010000>; +class AVER_U_H_ENC : MSA_3R_FMT<0b111, 0b01, 0b010000>; +class AVER_U_W_ENC : MSA_3R_FMT<0b111, 0b10, 0b010000>; +class AVER_U_D_ENC : MSA_3R_FMT<0b111, 0b11, 0b010000>; + +class BCLR_B_ENC : MSA_3R_FMT<0b011, 0b00, 0b001101>; +class BCLR_H_ENC : MSA_3R_FMT<0b011, 0b01, 0b001101>; +class BCLR_W_ENC : MSA_3R_FMT<0b011, 0b10, 0b001101>; +class BCLR_D_ENC : MSA_3R_FMT<0b011, 0b11, 0b001101>; + +class BCLRI_B_ENC : MSA_BIT_B_FMT<0b011, 0b001001>; +class BCLRI_H_ENC : MSA_BIT_H_FMT<0b011, 0b001001>; +class BCLRI_W_ENC : MSA_BIT_W_FMT<0b011, 0b001001>; +class BCLRI_D_ENC : MSA_BIT_D_FMT<0b011, 0b001001>; + +class BINSL_B_ENC : MSA_3R_FMT<0b110, 0b00, 0b001101>; +class BINSL_H_ENC : MSA_3R_FMT<0b110, 0b01, 0b001101>; +class BINSL_W_ENC : MSA_3R_FMT<0b110, 0b10, 0b001101>; +class BINSL_D_ENC : MSA_3R_FMT<0b110, 0b11, 0b001101>; + +class BINSLI_B_ENC : MSA_BIT_B_FMT<0b110, 0b001001>; +class BINSLI_H_ENC : MSA_BIT_H_FMT<0b110, 0b001001>; +class BINSLI_W_ENC : MSA_BIT_W_FMT<0b110, 0b001001>; +class BINSLI_D_ENC : MSA_BIT_D_FMT<0b110, 0b001001>; + +class BINSR_B_ENC : MSA_3R_FMT<0b111, 0b00, 0b001101>; +class BINSR_H_ENC : MSA_3R_FMT<0b111, 0b01, 0b001101>; +class BINSR_W_ENC : MSA_3R_FMT<0b111, 0b10, 0b001101>; +class BINSR_D_ENC : MSA_3R_FMT<0b111, 0b11, 0b001101>; + +class BINSRI_B_ENC : MSA_BIT_B_FMT<0b111, 0b001001>; +class BINSRI_H_ENC : MSA_BIT_H_FMT<0b111, 0b001001>; +class BINSRI_W_ENC : MSA_BIT_W_FMT<0b111, 0b001001>; +class BINSRI_D_ENC : MSA_BIT_D_FMT<0b111, 0b001001>; + +class BMNZ_V_ENC : MSA_VEC_FMT<0b00100, 0b011110>; + +class BMNZI_B_ENC : MSA_I8_FMT<0b00, 0b000001>; + +class BMZ_V_ENC : MSA_VEC_FMT<0b00101, 0b011110>; + +class BMZI_B_ENC : MSA_I8_FMT<0b01, 0b000001>; + +class BNEG_B_ENC : MSA_3R_FMT<0b101, 0b00, 0b001101>; +class BNEG_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b001101>; +class BNEG_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b001101>; +class BNEG_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b001101>; + +class BNEGI_B_ENC : MSA_BIT_B_FMT<0b101, 0b001001>; +class BNEGI_H_ENC : MSA_BIT_H_FMT<0b101, 0b001001>; +class BNEGI_W_ENC : MSA_BIT_W_FMT<0b101, 0b001001>; +class BNEGI_D_ENC : MSA_BIT_D_FMT<0b101, 0b001001>; + +class BNZ_B_ENC : MSA_CBRANCH_FMT<0b111, 0b00>; +class BNZ_H_ENC : MSA_CBRANCH_FMT<0b111, 0b01>; +class BNZ_W_ENC : MSA_CBRANCH_FMT<0b111, 0b10>; +class BNZ_D_ENC : MSA_CBRANCH_FMT<0b111, 0b11>; + +class BNZ_V_ENC : MSA_CBRANCH_V_FMT<0b01111>; + +class BSEL_V_ENC : MSA_VEC_FMT<0b00110, 0b011110>; + +class BSELI_B_ENC : MSA_I8_FMT<0b10, 0b000001>; + +class BSET_B_ENC : MSA_3R_FMT<0b100, 0b00, 0b001101>; +class BSET_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b001101>; +class BSET_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b001101>; +class BSET_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b001101>; + +class BSETI_B_ENC : MSA_BIT_B_FMT<0b100, 0b001001>; +class BSETI_H_ENC : MSA_BIT_H_FMT<0b100, 0b001001>; +class BSETI_W_ENC : MSA_BIT_W_FMT<0b100, 0b001001>; +class BSETI_D_ENC : MSA_BIT_D_FMT<0b100, 0b001001>; + +class BZ_B_ENC : MSA_CBRANCH_FMT<0b110, 0b00>; +class BZ_H_ENC : MSA_CBRANCH_FMT<0b110, 0b01>; +class BZ_W_ENC : MSA_CBRANCH_FMT<0b110, 0b10>; +class BZ_D_ENC : MSA_CBRANCH_FMT<0b110, 0b11>; + +class BZ_V_ENC : MSA_CBRANCH_V_FMT<0b01011>; + +class CEQ_B_ENC : MSA_3R_FMT<0b000, 0b00, 0b001111>; +class CEQ_H_ENC : MSA_3R_FMT<0b000, 0b01, 0b001111>; +class CEQ_W_ENC : MSA_3R_FMT<0b000, 0b10, 0b001111>; +class CEQ_D_ENC : MSA_3R_FMT<0b000, 0b11, 0b001111>; + +class CEQI_B_ENC : MSA_I5_FMT<0b000, 0b00, 0b000111>; +class CEQI_H_ENC : MSA_I5_FMT<0b000, 0b01, 0b000111>; +class CEQI_W_ENC : MSA_I5_FMT<0b000, 0b10, 0b000111>; +class CEQI_D_ENC : MSA_I5_FMT<0b000, 0b11, 0b000111>; + +class CFCMSA_ENC : MSA_ELM_CFCMSA_FMT<0b0001111110, 0b011001>; + +class CLE_S_B_ENC : MSA_3R_FMT<0b100, 0b00, 0b001111>; +class CLE_S_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b001111>; +class CLE_S_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b001111>; +class CLE_S_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b001111>; + +class CLE_U_B_ENC : MSA_3R_FMT<0b101, 0b00, 0b001111>; +class CLE_U_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b001111>; +class CLE_U_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b001111>; +class CLE_U_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b001111>; + +class CLEI_S_B_ENC : MSA_I5_FMT<0b100, 0b00, 0b000111>; +class CLEI_S_H_ENC : MSA_I5_FMT<0b100, 0b01, 0b000111>; +class CLEI_S_W_ENC : MSA_I5_FMT<0b100, 0b10, 0b000111>; +class CLEI_S_D_ENC : MSA_I5_FMT<0b100, 0b11, 0b000111>; + +class CLEI_U_B_ENC : MSA_I5_FMT<0b101, 0b00, 0b000111>; +class CLEI_U_H_ENC : MSA_I5_FMT<0b101, 0b01, 0b000111>; +class CLEI_U_W_ENC : MSA_I5_FMT<0b101, 0b10, 0b000111>; +class CLEI_U_D_ENC : MSA_I5_FMT<0b101, 0b11, 0b000111>; + +class CLT_S_B_ENC : MSA_3R_FMT<0b010, 0b00, 0b001111>; +class CLT_S_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b001111>; +class CLT_S_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b001111>; +class CLT_S_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b001111>; + +class CLT_U_B_ENC : MSA_3R_FMT<0b011, 0b00, 0b001111>; +class CLT_U_H_ENC : MSA_3R_FMT<0b011, 0b01, 0b001111>; +class CLT_U_W_ENC : MSA_3R_FMT<0b011, 0b10, 0b001111>; +class CLT_U_D_ENC : MSA_3R_FMT<0b011, 0b11, 0b001111>; + +class CLTI_S_B_ENC : MSA_I5_FMT<0b010, 0b00, 0b000111>; +class CLTI_S_H_ENC : MSA_I5_FMT<0b010, 0b01, 0b000111>; +class CLTI_S_W_ENC : MSA_I5_FMT<0b010, 0b10, 0b000111>; +class CLTI_S_D_ENC : MSA_I5_FMT<0b010, 0b11, 0b000111>; + +class CLTI_U_B_ENC : MSA_I5_FMT<0b011, 0b00, 0b000111>; +class CLTI_U_H_ENC : MSA_I5_FMT<0b011, 0b01, 0b000111>; +class CLTI_U_W_ENC : MSA_I5_FMT<0b011, 0b10, 0b000111>; +class CLTI_U_D_ENC : MSA_I5_FMT<0b011, 0b11, 0b000111>; + +class COPY_S_B_ENC : MSA_ELM_COPY_B_FMT<0b0010, 0b011001>; +class COPY_S_H_ENC : MSA_ELM_COPY_H_FMT<0b0010, 0b011001>; +class COPY_S_W_ENC : MSA_ELM_COPY_W_FMT<0b0010, 0b011001>; +class COPY_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 CTCMSA_ENC : MSA_ELM_CTCMSA_FMT<0b0000111110, 0b011001>; + +class DIV_S_B_ENC : MSA_3R_FMT<0b100, 0b00, 0b010010>; +class DIV_S_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b010010>; +class DIV_S_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b010010>; +class DIV_S_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b010010>; + +class DIV_U_B_ENC : MSA_3R_FMT<0b101, 0b00, 0b010010>; +class DIV_U_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b010010>; +class DIV_U_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b010010>; +class DIV_U_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b010010>; + +class DOTP_S_H_ENC : MSA_3R_FMT<0b000, 0b01, 0b010011>; +class DOTP_S_W_ENC : MSA_3R_FMT<0b000, 0b10, 0b010011>; +class DOTP_S_D_ENC : MSA_3R_FMT<0b000, 0b11, 0b010011>; + +class DOTP_U_H_ENC : MSA_3R_FMT<0b001, 0b01, 0b010011>; +class DOTP_U_W_ENC : MSA_3R_FMT<0b001, 0b10, 0b010011>; +class DOTP_U_D_ENC : MSA_3R_FMT<0b001, 0b11, 0b010011>; + +class DPADD_S_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b010011>; +class DPADD_S_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b010011>; +class DPADD_S_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b010011>; + +class DPADD_U_H_ENC : MSA_3R_FMT<0b011, 0b01, 0b010011>; +class DPADD_U_W_ENC : MSA_3R_FMT<0b011, 0b10, 0b010011>; +class DPADD_U_D_ENC : MSA_3R_FMT<0b011, 0b11, 0b010011>; + +class DPSUB_S_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b010011>; +class DPSUB_S_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b010011>; +class DPSUB_S_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b010011>; + +class DPSUB_U_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b010011>; +class DPSUB_U_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b010011>; +class DPSUB_U_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b010011>; + +class FADD_W_ENC : MSA_3RF_FMT<0b0000, 0b0, 0b011011>; +class FADD_D_ENC : MSA_3RF_FMT<0b0000, 0b1, 0b011011>; + +class FCAF_W_ENC : MSA_3RF_FMT<0b0000, 0b0, 0b011010>; +class FCAF_D_ENC : MSA_3RF_FMT<0b0000, 0b1, 0b011010>; + +class FCEQ_W_ENC : MSA_3RF_FMT<0b0010, 0b0, 0b011010>; +class FCEQ_D_ENC : MSA_3RF_FMT<0b0010, 0b1, 0b011010>; + +class FCLASS_W_ENC : MSA_2RF_FMT<0b110010000, 0b0, 0b011110>; +class FCLASS_D_ENC : MSA_2RF_FMT<0b110010000, 0b1, 0b011110>; + +class FCLE_W_ENC : MSA_3RF_FMT<0b0110, 0b0, 0b011010>; +class FCLE_D_ENC : MSA_3RF_FMT<0b0110, 0b1, 0b011010>; + +class FCLT_W_ENC : MSA_3RF_FMT<0b0100, 0b0, 0b011010>; +class FCLT_D_ENC : MSA_3RF_FMT<0b0100, 0b1, 0b011010>; + +class FCNE_W_ENC : MSA_3RF_FMT<0b0011, 0b0, 0b011100>; +class FCNE_D_ENC : MSA_3RF_FMT<0b0011, 0b1, 0b011100>; + +class FCOR_W_ENC : MSA_3RF_FMT<0b0001, 0b0, 0b011100>; +class FCOR_D_ENC : MSA_3RF_FMT<0b0001, 0b1, 0b011100>; + +class FCUEQ_W_ENC : MSA_3RF_FMT<0b0011, 0b0, 0b011010>; +class FCUEQ_D_ENC : MSA_3RF_FMT<0b0011, 0b1, 0b011010>; + +class FCULE_W_ENC : MSA_3RF_FMT<0b0111, 0b0, 0b011010>; +class FCULE_D_ENC : MSA_3RF_FMT<0b0111, 0b1, 0b011010>; + +class FCULT_W_ENC : MSA_3RF_FMT<0b0101, 0b0, 0b011010>; +class FCULT_D_ENC : MSA_3RF_FMT<0b0101, 0b1, 0b011010>; + +class FCUN_W_ENC : MSA_3RF_FMT<0b0001, 0b0, 0b011010>; +class FCUN_D_ENC : MSA_3RF_FMT<0b0001, 0b1, 0b011010>; + +class FCUNE_W_ENC : MSA_3RF_FMT<0b0010, 0b0, 0b011100>; +class FCUNE_D_ENC : MSA_3RF_FMT<0b0010, 0b1, 0b011100>; + +class FDIV_W_ENC : MSA_3RF_FMT<0b0011, 0b0, 0b011011>; +class FDIV_D_ENC : MSA_3RF_FMT<0b0011, 0b1, 0b011011>; + +class FEXDO_H_ENC : MSA_3RF_FMT<0b1000, 0b0, 0b011011>; +class FEXDO_W_ENC : MSA_3RF_FMT<0b1000, 0b1, 0b011011>; + +class FEXP2_W_ENC : MSA_3RF_FMT<0b0111, 0b0, 0b011011>; +class FEXP2_D_ENC : MSA_3RF_FMT<0b0111, 0b1, 0b011011>; + +class FEXUPL_W_ENC : MSA_2RF_FMT<0b110011000, 0b0, 0b011110>; +class FEXUPL_D_ENC : MSA_2RF_FMT<0b110011000, 0b1, 0b011110>; + +class FEXUPR_W_ENC : MSA_2RF_FMT<0b110011001, 0b0, 0b011110>; +class FEXUPR_D_ENC : MSA_2RF_FMT<0b110011001, 0b1, 0b011110>; + +class FFINT_S_W_ENC : MSA_2RF_FMT<0b110011110, 0b0, 0b011110>; +class FFINT_S_D_ENC : MSA_2RF_FMT<0b110011110, 0b1, 0b011110>; + +class FFINT_U_W_ENC : MSA_2RF_FMT<0b110011111, 0b0, 0b011110>; +class FFINT_U_D_ENC : MSA_2RF_FMT<0b110011111, 0b1, 0b011110>; + +class FFQL_W_ENC : MSA_2RF_FMT<0b110011010, 0b0, 0b011110>; +class FFQL_D_ENC : MSA_2RF_FMT<0b110011010, 0b1, 0b011110>; + +class FFQR_W_ENC : MSA_2RF_FMT<0b110011011, 0b0, 0b011110>; +class FFQR_D_ENC : MSA_2RF_FMT<0b110011011, 0b1, 0b011110>; + +class FILL_B_ENC : MSA_2R_FILL_FMT<0b11000000, 0b00, 0b011110>; +class FILL_H_ENC : MSA_2R_FILL_FMT<0b11000000, 0b01, 0b011110>; +class FILL_W_ENC : MSA_2R_FILL_FMT<0b11000000, 0b10, 0b011110>; +class 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>; + +class FMADD_W_ENC : MSA_3RF_FMT<0b0100, 0b0, 0b011011>; +class FMADD_D_ENC : MSA_3RF_FMT<0b0100, 0b1, 0b011011>; + +class FMAX_W_ENC : MSA_3RF_FMT<0b1110, 0b0, 0b011011>; +class FMAX_D_ENC : MSA_3RF_FMT<0b1110, 0b1, 0b011011>; + +class FMAX_A_W_ENC : MSA_3RF_FMT<0b1111, 0b0, 0b011011>; +class FMAX_A_D_ENC : MSA_3RF_FMT<0b1111, 0b1, 0b011011>; + +class FMIN_W_ENC : MSA_3RF_FMT<0b1100, 0b0, 0b011011>; +class FMIN_D_ENC : MSA_3RF_FMT<0b1100, 0b1, 0b011011>; + +class FMIN_A_W_ENC : MSA_3RF_FMT<0b1101, 0b0, 0b011011>; +class FMIN_A_D_ENC : MSA_3RF_FMT<0b1101, 0b1, 0b011011>; + +class FMSUB_W_ENC : MSA_3RF_FMT<0b0101, 0b0, 0b011011>; +class FMSUB_D_ENC : MSA_3RF_FMT<0b0101, 0b1, 0b011011>; + +class FMUL_W_ENC : MSA_3RF_FMT<0b0010, 0b0, 0b011011>; +class FMUL_D_ENC : MSA_3RF_FMT<0b0010, 0b1, 0b011011>; + +class FRINT_W_ENC : MSA_2RF_FMT<0b110010110, 0b0, 0b011110>; +class FRINT_D_ENC : MSA_2RF_FMT<0b110010110, 0b1, 0b011110>; + +class FRCP_W_ENC : MSA_2RF_FMT<0b110010101, 0b0, 0b011110>; +class FRCP_D_ENC : MSA_2RF_FMT<0b110010101, 0b1, 0b011110>; + +class FRSQRT_W_ENC : MSA_2RF_FMT<0b110010100, 0b0, 0b011110>; +class FRSQRT_D_ENC : MSA_2RF_FMT<0b110010100, 0b1, 0b011110>; + +class FSAF_W_ENC : MSA_3RF_FMT<0b1000, 0b0, 0b011010>; +class FSAF_D_ENC : MSA_3RF_FMT<0b1000, 0b1, 0b011010>; + +class FSEQ_W_ENC : MSA_3RF_FMT<0b1010, 0b0, 0b011010>; +class FSEQ_D_ENC : MSA_3RF_FMT<0b1010, 0b1, 0b011010>; + +class FSLE_W_ENC : MSA_3RF_FMT<0b1110, 0b0, 0b011010>; +class FSLE_D_ENC : MSA_3RF_FMT<0b1110, 0b1, 0b011010>; + +class FSLT_W_ENC : MSA_3RF_FMT<0b1100, 0b0, 0b011010>; +class FSLT_D_ENC : MSA_3RF_FMT<0b1100, 0b1, 0b011010>; + +class FSNE_W_ENC : MSA_3RF_FMT<0b1011, 0b0, 0b011100>; +class FSNE_D_ENC : MSA_3RF_FMT<0b1011, 0b1, 0b011100>; + +class FSOR_W_ENC : MSA_3RF_FMT<0b1001, 0b0, 0b011100>; +class FSOR_D_ENC : MSA_3RF_FMT<0b1001, 0b1, 0b011100>; + +class FSQRT_W_ENC : MSA_2RF_FMT<0b110010011, 0b0, 0b011110>; +class FSQRT_D_ENC : MSA_2RF_FMT<0b110010011, 0b1, 0b011110>; + +class FSUB_W_ENC : MSA_3RF_FMT<0b0001, 0b0, 0b011011>; +class FSUB_D_ENC : MSA_3RF_FMT<0b0001, 0b1, 0b011011>; + +class FSUEQ_W_ENC : MSA_3RF_FMT<0b1011, 0b0, 0b011010>; +class FSUEQ_D_ENC : MSA_3RF_FMT<0b1011, 0b1, 0b011010>; + +class FSULE_W_ENC : MSA_3RF_FMT<0b1111, 0b0, 0b011010>; +class FSULE_D_ENC : MSA_3RF_FMT<0b1111, 0b1, 0b011010>; + +class FSULT_W_ENC : MSA_3RF_FMT<0b1101, 0b0, 0b011010>; +class FSULT_D_ENC : MSA_3RF_FMT<0b1101, 0b1, 0b011010>; + +class FSUN_W_ENC : MSA_3RF_FMT<0b1001, 0b0, 0b011010>; +class FSUN_D_ENC : MSA_3RF_FMT<0b1001, 0b1, 0b011010>; + +class FSUNE_W_ENC : MSA_3RF_FMT<0b1010, 0b0, 0b011100>; +class FSUNE_D_ENC : MSA_3RF_FMT<0b1010, 0b1, 0b011100>; + +class FTINT_S_W_ENC : MSA_2RF_FMT<0b110011100, 0b0, 0b011110>; +class FTINT_S_D_ENC : MSA_2RF_FMT<0b110011100, 0b1, 0b011110>; + +class FTINT_U_W_ENC : MSA_2RF_FMT<0b110011101, 0b0, 0b011110>; +class FTINT_U_D_ENC : MSA_2RF_FMT<0b110011101, 0b1, 0b011110>; + +class FTQ_H_ENC : MSA_3RF_FMT<0b1010, 0b0, 0b011011>; +class FTQ_W_ENC : MSA_3RF_FMT<0b1010, 0b1, 0b011011>; + +class FTRUNC_S_W_ENC : MSA_2RF_FMT<0b110010001, 0b0, 0b011110>; +class FTRUNC_S_D_ENC : MSA_2RF_FMT<0b110010001, 0b1, 0b011110>; + +class FTRUNC_U_W_ENC : MSA_2RF_FMT<0b110010010, 0b0, 0b011110>; +class FTRUNC_U_D_ENC : MSA_2RF_FMT<0b110010010, 0b1, 0b011110>; + +class HADD_S_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b010101>; +class HADD_S_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b010101>; +class HADD_S_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b010101>; + +class HADD_U_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b010101>; +class HADD_U_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b010101>; +class HADD_U_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b010101>; + +class HSUB_S_H_ENC : MSA_3R_FMT<0b110, 0b01, 0b010101>; +class HSUB_S_W_ENC : MSA_3R_FMT<0b110, 0b10, 0b010101>; +class HSUB_S_D_ENC : MSA_3R_FMT<0b110, 0b11, 0b010101>; + +class HSUB_U_H_ENC : MSA_3R_FMT<0b111, 0b01, 0b010101>; +class HSUB_U_W_ENC : MSA_3R_FMT<0b111, 0b10, 0b010101>; +class HSUB_U_D_ENC : MSA_3R_FMT<0b111, 0b11, 0b010101>; + +class ILVEV_B_ENC : MSA_3R_FMT<0b110, 0b00, 0b010100>; +class ILVEV_H_ENC : MSA_3R_FMT<0b110, 0b01, 0b010100>; +class ILVEV_W_ENC : MSA_3R_FMT<0b110, 0b10, 0b010100>; +class ILVEV_D_ENC : MSA_3R_FMT<0b110, 0b11, 0b010100>; + +class ILVL_B_ENC : MSA_3R_FMT<0b100, 0b00, 0b010100>; +class ILVL_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b010100>; +class ILVL_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b010100>; +class ILVL_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b010100>; + +class ILVOD_B_ENC : MSA_3R_FMT<0b111, 0b00, 0b010100>; +class ILVOD_H_ENC : MSA_3R_FMT<0b111, 0b01, 0b010100>; +class ILVOD_W_ENC : MSA_3R_FMT<0b111, 0b10, 0b010100>; +class ILVOD_D_ENC : MSA_3R_FMT<0b111, 0b11, 0b010100>; + +class ILVR_B_ENC : MSA_3R_FMT<0b101, 0b00, 0b010100>; +class ILVR_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b010100>; +class ILVR_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b010100>; +class ILVR_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b010100>; + +class INSERT_B_ENC : MSA_ELM_INSERT_B_FMT<0b0100, 0b011001>; +class INSERT_H_ENC : MSA_ELM_INSERT_H_FMT<0b0100, 0b011001>; +class INSERT_W_ENC : MSA_ELM_INSERT_W_FMT<0b0100, 0b011001>; +class 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>; +class INSVE_W_ENC : MSA_ELM_W_FMT<0b0101, 0b011001>; +class INSVE_D_ENC : MSA_ELM_D_FMT<0b0101, 0b011001>; + +class LD_B_ENC : MSA_MI10_FMT<0b00, 0b1000>; +class LD_H_ENC : MSA_MI10_FMT<0b01, 0b1000>; +class LD_W_ENC : MSA_MI10_FMT<0b10, 0b1000>; +class LD_D_ENC : MSA_MI10_FMT<0b11, 0b1000>; + +class LDI_B_ENC : MSA_I10_FMT<0b110, 0b00, 0b000111>; +class LDI_H_ENC : MSA_I10_FMT<0b110, 0b01, 0b000111>; +class LDI_W_ENC : MSA_I10_FMT<0b110, 0b10, 0b000111>; +class LDI_D_ENC : MSA_I10_FMT<0b110, 0b11, 0b000111>; + +class LSA_ENC : SPECIAL_LSA_FMT<0b000101>; +class 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>; + +class MADDR_Q_H_ENC : MSA_3RF_FMT<0b1101, 0b0, 0b011100>; +class MADDR_Q_W_ENC : MSA_3RF_FMT<0b1101, 0b1, 0b011100>; + +class MADDV_B_ENC : MSA_3R_FMT<0b001, 0b00, 0b010010>; +class MADDV_H_ENC : MSA_3R_FMT<0b001, 0b01, 0b010010>; +class MADDV_W_ENC : MSA_3R_FMT<0b001, 0b10, 0b010010>; +class MADDV_D_ENC : MSA_3R_FMT<0b001, 0b11, 0b010010>; + +class MAX_A_B_ENC : MSA_3R_FMT<0b110, 0b00, 0b001110>; +class MAX_A_H_ENC : MSA_3R_FMT<0b110, 0b01, 0b001110>; +class MAX_A_W_ENC : MSA_3R_FMT<0b110, 0b10, 0b001110>; +class MAX_A_D_ENC : MSA_3R_FMT<0b110, 0b11, 0b001110>; + +class MAX_S_B_ENC : MSA_3R_FMT<0b010, 0b00, 0b001110>; +class MAX_S_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b001110>; +class MAX_S_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b001110>; +class MAX_S_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b001110>; + +class MAX_U_B_ENC : MSA_3R_FMT<0b011, 0b00, 0b001110>; +class MAX_U_H_ENC : MSA_3R_FMT<0b011, 0b01, 0b001110>; +class MAX_U_W_ENC : MSA_3R_FMT<0b011, 0b10, 0b001110>; +class MAX_U_D_ENC : MSA_3R_FMT<0b011, 0b11, 0b001110>; + +class MAXI_S_B_ENC : MSA_I5_FMT<0b010, 0b00, 0b000110>; +class MAXI_S_H_ENC : MSA_I5_FMT<0b010, 0b01, 0b000110>; +class MAXI_S_W_ENC : MSA_I5_FMT<0b010, 0b10, 0b000110>; +class MAXI_S_D_ENC : MSA_I5_FMT<0b010, 0b11, 0b000110>; + +class MAXI_U_B_ENC : MSA_I5_FMT<0b011, 0b00, 0b000110>; +class MAXI_U_H_ENC : MSA_I5_FMT<0b011, 0b01, 0b000110>; +class MAXI_U_W_ENC : MSA_I5_FMT<0b011, 0b10, 0b000110>; +class MAXI_U_D_ENC : MSA_I5_FMT<0b011, 0b11, 0b000110>; + +class MIN_A_B_ENC : MSA_3R_FMT<0b111, 0b00, 0b001110>; +class MIN_A_H_ENC : MSA_3R_FMT<0b111, 0b01, 0b001110>; +class MIN_A_W_ENC : MSA_3R_FMT<0b111, 0b10, 0b001110>; +class MIN_A_D_ENC : MSA_3R_FMT<0b111, 0b11, 0b001110>; + +class MIN_S_B_ENC : MSA_3R_FMT<0b100, 0b00, 0b001110>; +class MIN_S_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b001110>; +class MIN_S_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b001110>; +class MIN_S_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b001110>; + +class MIN_U_B_ENC : MSA_3R_FMT<0b101, 0b00, 0b001110>; +class MIN_U_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b001110>; +class MIN_U_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b001110>; +class MIN_U_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b001110>; + +class MINI_S_B_ENC : MSA_I5_FMT<0b100, 0b00, 0b000110>; +class MINI_S_H_ENC : MSA_I5_FMT<0b100, 0b01, 0b000110>; +class MINI_S_W_ENC : MSA_I5_FMT<0b100, 0b10, 0b000110>; +class MINI_S_D_ENC : MSA_I5_FMT<0b100, 0b11, 0b000110>; + +class MINI_U_B_ENC : MSA_I5_FMT<0b101, 0b00, 0b000110>; +class MINI_U_H_ENC : MSA_I5_FMT<0b101, 0b01, 0b000110>; +class MINI_U_W_ENC : MSA_I5_FMT<0b101, 0b10, 0b000110>; +class MINI_U_D_ENC : MSA_I5_FMT<0b101, 0b11, 0b000110>; + +class MOD_S_B_ENC : MSA_3R_FMT<0b110, 0b00, 0b010010>; +class MOD_S_H_ENC : MSA_3R_FMT<0b110, 0b01, 0b010010>; +class MOD_S_W_ENC : MSA_3R_FMT<0b110, 0b10, 0b010010>; +class MOD_S_D_ENC : MSA_3R_FMT<0b110, 0b11, 0b010010>; + +class MOD_U_B_ENC : MSA_3R_FMT<0b111, 0b00, 0b010010>; +class MOD_U_H_ENC : MSA_3R_FMT<0b111, 0b01, 0b010010>; +class MOD_U_W_ENC : MSA_3R_FMT<0b111, 0b10, 0b010010>; +class MOD_U_D_ENC : MSA_3R_FMT<0b111, 0b11, 0b010010>; + +class MOVE_V_ENC : MSA_ELM_FMT<0b0010111110, 0b011001>; + +class MSUB_Q_H_ENC : MSA_3RF_FMT<0b0110, 0b0, 0b011100>; +class MSUB_Q_W_ENC : MSA_3RF_FMT<0b0110, 0b1, 0b011100>; + +class MSUBR_Q_H_ENC : MSA_3RF_FMT<0b1110, 0b0, 0b011100>; +class MSUBR_Q_W_ENC : MSA_3RF_FMT<0b1110, 0b1, 0b011100>; + +class MSUBV_B_ENC : MSA_3R_FMT<0b010, 0b00, 0b010010>; +class MSUBV_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b010010>; +class MSUBV_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b010010>; +class MSUBV_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b010010>; + +class MUL_Q_H_ENC : MSA_3RF_FMT<0b0100, 0b0, 0b011100>; +class MUL_Q_W_ENC : MSA_3RF_FMT<0b0100, 0b1, 0b011100>; + +class MULR_Q_H_ENC : MSA_3RF_FMT<0b1100, 0b0, 0b011100>; +class MULR_Q_W_ENC : MSA_3RF_FMT<0b1100, 0b1, 0b011100>; + +class MULV_B_ENC : MSA_3R_FMT<0b000, 0b00, 0b010010>; +class MULV_H_ENC : MSA_3R_FMT<0b000, 0b01, 0b010010>; +class MULV_W_ENC : MSA_3R_FMT<0b000, 0b10, 0b010010>; +class MULV_D_ENC : MSA_3R_FMT<0b000, 0b11, 0b010010>; + +class NLOC_B_ENC : MSA_2R_FMT<0b11000010, 0b00, 0b011110>; +class NLOC_H_ENC : MSA_2R_FMT<0b11000010, 0b01, 0b011110>; +class NLOC_W_ENC : MSA_2R_FMT<0b11000010, 0b10, 0b011110>; +class NLOC_D_ENC : MSA_2R_FMT<0b11000010, 0b11, 0b011110>; + +class NLZC_B_ENC : MSA_2R_FMT<0b11000011, 0b00, 0b011110>; +class NLZC_H_ENC : MSA_2R_FMT<0b11000011, 0b01, 0b011110>; +class NLZC_W_ENC : MSA_2R_FMT<0b11000011, 0b10, 0b011110>; +class NLZC_D_ENC : MSA_2R_FMT<0b11000011, 0b11, 0b011110>; + +class NOR_V_ENC : MSA_VEC_FMT<0b00010, 0b011110>; + +class NORI_B_ENC : MSA_I8_FMT<0b10, 0b000000>; + +class OR_V_ENC : MSA_VEC_FMT<0b00001, 0b011110>; + +class ORI_B_ENC : MSA_I8_FMT<0b01, 0b000000>; + +class PCKEV_B_ENC : MSA_3R_FMT<0b010, 0b00, 0b010100>; +class PCKEV_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b010100>; +class PCKEV_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b010100>; +class PCKEV_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b010100>; + +class PCKOD_B_ENC : MSA_3R_FMT<0b011, 0b00, 0b010100>; +class PCKOD_H_ENC : MSA_3R_FMT<0b011, 0b01, 0b010100>; +class PCKOD_W_ENC : MSA_3R_FMT<0b011, 0b10, 0b010100>; +class PCKOD_D_ENC : MSA_3R_FMT<0b011, 0b11, 0b010100>; + +class PCNT_B_ENC : MSA_2R_FMT<0b11000001, 0b00, 0b011110>; +class PCNT_H_ENC : MSA_2R_FMT<0b11000001, 0b01, 0b011110>; +class PCNT_W_ENC : MSA_2R_FMT<0b11000001, 0b10, 0b011110>; +class PCNT_D_ENC : MSA_2R_FMT<0b11000001, 0b11, 0b011110>; + +class SAT_S_B_ENC : MSA_BIT_B_FMT<0b000, 0b001010>; +class SAT_S_H_ENC : MSA_BIT_H_FMT<0b000, 0b001010>; +class SAT_S_W_ENC : MSA_BIT_W_FMT<0b000, 0b001010>; +class SAT_S_D_ENC : MSA_BIT_D_FMT<0b000, 0b001010>; + +class SAT_U_B_ENC : MSA_BIT_B_FMT<0b001, 0b001010>; +class SAT_U_H_ENC : MSA_BIT_H_FMT<0b001, 0b001010>; +class SAT_U_W_ENC : MSA_BIT_W_FMT<0b001, 0b001010>; +class SAT_U_D_ENC : MSA_BIT_D_FMT<0b001, 0b001010>; + +class SHF_B_ENC : MSA_I8_FMT<0b00, 0b000010>; +class SHF_H_ENC : MSA_I8_FMT<0b01, 0b000010>; +class SHF_W_ENC : MSA_I8_FMT<0b10, 0b000010>; + +class SLD_B_ENC : MSA_3R_INDEX_FMT<0b000, 0b00, 0b010100>; +class SLD_H_ENC : MSA_3R_INDEX_FMT<0b000, 0b01, 0b010100>; +class SLD_W_ENC : MSA_3R_INDEX_FMT<0b000, 0b10, 0b010100>; +class SLD_D_ENC : MSA_3R_INDEX_FMT<0b000, 0b11, 0b010100>; + +class SLDI_B_ENC : MSA_ELM_B_FMT<0b0000, 0b011001>; +class SLDI_H_ENC : MSA_ELM_H_FMT<0b0000, 0b011001>; +class SLDI_W_ENC : MSA_ELM_W_FMT<0b0000, 0b011001>; +class SLDI_D_ENC : MSA_ELM_D_FMT<0b0000, 0b011001>; + +class SLL_B_ENC : MSA_3R_FMT<0b000, 0b00, 0b001101>; +class SLL_H_ENC : MSA_3R_FMT<0b000, 0b01, 0b001101>; +class SLL_W_ENC : MSA_3R_FMT<0b000, 0b10, 0b001101>; +class SLL_D_ENC : MSA_3R_FMT<0b000, 0b11, 0b001101>; + +class SLLI_B_ENC : MSA_BIT_B_FMT<0b000, 0b001001>; +class SLLI_H_ENC : MSA_BIT_H_FMT<0b000, 0b001001>; +class SLLI_W_ENC : MSA_BIT_W_FMT<0b000, 0b001001>; +class SLLI_D_ENC : MSA_BIT_D_FMT<0b000, 0b001001>; + +class SPLAT_B_ENC : MSA_3R_INDEX_FMT<0b001, 0b00, 0b010100>; +class SPLAT_H_ENC : MSA_3R_INDEX_FMT<0b001, 0b01, 0b010100>; +class SPLAT_W_ENC : MSA_3R_INDEX_FMT<0b001, 0b10, 0b010100>; +class SPLAT_D_ENC : MSA_3R_INDEX_FMT<0b001, 0b11, 0b010100>; + +class SPLATI_B_ENC : MSA_ELM_B_FMT<0b0001, 0b011001>; +class SPLATI_H_ENC : MSA_ELM_H_FMT<0b0001, 0b011001>; +class SPLATI_W_ENC : MSA_ELM_W_FMT<0b0001, 0b011001>; +class SPLATI_D_ENC : MSA_ELM_D_FMT<0b0001, 0b011001>; + +class SRA_B_ENC : MSA_3R_FMT<0b001, 0b00, 0b001101>; +class SRA_H_ENC : MSA_3R_FMT<0b001, 0b01, 0b001101>; +class SRA_W_ENC : MSA_3R_FMT<0b001, 0b10, 0b001101>; +class SRA_D_ENC : MSA_3R_FMT<0b001, 0b11, 0b001101>; + +class SRAI_B_ENC : MSA_BIT_B_FMT<0b001, 0b001001>; +class SRAI_H_ENC : MSA_BIT_H_FMT<0b001, 0b001001>; +class SRAI_W_ENC : MSA_BIT_W_FMT<0b001, 0b001001>; +class SRAI_D_ENC : MSA_BIT_D_FMT<0b001, 0b001001>; + +class SRAR_B_ENC : MSA_3R_FMT<0b001, 0b00, 0b010101>; +class SRAR_H_ENC : MSA_3R_FMT<0b001, 0b01, 0b010101>; +class SRAR_W_ENC : MSA_3R_FMT<0b001, 0b10, 0b010101>; +class SRAR_D_ENC : MSA_3R_FMT<0b001, 0b11, 0b010101>; + +class SRARI_B_ENC : MSA_BIT_B_FMT<0b010, 0b001010>; +class SRARI_H_ENC : MSA_BIT_H_FMT<0b010, 0b001010>; +class SRARI_W_ENC : MSA_BIT_W_FMT<0b010, 0b001010>; +class SRARI_D_ENC : MSA_BIT_D_FMT<0b010, 0b001010>; + +class SRL_B_ENC : MSA_3R_FMT<0b010, 0b00, 0b001101>; +class SRL_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b001101>; +class SRL_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b001101>; +class SRL_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b001101>; + +class SRLI_B_ENC : MSA_BIT_B_FMT<0b010, 0b001001>; +class SRLI_H_ENC : MSA_BIT_H_FMT<0b010, 0b001001>; +class SRLI_W_ENC : MSA_BIT_W_FMT<0b010, 0b001001>; +class SRLI_D_ENC : MSA_BIT_D_FMT<0b010, 0b001001>; + +class SRLR_B_ENC : MSA_3R_FMT<0b010, 0b00, 0b010101>; +class SRLR_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b010101>; +class SRLR_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b010101>; +class SRLR_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b010101>; + +class SRLRI_B_ENC : MSA_BIT_B_FMT<0b011, 0b001010>; +class SRLRI_H_ENC : MSA_BIT_H_FMT<0b011, 0b001010>; +class SRLRI_W_ENC : MSA_BIT_W_FMT<0b011, 0b001010>; +class SRLRI_D_ENC : MSA_BIT_D_FMT<0b011, 0b001010>; + +class ST_B_ENC : MSA_MI10_FMT<0b00, 0b1001>; +class ST_H_ENC : MSA_MI10_FMT<0b01, 0b1001>; +class ST_W_ENC : MSA_MI10_FMT<0b10, 0b1001>; +class ST_D_ENC : MSA_MI10_FMT<0b11, 0b1001>; + +class SUBS_S_B_ENC : MSA_3R_FMT<0b000, 0b00, 0b010001>; +class SUBS_S_H_ENC : MSA_3R_FMT<0b000, 0b01, 0b010001>; +class SUBS_S_W_ENC : MSA_3R_FMT<0b000, 0b10, 0b010001>; +class SUBS_S_D_ENC : MSA_3R_FMT<0b000, 0b11, 0b010001>; + +class SUBS_U_B_ENC : MSA_3R_FMT<0b001, 0b00, 0b010001>; +class SUBS_U_H_ENC : MSA_3R_FMT<0b001, 0b01, 0b010001>; +class SUBS_U_W_ENC : MSA_3R_FMT<0b001, 0b10, 0b010001>; +class SUBS_U_D_ENC : MSA_3R_FMT<0b001, 0b11, 0b010001>; + +class SUBSUS_U_B_ENC : MSA_3R_FMT<0b010, 0b00, 0b010001>; +class SUBSUS_U_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b010001>; +class SUBSUS_U_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b010001>; +class SUBSUS_U_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b010001>; + +class SUBSUU_S_B_ENC : MSA_3R_FMT<0b011, 0b00, 0b010001>; +class SUBSUU_S_H_ENC : MSA_3R_FMT<0b011, 0b01, 0b010001>; +class SUBSUU_S_W_ENC : MSA_3R_FMT<0b011, 0b10, 0b010001>; +class SUBSUU_S_D_ENC : MSA_3R_FMT<0b011, 0b11, 0b010001>; + +class SUBV_B_ENC : MSA_3R_FMT<0b001, 0b00, 0b001110>; +class SUBV_H_ENC : MSA_3R_FMT<0b001, 0b01, 0b001110>; +class SUBV_W_ENC : MSA_3R_FMT<0b001, 0b10, 0b001110>; +class SUBV_D_ENC : MSA_3R_FMT<0b001, 0b11, 0b001110>; + +class SUBVI_B_ENC : MSA_I5_FMT<0b001, 0b00, 0b000110>; +class SUBVI_H_ENC : MSA_I5_FMT<0b001, 0b01, 0b000110>; +class SUBVI_W_ENC : MSA_I5_FMT<0b001, 0b10, 0b000110>; +class SUBVI_D_ENC : MSA_I5_FMT<0b001, 0b11, 0b000110>; + +class VSHF_B_ENC : MSA_3R_FMT<0b000, 0b00, 0b010101>; +class VSHF_H_ENC : MSA_3R_FMT<0b000, 0b01, 0b010101>; +class VSHF_W_ENC : MSA_3R_FMT<0b000, 0b10, 0b010101>; +class VSHF_D_ENC : MSA_3R_FMT<0b000, 0b11, 0b010101>; + +class XOR_V_ENC : MSA_VEC_FMT<0b00011, 0b011110>; + +class XORI_B_ENC : MSA_I8_FMT<0b11, 0b000000>; + +// Instruction desc. +class MSA_BIT_B_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + ComplexPattern Imm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, vsplat_uimm3:$m); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $m"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, Imm:$m))]; + InstrItinClass Itinerary = itin; +} + +class MSA_BIT_H_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + ComplexPattern Imm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, vsplat_uimm4:$m); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $m"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, Imm:$m))]; + InstrItinClass Itinerary = itin; +} + +class MSA_BIT_W_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + ComplexPattern Imm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, vsplat_uimm5:$m); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $m"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, Imm:$m))]; + InstrItinClass Itinerary = itin; +} + +class MSA_BIT_D_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + ComplexPattern Imm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, vsplat_uimm6:$m); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $m"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, Imm:$m))]; + InstrItinClass Itinerary = itin; +} + +class MSA_BIT_X_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + Operand ImmOp, ImmLeaf Imm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, ImmOp:$m); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $m"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, Imm:$m))]; + InstrItinClass Itinerary = itin; +} + +class MSA_BIT_BINSXI_DESC_BASE<string instr_asm, ValueType Ty, + ComplexPattern Mask, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWD:$wd_in, ROWS:$ws, vsplat_uimm8:$m); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $m"); + // 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"; +} + +class MSA_BIT_BINSLI_DESC_BASE<string instr_asm, ValueType Ty, + RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> : + MSA_BIT_BINSXI_DESC_BASE<instr_asm, Ty, vsplat_maskl_bits, ROWD, ROWS, itin>; + +class MSA_BIT_BINSRI_DESC_BASE<string instr_asm, ValueType Ty, + RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> : + MSA_BIT_BINSXI_DESC_BASE<instr_asm, Ty, vsplat_maskr_bits, ROWD, ROWS, itin>; + +class MSA_BIT_SPLAT_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + SplatComplexPattern SplatImm, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, SplatImm.OpClass:$m); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $m"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, SplatImm:$m))]; + InstrItinClass Itinerary = itin; +} + +class MSA_COPY_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + ValueType VecTy, RegisterOperand ROD, + RegisterOperand ROWS, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROD:$rd); + dag InOperandList = (ins ROWS:$ws, uimm4_ptr:$n); + string AsmString = !strconcat(instr_asm, "\t$rd, $ws[$n]"); + list<dag> Pattern = [(set ROD:$rd, (OpNode (VecTy ROWS:$ws), immZExt4Ptr:$n))]; + InstrItinClass Itinerary = itin; +} + +class MSA_ELM_SLD_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS, + Operand ImmOp, ImmLeaf Imm, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWD:$wd_in, ROWS:$ws, ImmOp:$n); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws[$n]"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWD:$wd_in, ROWS:$ws, + Imm:$n))]; + string Constraints = "$wd = $wd_in"; + InstrItinClass Itinerary = itin; +} + +class MSA_COPY_PSEUDO_BASE<SDPatternOperator OpNode, ValueType VecTy, + RegisterClass RCD, RegisterClass RCWS> : + MSAPseudo<(outs RCD:$wd), (ins RCWS:$ws, uimm4_ptr:$n), + [(set RCD:$wd, (OpNode (VecTy RCWS:$ws), immZExt4Ptr:$n))]> { + bit usesCustomInserter = 1; +} + +class MSA_I5_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + SplatComplexPattern SplatImm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, SplatImm.OpClass:$imm); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $imm"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, SplatImm:$imm))]; + InstrItinClass Itinerary = itin; +} + +class MSA_I8_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + SplatComplexPattern SplatImm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, SplatImm.OpClass:$u8); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $u8"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, SplatImm:$u8))]; + InstrItinClass Itinerary = itin; +} + +class MSA_I8_SHF_DESC_BASE<string instr_asm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, uimm8:$u8); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $u8"); + list<dag> Pattern = [(set ROWD:$wd, (MipsSHF immZExt8:$u8, ROWS:$ws))]; + InstrItinClass Itinerary = itin; +} + +class MSA_I10_LDI_DESC_BASE<string instr_asm, RegisterOperand ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins vsplat_simm10:$s10); + string AsmString = !strconcat(instr_asm, "\t$wd, $s10"); + // LDI is matched using custom matching code in MipsSEISelDAGToDAG.cpp + list<dag> Pattern = []; + bit hasSideEffects = 0; + InstrItinClass Itinerary = itin; +} + +class MSA_2R_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws))]; + InstrItinClass Itinerary = itin; +} + +class MSA_2R_FILL_DESC_BASE<string instr_asm, ValueType VT, + SDPatternOperator OpNode, RegisterOperand ROWD, + RegisterOperand ROS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROS:$rs); + string AsmString = !strconcat(instr_asm, "\t$wd, $rs"); + list<dag> Pattern = [(set ROWD:$wd, (VT (OpNode ROS:$rs)))]; + InstrItinClass Itinerary = itin; +} + +class MSA_2R_FILL_PSEUDO_BASE<ValueType VT, SDPatternOperator OpNode, + RegisterClass RCWD, RegisterClass RCWS = RCWD> : + MSAPseudo<(outs RCWD:$wd), (ins RCWS:$fs), + [(set RCWD:$wd, (OpNode RCWS:$fs))]> { + let usesCustomInserter = 1; +} + +class MSA_2RF_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws))]; + InstrItinClass Itinerary = itin; +} + +class MSA_3R_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + RegisterOperand ROWT = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, ROWT:$wt); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $wt"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, ROWT:$wt))]; + InstrItinClass Itinerary = itin; +} + +class MSA_3R_BINSX_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + RegisterOperand ROWT = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWD:$wd_in, ROWS:$ws, ROWT:$wt); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $wt"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWD:$wd_in, ROWS:$ws, + ROWT:$wt))]; + string Constraints = "$wd = $wd_in"; + InstrItinClass Itinerary = itin; +} + +class MSA_3R_SPLAT_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, GPR32Opnd:$rt); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws[$rt]"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, GPR32Opnd:$rt))]; + InstrItinClass Itinerary = itin; +} + +class MSA_3R_VSHF_DESC_BASE<string instr_asm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + RegisterOperand ROWT = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWD:$wd_in, ROWS:$ws, ROWT:$wt); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $wt"); + list<dag> Pattern = [(set ROWD:$wd, (MipsVSHF ROWD:$wd_in, ROWS:$ws, + ROWT:$wt))]; + string Constraints = "$wd = $wd_in"; + InstrItinClass Itinerary = itin; +} + +class MSA_3R_SLD_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWD:$wd_in, ROWS:$ws, GPR32Opnd:$rt); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws[$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, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + RegisterOperand ROWT = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWD:$wd_in, ROWS:$ws, ROWT:$wt); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $wt"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWD:$wd_in, ROWS:$ws, + ROWT:$wt))]; + InstrItinClass Itinerary = itin; + string Constraints = "$wd = $wd_in"; +} + +class MSA_3RF_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + RegisterOperand ROWT = ROWD, + InstrItinClass itin = NoItinerary> : + MSA_3R_DESC_BASE<instr_asm, OpNode, ROWD, ROWS, ROWT, itin>; + +class MSA_3RF_4RF_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + RegisterOperand ROWT = ROWD, + InstrItinClass itin = NoItinerary> : + MSA_3R_4R_DESC_BASE<instr_asm, OpNode, ROWD, ROWS, ROWT, itin>; + +class MSA_CBRANCH_DESC_BASE<string instr_asm, RegisterOperand ROWD> { + dag OutOperandList = (outs); + dag InOperandList = (ins ROWD:$wt, brtarget:$offset); + string AsmString = !strconcat(instr_asm, "\t$wt, $offset"); + list<dag> Pattern = []; + InstrItinClass Itinerary = NoItinerary; + bit isBranch = 1; + bit isTerminator = 1; + bit hasDelaySlot = 1; + list<Register> Defs = [AT]; +} + +class MSA_INSERT_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROS, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWD:$wd_in, ROS:$rs, uimm6_ptr:$n); + string AsmString = !strconcat(instr_asm, "\t$wd[$n], $rs"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWD:$wd_in, + ROS:$rs, + immZExt6Ptr:$n))]; + InstrItinClass Itinerary = itin; + string Constraints = "$wd = $wd_in"; +} + +class MSA_INSERT_PSEUDO_BASE<SDPatternOperator OpNode, ValueType Ty, + RegisterOperand ROWD, RegisterOperand ROFS> : + MSAPseudo<(outs ROWD:$wd), (ins ROWD:$wd_in, uimm6_ptr:$n, ROFS:$fs), + [(set ROWD:$wd, (OpNode (Ty ROWD:$wd_in), ROFS:$fs, + immZExt6Ptr:$n))]> { + bit usesCustomInserter = 1; + string Constraints = "$wd = $wd_in"; +} + +class MSA_INSERT_VIDX_PSEUDO_BASE<SDPatternOperator OpNode, ValueType Ty, + RegisterOperand ROWD, RegisterOperand ROFS, + RegisterOperand ROIdx> : + MSAPseudo<(outs ROWD:$wd), (ins ROWD:$wd_in, ROIdx:$n, ROFS:$fs), + [(set ROWD:$wd, (OpNode (Ty ROWD:$wd_in), ROFS:$fs, + ROIdx:$n))]> { + bit usesCustomInserter = 1; + string Constraints = "$wd = $wd_in"; +} + +class MSA_INSVE_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + Operand ImmOp, ImmLeaf Imm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWD:$wd_in, ImmOp:$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, + Imm:$n, + ROWS:$ws, + immz:$n2))]; + InstrItinClass Itinerary = itin; + string Constraints = "$wd = $wd_in"; +} + +class MSA_VEC_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + RegisterOperand ROWT = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, ROWT:$wt); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $wt"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, ROWT:$wt))]; + InstrItinClass Itinerary = itin; +} + +class MSA_ELM_SPLAT_DESC_BASE<string instr_asm, SplatComplexPattern SplatImm, + RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, SplatImm.OpClass:$n); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws[$n]"); + list<dag> Pattern = [(set ROWD:$wd, (MipsVSHF SplatImm:$n, ROWS:$ws, + ROWS:$ws))]; + InstrItinClass Itinerary = itin; +} + +class MSA_VEC_PSEUDO_BASE<SDPatternOperator OpNode, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + RegisterOperand ROWT = ROWD> : + 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; +class ADD_A_H_DESC : MSA_3R_DESC_BASE<"add_a.h", int_mips_add_a_h, MSA128HOpnd>, + IsCommutable; +class ADD_A_W_DESC : MSA_3R_DESC_BASE<"add_a.w", int_mips_add_a_w, MSA128WOpnd>, + IsCommutable; +class ADD_A_D_DESC : MSA_3R_DESC_BASE<"add_a.d", int_mips_add_a_d, MSA128DOpnd>, + IsCommutable; + +class ADDS_A_B_DESC : MSA_3R_DESC_BASE<"adds_a.b", int_mips_adds_a_b, + MSA128BOpnd>, IsCommutable; +class ADDS_A_H_DESC : MSA_3R_DESC_BASE<"adds_a.h", int_mips_adds_a_h, + MSA128HOpnd>, IsCommutable; +class ADDS_A_W_DESC : MSA_3R_DESC_BASE<"adds_a.w", int_mips_adds_a_w, + MSA128WOpnd>, IsCommutable; +class ADDS_A_D_DESC : MSA_3R_DESC_BASE<"adds_a.d", int_mips_adds_a_d, + MSA128DOpnd>, IsCommutable; + +class ADDS_S_B_DESC : MSA_3R_DESC_BASE<"adds_s.b", int_mips_adds_s_b, + MSA128BOpnd>, IsCommutable; +class ADDS_S_H_DESC : MSA_3R_DESC_BASE<"adds_s.h", int_mips_adds_s_h, + MSA128HOpnd>, IsCommutable; +class ADDS_S_W_DESC : MSA_3R_DESC_BASE<"adds_s.w", int_mips_adds_s_w, + MSA128WOpnd>, IsCommutable; +class ADDS_S_D_DESC : MSA_3R_DESC_BASE<"adds_s.d", int_mips_adds_s_d, + MSA128DOpnd>, IsCommutable; + +class ADDS_U_B_DESC : MSA_3R_DESC_BASE<"adds_u.b", int_mips_adds_u_b, + MSA128BOpnd>, IsCommutable; +class ADDS_U_H_DESC : MSA_3R_DESC_BASE<"adds_u.h", int_mips_adds_u_h, + MSA128HOpnd>, IsCommutable; +class ADDS_U_W_DESC : MSA_3R_DESC_BASE<"adds_u.w", int_mips_adds_u_w, + MSA128WOpnd>, IsCommutable; +class ADDS_U_D_DESC : MSA_3R_DESC_BASE<"adds_u.d", int_mips_adds_u_d, + MSA128DOpnd>, IsCommutable; + +class ADDV_B_DESC : MSA_3R_DESC_BASE<"addv.b", add, MSA128BOpnd>, IsCommutable; +class ADDV_H_DESC : MSA_3R_DESC_BASE<"addv.h", add, MSA128HOpnd>, IsCommutable; +class ADDV_W_DESC : MSA_3R_DESC_BASE<"addv.w", add, MSA128WOpnd>, IsCommutable; +class ADDV_D_DESC : MSA_3R_DESC_BASE<"addv.d", add, MSA128DOpnd>, IsCommutable; + +class ADDVI_B_DESC : MSA_I5_DESC_BASE<"addvi.b", add, vsplati8_uimm5, + MSA128BOpnd>; +class ADDVI_H_DESC : MSA_I5_DESC_BASE<"addvi.h", add, vsplati16_uimm5, + MSA128HOpnd>; +class ADDVI_W_DESC : MSA_I5_DESC_BASE<"addvi.w", add, vsplati32_uimm5, + MSA128WOpnd>; +class ADDVI_D_DESC : MSA_I5_DESC_BASE<"addvi.d", add, vsplati64_uimm5, + MSA128DOpnd>; + +class AND_V_DESC : MSA_VEC_DESC_BASE<"and.v", and, MSA128BOpnd>; +class AND_V_H_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<and, MSA128HOpnd>; +class AND_V_W_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<and, MSA128WOpnd>; +class AND_V_D_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<and, MSA128DOpnd>; + +class ANDI_B_DESC : MSA_I8_DESC_BASE<"andi.b", and, vsplati8_uimm8, + MSA128BOpnd>; + +class ASUB_S_B_DESC : MSA_3R_DESC_BASE<"asub_s.b", int_mips_asub_s_b, + MSA128BOpnd>; +class ASUB_S_H_DESC : MSA_3R_DESC_BASE<"asub_s.h", int_mips_asub_s_h, + MSA128HOpnd>; +class ASUB_S_W_DESC : MSA_3R_DESC_BASE<"asub_s.w", int_mips_asub_s_w, + MSA128WOpnd>; +class ASUB_S_D_DESC : MSA_3R_DESC_BASE<"asub_s.d", int_mips_asub_s_d, + MSA128DOpnd>; + +class ASUB_U_B_DESC : MSA_3R_DESC_BASE<"asub_u.b", int_mips_asub_u_b, + MSA128BOpnd>; +class ASUB_U_H_DESC : MSA_3R_DESC_BASE<"asub_u.h", int_mips_asub_u_h, + MSA128HOpnd>; +class ASUB_U_W_DESC : MSA_3R_DESC_BASE<"asub_u.w", int_mips_asub_u_w, + MSA128WOpnd>; +class ASUB_U_D_DESC : MSA_3R_DESC_BASE<"asub_u.d", int_mips_asub_u_d, + MSA128DOpnd>; + +class AVE_S_B_DESC : MSA_3R_DESC_BASE<"ave_s.b", int_mips_ave_s_b, MSA128BOpnd>, + IsCommutable; +class AVE_S_H_DESC : MSA_3R_DESC_BASE<"ave_s.h", int_mips_ave_s_h, MSA128HOpnd>, + IsCommutable; +class AVE_S_W_DESC : MSA_3R_DESC_BASE<"ave_s.w", int_mips_ave_s_w, MSA128WOpnd>, + IsCommutable; +class AVE_S_D_DESC : MSA_3R_DESC_BASE<"ave_s.d", int_mips_ave_s_d, MSA128DOpnd>, + IsCommutable; + +class AVE_U_B_DESC : MSA_3R_DESC_BASE<"ave_u.b", int_mips_ave_u_b, MSA128BOpnd>, + IsCommutable; +class AVE_U_H_DESC : MSA_3R_DESC_BASE<"ave_u.h", int_mips_ave_u_h, MSA128HOpnd>, + IsCommutable; +class AVE_U_W_DESC : MSA_3R_DESC_BASE<"ave_u.w", int_mips_ave_u_w, MSA128WOpnd>, + IsCommutable; +class AVE_U_D_DESC : MSA_3R_DESC_BASE<"ave_u.d", int_mips_ave_u_d, MSA128DOpnd>, + IsCommutable; + +class AVER_S_B_DESC : MSA_3R_DESC_BASE<"aver_s.b", int_mips_aver_s_b, + MSA128BOpnd>, IsCommutable; +class AVER_S_H_DESC : MSA_3R_DESC_BASE<"aver_s.h", int_mips_aver_s_h, + MSA128HOpnd>, IsCommutable; +class AVER_S_W_DESC : MSA_3R_DESC_BASE<"aver_s.w", int_mips_aver_s_w, + MSA128WOpnd>, IsCommutable; +class AVER_S_D_DESC : MSA_3R_DESC_BASE<"aver_s.d", int_mips_aver_s_d, + MSA128DOpnd>, IsCommutable; + +class AVER_U_B_DESC : MSA_3R_DESC_BASE<"aver_u.b", int_mips_aver_u_b, + MSA128BOpnd>, IsCommutable; +class AVER_U_H_DESC : MSA_3R_DESC_BASE<"aver_u.h", int_mips_aver_u_h, + MSA128HOpnd>, IsCommutable; +class AVER_U_W_DESC : MSA_3R_DESC_BASE<"aver_u.w", int_mips_aver_u_w, + MSA128WOpnd>, IsCommutable; +class AVER_U_D_DESC : MSA_3R_DESC_BASE<"aver_u.d", int_mips_aver_u_d, + MSA128DOpnd>, IsCommutable; + +class BCLR_B_DESC : MSA_3R_DESC_BASE<"bclr.b", vbclr_b, MSA128BOpnd>; +class BCLR_H_DESC : MSA_3R_DESC_BASE<"bclr.h", vbclr_h, MSA128HOpnd>; +class BCLR_W_DESC : MSA_3R_DESC_BASE<"bclr.w", vbclr_w, MSA128WOpnd>; +class BCLR_D_DESC : MSA_3R_DESC_BASE<"bclr.d", vbclr_d, MSA128DOpnd>; + +class BCLRI_B_DESC : MSA_BIT_B_DESC_BASE<"bclri.b", and, vsplat_uimm_inv_pow2, + MSA128BOpnd>; +class BCLRI_H_DESC : MSA_BIT_H_DESC_BASE<"bclri.h", and, vsplat_uimm_inv_pow2, + MSA128HOpnd>; +class BCLRI_W_DESC : MSA_BIT_W_DESC_BASE<"bclri.w", and, vsplat_uimm_inv_pow2, + MSA128WOpnd>; +class BCLRI_D_DESC : MSA_BIT_D_DESC_BASE<"bclri.d", and, vsplat_uimm_inv_pow2, + MSA128DOpnd>; + +class BINSL_B_DESC : MSA_3R_BINSX_DESC_BASE<"binsl.b", int_mips_binsl_b, + MSA128BOpnd>; +class BINSL_H_DESC : MSA_3R_BINSX_DESC_BASE<"binsl.h", int_mips_binsl_h, + MSA128HOpnd>; +class BINSL_W_DESC : MSA_3R_BINSX_DESC_BASE<"binsl.w", int_mips_binsl_w, + MSA128WOpnd>; +class BINSL_D_DESC : MSA_3R_BINSX_DESC_BASE<"binsl.d", int_mips_binsl_d, + MSA128DOpnd>; + +class BINSLI_B_DESC : MSA_BIT_BINSLI_DESC_BASE<"binsli.b", v16i8, MSA128BOpnd>; +class BINSLI_H_DESC : MSA_BIT_BINSLI_DESC_BASE<"binsli.h", v8i16, MSA128HOpnd>; +class BINSLI_W_DESC : MSA_BIT_BINSLI_DESC_BASE<"binsli.w", v4i32, MSA128WOpnd>; +class BINSLI_D_DESC : MSA_BIT_BINSLI_DESC_BASE<"binsli.d", v2i64, MSA128DOpnd>; + +class BINSR_B_DESC : MSA_3R_BINSX_DESC_BASE<"binsr.b", int_mips_binsr_b, + MSA128BOpnd>; +class BINSR_H_DESC : MSA_3R_BINSX_DESC_BASE<"binsr.h", int_mips_binsr_h, + MSA128HOpnd>; +class BINSR_W_DESC : MSA_3R_BINSX_DESC_BASE<"binsr.w", int_mips_binsr_w, + MSA128WOpnd>; +class BINSR_D_DESC : MSA_3R_BINSX_DESC_BASE<"binsr.d", int_mips_binsr_d, + MSA128DOpnd>; + +class BINSRI_B_DESC : MSA_BIT_BINSRI_DESC_BASE<"binsri.b", v16i8, MSA128BOpnd>; +class BINSRI_H_DESC : MSA_BIT_BINSRI_DESC_BASE<"binsri.h", v8i16, MSA128HOpnd>; +class BINSRI_W_DESC : MSA_BIT_BINSRI_DESC_BASE<"binsri.w", v4i32, MSA128WOpnd>; +class BINSRI_D_DESC : MSA_BIT_BINSRI_DESC_BASE<"binsri.d", v2i64, MSA128DOpnd>; + +class BMNZ_V_DESC { + dag OutOperandList = (outs MSA128BOpnd:$wd); + dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws, + MSA128BOpnd:$wt); + string AsmString = "bmnz.v\t$wd, $ws, $wt"; + list<dag> Pattern = [(set MSA128BOpnd:$wd, (vselect MSA128BOpnd:$wt, + MSA128BOpnd:$ws, + MSA128BOpnd:$wd_in))]; + InstrItinClass Itinerary = NoItinerary; + string Constraints = "$wd = $wd_in"; +} + +class BMNZI_B_DESC { + dag OutOperandList = (outs MSA128BOpnd:$wd); + dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws, + vsplat_uimm8:$u8); + string AsmString = "bmnzi.b\t$wd, $ws, $u8"; + list<dag> Pattern = [(set MSA128BOpnd:$wd, (vselect vsplati8_uimm8:$u8, + MSA128BOpnd:$ws, + MSA128BOpnd:$wd_in))]; + InstrItinClass Itinerary = NoItinerary; + string Constraints = "$wd = $wd_in"; +} + +class BMZ_V_DESC { + dag OutOperandList = (outs MSA128BOpnd:$wd); + dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws, + MSA128BOpnd:$wt); + string AsmString = "bmz.v\t$wd, $ws, $wt"; + list<dag> Pattern = [(set MSA128BOpnd:$wd, (vselect MSA128BOpnd:$wt, + MSA128BOpnd:$wd_in, + MSA128BOpnd:$ws))]; + InstrItinClass Itinerary = NoItinerary; + string Constraints = "$wd = $wd_in"; +} + +class BMZI_B_DESC { + dag OutOperandList = (outs MSA128BOpnd:$wd); + dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws, + vsplat_uimm8:$u8); + string AsmString = "bmzi.b\t$wd, $ws, $u8"; + list<dag> Pattern = [(set MSA128BOpnd:$wd, (vselect vsplati8_uimm8:$u8, + MSA128BOpnd:$wd_in, + MSA128BOpnd:$ws))]; + InstrItinClass Itinerary = NoItinerary; + string Constraints = "$wd = $wd_in"; +} + +class BNEG_B_DESC : MSA_3R_DESC_BASE<"bneg.b", vbneg_b, MSA128BOpnd>; +class BNEG_H_DESC : MSA_3R_DESC_BASE<"bneg.h", vbneg_h, MSA128HOpnd>; +class BNEG_W_DESC : MSA_3R_DESC_BASE<"bneg.w", vbneg_w, MSA128WOpnd>; +class BNEG_D_DESC : MSA_3R_DESC_BASE<"bneg.d", vbneg_d, MSA128DOpnd>; + +class BNEGI_B_DESC : MSA_BIT_B_DESC_BASE<"bnegi.b", xor, vsplat_uimm_pow2, + MSA128BOpnd>; +class BNEGI_H_DESC : MSA_BIT_H_DESC_BASE<"bnegi.h", xor, vsplat_uimm_pow2, + MSA128HOpnd>; +class BNEGI_W_DESC : MSA_BIT_W_DESC_BASE<"bnegi.w", xor, vsplat_uimm_pow2, + MSA128WOpnd>; +class BNEGI_D_DESC : MSA_BIT_D_DESC_BASE<"bnegi.d", xor, vsplat_uimm_pow2, + MSA128DOpnd>; + +class BNZ_B_DESC : MSA_CBRANCH_DESC_BASE<"bnz.b", MSA128BOpnd>; +class BNZ_H_DESC : MSA_CBRANCH_DESC_BASE<"bnz.h", MSA128HOpnd>; +class BNZ_W_DESC : MSA_CBRANCH_DESC_BASE<"bnz.w", MSA128WOpnd>; +class BNZ_D_DESC : MSA_CBRANCH_DESC_BASE<"bnz.d", MSA128DOpnd>; + +class BNZ_V_DESC : MSA_CBRANCH_DESC_BASE<"bnz.v", MSA128BOpnd>; + +class BSEL_V_DESC { + dag OutOperandList = (outs MSA128BOpnd:$wd); + dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws, + MSA128BOpnd:$wt); + string AsmString = "bsel.v\t$wd, $ws, $wt"; + // 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:$wt, + MSA128BOpnd:$ws))]; + InstrItinClass Itinerary = NoItinerary; + string Constraints = "$wd = $wd_in"; +} + +class BSELI_B_DESC { + dag OutOperandList = (outs MSA128BOpnd:$wd); + dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws, + vsplat_uimm8:$u8); + string AsmString = "bseli.b\t$wd, $ws, $u8"; + // 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, + vsplati8_uimm8:$u8, + MSA128BOpnd:$ws))]; + InstrItinClass Itinerary = NoItinerary; + string Constraints = "$wd = $wd_in"; +} + +class BSET_B_DESC : MSA_3R_DESC_BASE<"bset.b", vbset_b, MSA128BOpnd>; +class BSET_H_DESC : MSA_3R_DESC_BASE<"bset.h", vbset_h, MSA128HOpnd>; +class BSET_W_DESC : MSA_3R_DESC_BASE<"bset.w", vbset_w, MSA128WOpnd>; +class BSET_D_DESC : MSA_3R_DESC_BASE<"bset.d", vbset_d, MSA128DOpnd>; + +class BSETI_B_DESC : MSA_BIT_B_DESC_BASE<"bseti.b", or, vsplat_uimm_pow2, + MSA128BOpnd>; +class BSETI_H_DESC : MSA_BIT_H_DESC_BASE<"bseti.h", or, vsplat_uimm_pow2, + MSA128HOpnd>; +class BSETI_W_DESC : MSA_BIT_W_DESC_BASE<"bseti.w", or, vsplat_uimm_pow2, + MSA128WOpnd>; +class BSETI_D_DESC : MSA_BIT_D_DESC_BASE<"bseti.d", or, vsplat_uimm_pow2, + MSA128DOpnd>; + +class BZ_B_DESC : MSA_CBRANCH_DESC_BASE<"bz.b", MSA128BOpnd>; +class BZ_H_DESC : MSA_CBRANCH_DESC_BASE<"bz.h", MSA128HOpnd>; +class BZ_W_DESC : MSA_CBRANCH_DESC_BASE<"bz.w", MSA128WOpnd>; +class BZ_D_DESC : MSA_CBRANCH_DESC_BASE<"bz.d", MSA128DOpnd>; + +class BZ_V_DESC : MSA_CBRANCH_DESC_BASE<"bz.v", MSA128BOpnd>; + +class CEQ_B_DESC : MSA_3R_DESC_BASE<"ceq.b", vseteq_v16i8, MSA128BOpnd>, + IsCommutable; +class CEQ_H_DESC : MSA_3R_DESC_BASE<"ceq.h", vseteq_v8i16, MSA128HOpnd>, + IsCommutable; +class CEQ_W_DESC : MSA_3R_DESC_BASE<"ceq.w", vseteq_v4i32, MSA128WOpnd>, + IsCommutable; +class CEQ_D_DESC : MSA_3R_DESC_BASE<"ceq.d", vseteq_v2i64, MSA128DOpnd>, + IsCommutable; + +class CEQI_B_DESC : MSA_I5_DESC_BASE<"ceqi.b", vseteq_v16i8, vsplati8_simm5, + MSA128BOpnd>; +class CEQI_H_DESC : MSA_I5_DESC_BASE<"ceqi.h", vseteq_v8i16, vsplati16_simm5, + MSA128HOpnd>; +class CEQI_W_DESC : MSA_I5_DESC_BASE<"ceqi.w", vseteq_v4i32, vsplati32_simm5, + MSA128WOpnd>; +class CEQI_D_DESC : MSA_I5_DESC_BASE<"ceqi.d", vseteq_v2i64, vsplati64_simm5, + MSA128DOpnd>; + +class CFCMSA_DESC { + dag OutOperandList = (outs GPR32Opnd:$rd); + dag InOperandList = (ins MSA128CROpnd:$cs); + string AsmString = "cfcmsa\t$rd, $cs"; + InstrItinClass Itinerary = NoItinerary; + bit hasSideEffects = 1; +} + +class CLE_S_B_DESC : MSA_3R_DESC_BASE<"cle_s.b", vsetle_v16i8, MSA128BOpnd>; +class CLE_S_H_DESC : MSA_3R_DESC_BASE<"cle_s.h", vsetle_v8i16, MSA128HOpnd>; +class CLE_S_W_DESC : MSA_3R_DESC_BASE<"cle_s.w", vsetle_v4i32, MSA128WOpnd>; +class CLE_S_D_DESC : MSA_3R_DESC_BASE<"cle_s.d", vsetle_v2i64, MSA128DOpnd>; + +class CLE_U_B_DESC : MSA_3R_DESC_BASE<"cle_u.b", vsetule_v16i8, MSA128BOpnd>; +class CLE_U_H_DESC : MSA_3R_DESC_BASE<"cle_u.h", vsetule_v8i16, MSA128HOpnd>; +class CLE_U_W_DESC : MSA_3R_DESC_BASE<"cle_u.w", vsetule_v4i32, MSA128WOpnd>; +class CLE_U_D_DESC : MSA_3R_DESC_BASE<"cle_u.d", vsetule_v2i64, MSA128DOpnd>; + +class CLEI_S_B_DESC : MSA_I5_DESC_BASE<"clei_s.b", vsetle_v16i8, + vsplati8_simm5, MSA128BOpnd>; +class CLEI_S_H_DESC : MSA_I5_DESC_BASE<"clei_s.h", vsetle_v8i16, + vsplati16_simm5, MSA128HOpnd>; +class CLEI_S_W_DESC : MSA_I5_DESC_BASE<"clei_s.w", vsetle_v4i32, + vsplati32_simm5, MSA128WOpnd>; +class CLEI_S_D_DESC : MSA_I5_DESC_BASE<"clei_s.d", vsetle_v2i64, + vsplati64_simm5, MSA128DOpnd>; + +class CLEI_U_B_DESC : MSA_I5_DESC_BASE<"clei_u.b", vsetule_v16i8, + vsplati8_uimm5, MSA128BOpnd>; +class CLEI_U_H_DESC : MSA_I5_DESC_BASE<"clei_u.h", vsetule_v8i16, + vsplati16_uimm5, MSA128HOpnd>; +class CLEI_U_W_DESC : MSA_I5_DESC_BASE<"clei_u.w", vsetule_v4i32, + vsplati32_uimm5, MSA128WOpnd>; +class CLEI_U_D_DESC : MSA_I5_DESC_BASE<"clei_u.d", vsetule_v2i64, + vsplati64_uimm5, MSA128DOpnd>; + +class CLT_S_B_DESC : MSA_3R_DESC_BASE<"clt_s.b", vsetlt_v16i8, MSA128BOpnd>; +class CLT_S_H_DESC : MSA_3R_DESC_BASE<"clt_s.h", vsetlt_v8i16, MSA128HOpnd>; +class CLT_S_W_DESC : MSA_3R_DESC_BASE<"clt_s.w", vsetlt_v4i32, MSA128WOpnd>; +class CLT_S_D_DESC : MSA_3R_DESC_BASE<"clt_s.d", vsetlt_v2i64, MSA128DOpnd>; + +class CLT_U_B_DESC : MSA_3R_DESC_BASE<"clt_u.b", vsetult_v16i8, MSA128BOpnd>; +class CLT_U_H_DESC : MSA_3R_DESC_BASE<"clt_u.h", vsetult_v8i16, MSA128HOpnd>; +class CLT_U_W_DESC : MSA_3R_DESC_BASE<"clt_u.w", vsetult_v4i32, MSA128WOpnd>; +class CLT_U_D_DESC : MSA_3R_DESC_BASE<"clt_u.d", vsetult_v2i64, MSA128DOpnd>; + +class CLTI_S_B_DESC : MSA_I5_DESC_BASE<"clti_s.b", vsetlt_v16i8, + vsplati8_simm5, MSA128BOpnd>; +class CLTI_S_H_DESC : MSA_I5_DESC_BASE<"clti_s.h", vsetlt_v8i16, + vsplati16_simm5, MSA128HOpnd>; +class CLTI_S_W_DESC : MSA_I5_DESC_BASE<"clti_s.w", vsetlt_v4i32, + vsplati32_simm5, MSA128WOpnd>; +class CLTI_S_D_DESC : MSA_I5_DESC_BASE<"clti_s.d", vsetlt_v2i64, + vsplati64_simm5, MSA128DOpnd>; + +class CLTI_U_B_DESC : MSA_I5_DESC_BASE<"clti_u.b", vsetult_v16i8, + vsplati8_uimm5, MSA128BOpnd>; +class CLTI_U_H_DESC : MSA_I5_DESC_BASE<"clti_u.h", vsetult_v8i16, + vsplati16_uimm5, MSA128HOpnd>; +class CLTI_U_W_DESC : MSA_I5_DESC_BASE<"clti_u.w", vsetult_v4i32, + vsplati32_uimm5, MSA128WOpnd>; +class CLTI_U_D_DESC : MSA_I5_DESC_BASE<"clti_u.d", vsetult_v2i64, + vsplati64_uimm5, MSA128DOpnd>; + +class COPY_S_B_DESC : MSA_COPY_DESC_BASE<"copy_s.b", vextract_sext_i8, v16i8, + GPR32Opnd, MSA128BOpnd>; +class COPY_S_H_DESC : MSA_COPY_DESC_BASE<"copy_s.h", vextract_sext_i16, v8i16, + GPR32Opnd, MSA128HOpnd>; +class COPY_S_W_DESC : MSA_COPY_DESC_BASE<"copy_s.w", vextract_sext_i32, v4i32, + GPR32Opnd, MSA128WOpnd>; +class COPY_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>; +class COPY_U_H_DESC : MSA_COPY_DESC_BASE<"copy_u.h", vextract_zext_i16, v8i16, + GPR32Opnd, MSA128HOpnd>; +class COPY_U_W_DESC : MSA_COPY_DESC_BASE<"copy_u.w", vextract_zext_i32, v4i32, + GPR32Opnd, MSA128WOpnd>; + +class COPY_FW_PSEUDO_DESC : MSA_COPY_PSEUDO_BASE<vector_extract, v4f32, FGR32, + MSA128W>; +class COPY_FD_PSEUDO_DESC : MSA_COPY_PSEUDO_BASE<vector_extract, v2f64, FGR64, + MSA128D>; + +class CTCMSA_DESC { + dag OutOperandList = (outs); + dag InOperandList = (ins MSA128CROpnd:$cd, GPR32Opnd:$rs); + string AsmString = "ctcmsa\t$cd, $rs"; + InstrItinClass Itinerary = NoItinerary; + bit hasSideEffects = 1; +} + +class DIV_S_B_DESC : MSA_3R_DESC_BASE<"div_s.b", sdiv, MSA128BOpnd>; +class DIV_S_H_DESC : MSA_3R_DESC_BASE<"div_s.h", sdiv, MSA128HOpnd>; +class DIV_S_W_DESC : MSA_3R_DESC_BASE<"div_s.w", sdiv, MSA128WOpnd>; +class DIV_S_D_DESC : MSA_3R_DESC_BASE<"div_s.d", sdiv, MSA128DOpnd>; + +class DIV_U_B_DESC : MSA_3R_DESC_BASE<"div_u.b", udiv, MSA128BOpnd>; +class DIV_U_H_DESC : MSA_3R_DESC_BASE<"div_u.h", udiv, MSA128HOpnd>; +class DIV_U_W_DESC : MSA_3R_DESC_BASE<"div_u.w", udiv, MSA128WOpnd>; +class DIV_U_D_DESC : MSA_3R_DESC_BASE<"div_u.d", udiv, MSA128DOpnd>; + +class DOTP_S_H_DESC : MSA_3R_DESC_BASE<"dotp_s.h", int_mips_dotp_s_h, + MSA128HOpnd, MSA128BOpnd, MSA128BOpnd>, + IsCommutable; +class DOTP_S_W_DESC : MSA_3R_DESC_BASE<"dotp_s.w", int_mips_dotp_s_w, + MSA128WOpnd, MSA128HOpnd, MSA128HOpnd>, + IsCommutable; +class DOTP_S_D_DESC : MSA_3R_DESC_BASE<"dotp_s.d", int_mips_dotp_s_d, + MSA128DOpnd, MSA128WOpnd, MSA128WOpnd>, + IsCommutable; + +class DOTP_U_H_DESC : MSA_3R_DESC_BASE<"dotp_u.h", int_mips_dotp_u_h, + MSA128HOpnd, MSA128BOpnd, MSA128BOpnd>, + IsCommutable; +class DOTP_U_W_DESC : MSA_3R_DESC_BASE<"dotp_u.w", int_mips_dotp_u_w, + MSA128WOpnd, MSA128HOpnd, MSA128HOpnd>, + IsCommutable; +class DOTP_U_D_DESC : MSA_3R_DESC_BASE<"dotp_u.d", int_mips_dotp_u_d, + MSA128DOpnd, MSA128WOpnd, MSA128WOpnd>, + IsCommutable; + +class DPADD_S_H_DESC : MSA_3R_4R_DESC_BASE<"dpadd_s.h", int_mips_dpadd_s_h, + MSA128HOpnd, MSA128BOpnd, + MSA128BOpnd>, IsCommutable; +class DPADD_S_W_DESC : MSA_3R_4R_DESC_BASE<"dpadd_s.w", int_mips_dpadd_s_w, + MSA128WOpnd, MSA128HOpnd, + MSA128HOpnd>, IsCommutable; +class DPADD_S_D_DESC : MSA_3R_4R_DESC_BASE<"dpadd_s.d", int_mips_dpadd_s_d, + MSA128DOpnd, MSA128WOpnd, + MSA128WOpnd>, IsCommutable; + +class DPADD_U_H_DESC : MSA_3R_4R_DESC_BASE<"dpadd_u.h", int_mips_dpadd_u_h, + MSA128HOpnd, MSA128BOpnd, + MSA128BOpnd>, IsCommutable; +class DPADD_U_W_DESC : MSA_3R_4R_DESC_BASE<"dpadd_u.w", int_mips_dpadd_u_w, + MSA128WOpnd, MSA128HOpnd, + MSA128HOpnd>, IsCommutable; +class DPADD_U_D_DESC : MSA_3R_4R_DESC_BASE<"dpadd_u.d", int_mips_dpadd_u_d, + MSA128DOpnd, MSA128WOpnd, + MSA128WOpnd>, IsCommutable; + +class DPSUB_S_H_DESC : MSA_3R_4R_DESC_BASE<"dpsub_s.h", int_mips_dpsub_s_h, + MSA128HOpnd, MSA128BOpnd, + MSA128BOpnd>; +class DPSUB_S_W_DESC : MSA_3R_4R_DESC_BASE<"dpsub_s.w", int_mips_dpsub_s_w, + MSA128WOpnd, MSA128HOpnd, + MSA128HOpnd>; +class DPSUB_S_D_DESC : MSA_3R_4R_DESC_BASE<"dpsub_s.d", int_mips_dpsub_s_d, + MSA128DOpnd, MSA128WOpnd, + MSA128WOpnd>; + +class DPSUB_U_H_DESC : MSA_3R_4R_DESC_BASE<"dpsub_u.h", int_mips_dpsub_u_h, + MSA128HOpnd, MSA128BOpnd, + MSA128BOpnd>; +class DPSUB_U_W_DESC : MSA_3R_4R_DESC_BASE<"dpsub_u.w", int_mips_dpsub_u_w, + MSA128WOpnd, MSA128HOpnd, + MSA128HOpnd>; +class DPSUB_U_D_DESC : MSA_3R_4R_DESC_BASE<"dpsub_u.d", int_mips_dpsub_u_d, + MSA128DOpnd, MSA128WOpnd, + MSA128WOpnd>; + +class FADD_W_DESC : MSA_3RF_DESC_BASE<"fadd.w", fadd, MSA128WOpnd>, + IsCommutable; +class FADD_D_DESC : MSA_3RF_DESC_BASE<"fadd.d", fadd, MSA128DOpnd>, + IsCommutable; + +class FCAF_W_DESC : MSA_3RF_DESC_BASE<"fcaf.w", int_mips_fcaf_w, MSA128WOpnd>, + IsCommutable; +class FCAF_D_DESC : MSA_3RF_DESC_BASE<"fcaf.d", int_mips_fcaf_d, MSA128DOpnd>, + IsCommutable; + +class FCEQ_W_DESC : MSA_3RF_DESC_BASE<"fceq.w", vfsetoeq_v4f32, MSA128WOpnd>, + IsCommutable; +class FCEQ_D_DESC : MSA_3RF_DESC_BASE<"fceq.d", vfsetoeq_v2f64, MSA128DOpnd>, + IsCommutable; + +class FCLASS_W_DESC : MSA_2RF_DESC_BASE<"fclass.w", int_mips_fclass_w, + MSA128WOpnd>; +class FCLASS_D_DESC : MSA_2RF_DESC_BASE<"fclass.d", int_mips_fclass_d, + MSA128DOpnd>; + +class FCLE_W_DESC : MSA_3RF_DESC_BASE<"fcle.w", vfsetole_v4f32, MSA128WOpnd>; +class FCLE_D_DESC : MSA_3RF_DESC_BASE<"fcle.d", vfsetole_v2f64, MSA128DOpnd>; + +class FCLT_W_DESC : MSA_3RF_DESC_BASE<"fclt.w", vfsetolt_v4f32, MSA128WOpnd>; +class FCLT_D_DESC : MSA_3RF_DESC_BASE<"fclt.d", vfsetolt_v2f64, MSA128DOpnd>; + +class FCNE_W_DESC : MSA_3RF_DESC_BASE<"fcne.w", vfsetone_v4f32, MSA128WOpnd>, + IsCommutable; +class FCNE_D_DESC : MSA_3RF_DESC_BASE<"fcne.d", vfsetone_v2f64, MSA128DOpnd>, + IsCommutable; + +class FCOR_W_DESC : MSA_3RF_DESC_BASE<"fcor.w", vfsetord_v4f32, MSA128WOpnd>, + IsCommutable; +class FCOR_D_DESC : MSA_3RF_DESC_BASE<"fcor.d", vfsetord_v2f64, MSA128DOpnd>, + IsCommutable; + +class FCUEQ_W_DESC : MSA_3RF_DESC_BASE<"fcueq.w", vfsetueq_v4f32, MSA128WOpnd>, + IsCommutable; +class FCUEQ_D_DESC : MSA_3RF_DESC_BASE<"fcueq.d", vfsetueq_v2f64, MSA128DOpnd>, + IsCommutable; + +class FCULE_W_DESC : MSA_3RF_DESC_BASE<"fcule.w", vfsetule_v4f32, MSA128WOpnd>, + IsCommutable; +class FCULE_D_DESC : MSA_3RF_DESC_BASE<"fcule.d", vfsetule_v2f64, MSA128DOpnd>, + IsCommutable; + +class FCULT_W_DESC : MSA_3RF_DESC_BASE<"fcult.w", vfsetult_v4f32, MSA128WOpnd>, + IsCommutable; +class FCULT_D_DESC : MSA_3RF_DESC_BASE<"fcult.d", vfsetult_v2f64, MSA128DOpnd>, + IsCommutable; + +class FCUN_W_DESC : MSA_3RF_DESC_BASE<"fcun.w", vfsetun_v4f32, MSA128WOpnd>, + IsCommutable; +class FCUN_D_DESC : MSA_3RF_DESC_BASE<"fcun.d", vfsetun_v2f64, MSA128DOpnd>, + IsCommutable; + +class FCUNE_W_DESC : MSA_3RF_DESC_BASE<"fcune.w", vfsetune_v4f32, MSA128WOpnd>, + IsCommutable; +class FCUNE_D_DESC : MSA_3RF_DESC_BASE<"fcune.d", vfsetune_v2f64, MSA128DOpnd>, + IsCommutable; + +class FDIV_W_DESC : MSA_3RF_DESC_BASE<"fdiv.w", fdiv, MSA128WOpnd>; +class FDIV_D_DESC : MSA_3RF_DESC_BASE<"fdiv.d", fdiv, MSA128DOpnd>; + +class FEXDO_H_DESC : MSA_3RF_DESC_BASE<"fexdo.h", int_mips_fexdo_h, + MSA128HOpnd, MSA128WOpnd, MSA128WOpnd>; +class FEXDO_W_DESC : MSA_3RF_DESC_BASE<"fexdo.w", int_mips_fexdo_w, + MSA128WOpnd, MSA128DOpnd, MSA128DOpnd>; + +// The fexp2.df instruction multiplies the first operand by 2 to the power of +// the second operand. We therefore need a pseudo-insn in order to invent the +// 1.0 when we only need to match ISD::FEXP2. +class FEXP2_W_DESC : MSA_3RF_DESC_BASE<"fexp2.w", mul_fexp2, MSA128WOpnd>; +class FEXP2_D_DESC : MSA_3RF_DESC_BASE<"fexp2.d", mul_fexp2, MSA128DOpnd>; +let usesCustomInserter = 1 in { + class FEXP2_W_1_PSEUDO_DESC : + MSAPseudo<(outs MSA128W:$wd), (ins MSA128W:$ws), + [(set MSA128W:$wd, (fexp2 MSA128W:$ws))]>; + class FEXP2_D_1_PSEUDO_DESC : + 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, + MSA128WOpnd, MSA128HOpnd>; +class FEXUPL_D_DESC : MSA_2RF_DESC_BASE<"fexupl.d", int_mips_fexupl_d, + MSA128DOpnd, MSA128WOpnd>; + +class FEXUPR_W_DESC : MSA_2RF_DESC_BASE<"fexupr.w", int_mips_fexupr_w, + MSA128WOpnd, MSA128HOpnd>; +class FEXUPR_D_DESC : MSA_2RF_DESC_BASE<"fexupr.d", int_mips_fexupr_d, + MSA128DOpnd, MSA128WOpnd>; + +class FFINT_S_W_DESC : MSA_2RF_DESC_BASE<"ffint_s.w", sint_to_fp, MSA128WOpnd>; +class FFINT_S_D_DESC : MSA_2RF_DESC_BASE<"ffint_s.d", sint_to_fp, MSA128DOpnd>; + +class FFINT_U_W_DESC : MSA_2RF_DESC_BASE<"ffint_u.w", uint_to_fp, MSA128WOpnd>; +class FFINT_U_D_DESC : MSA_2RF_DESC_BASE<"ffint_u.d", uint_to_fp, MSA128DOpnd>; + +class FFQL_W_DESC : MSA_2RF_DESC_BASE<"ffql.w", int_mips_ffql_w, + MSA128WOpnd, MSA128HOpnd>; +class FFQL_D_DESC : MSA_2RF_DESC_BASE<"ffql.d", int_mips_ffql_d, + MSA128DOpnd, MSA128WOpnd>; + +class FFQR_W_DESC : MSA_2RF_DESC_BASE<"ffqr.w", int_mips_ffqr_w, + MSA128WOpnd, MSA128HOpnd>; +class FFQR_D_DESC : MSA_2RF_DESC_BASE<"ffqr.d", int_mips_ffqr_d, + MSA128DOpnd, MSA128WOpnd>; + +class FILL_B_DESC : MSA_2R_FILL_DESC_BASE<"fill.b", v16i8, vsplati8, + MSA128BOpnd, GPR32Opnd>; +class FILL_H_DESC : MSA_2R_FILL_DESC_BASE<"fill.h", v8i16, vsplati16, + MSA128HOpnd, GPR32Opnd>; +class FILL_W_DESC : MSA_2R_FILL_DESC_BASE<"fill.w", v4i32, vsplati32, + MSA128WOpnd, GPR32Opnd>; +class FILL_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>; +class FILL_FD_PSEUDO_DESC : MSA_2R_FILL_PSEUDO_BASE<v2f64, vsplatf64, MSA128D, + FGR64>; + +class FLOG2_W_DESC : MSA_2RF_DESC_BASE<"flog2.w", flog2, MSA128WOpnd>; +class FLOG2_D_DESC : MSA_2RF_DESC_BASE<"flog2.d", flog2, MSA128DOpnd>; + +class FMADD_W_DESC : MSA_3RF_4RF_DESC_BASE<"fmadd.w", fma, MSA128WOpnd>; +class FMADD_D_DESC : MSA_3RF_4RF_DESC_BASE<"fmadd.d", fma, MSA128DOpnd>; + +class FMAX_W_DESC : MSA_3RF_DESC_BASE<"fmax.w", int_mips_fmax_w, MSA128WOpnd>; +class FMAX_D_DESC : MSA_3RF_DESC_BASE<"fmax.d", int_mips_fmax_d, MSA128DOpnd>; + +class FMAX_A_W_DESC : MSA_3RF_DESC_BASE<"fmax_a.w", int_mips_fmax_a_w, + MSA128WOpnd>; +class FMAX_A_D_DESC : MSA_3RF_DESC_BASE<"fmax_a.d", int_mips_fmax_a_d, + MSA128DOpnd>; + +class FMIN_W_DESC : MSA_3RF_DESC_BASE<"fmin.w", int_mips_fmin_w, MSA128WOpnd>; +class FMIN_D_DESC : MSA_3RF_DESC_BASE<"fmin.d", int_mips_fmin_d, MSA128DOpnd>; + +class FMIN_A_W_DESC : MSA_3RF_DESC_BASE<"fmin_a.w", int_mips_fmin_a_w, + MSA128WOpnd>; +class FMIN_A_D_DESC : MSA_3RF_DESC_BASE<"fmin_a.d", int_mips_fmin_a_d, + MSA128DOpnd>; + +class FMSUB_W_DESC : MSA_3RF_4RF_DESC_BASE<"fmsub.w", fms, MSA128WOpnd>; +class FMSUB_D_DESC : MSA_3RF_4RF_DESC_BASE<"fmsub.d", fms, MSA128DOpnd>; + +class FMUL_W_DESC : MSA_3RF_DESC_BASE<"fmul.w", fmul, MSA128WOpnd>; +class FMUL_D_DESC : MSA_3RF_DESC_BASE<"fmul.d", fmul, MSA128DOpnd>; + +class FRINT_W_DESC : MSA_2RF_DESC_BASE<"frint.w", frint, MSA128WOpnd>; +class FRINT_D_DESC : MSA_2RF_DESC_BASE<"frint.d", frint, MSA128DOpnd>; + +class FRCP_W_DESC : MSA_2RF_DESC_BASE<"frcp.w", int_mips_frcp_w, MSA128WOpnd>; +class FRCP_D_DESC : MSA_2RF_DESC_BASE<"frcp.d", int_mips_frcp_d, MSA128DOpnd>; + +class FRSQRT_W_DESC : MSA_2RF_DESC_BASE<"frsqrt.w", int_mips_frsqrt_w, + MSA128WOpnd>; +class FRSQRT_D_DESC : MSA_2RF_DESC_BASE<"frsqrt.d", int_mips_frsqrt_d, + MSA128DOpnd>; + +class FSAF_W_DESC : MSA_3RF_DESC_BASE<"fsaf.w", int_mips_fsaf_w, MSA128WOpnd>; +class FSAF_D_DESC : MSA_3RF_DESC_BASE<"fsaf.d", int_mips_fsaf_d, MSA128DOpnd>; + +class FSEQ_W_DESC : MSA_3RF_DESC_BASE<"fseq.w", int_mips_fseq_w, MSA128WOpnd>; +class FSEQ_D_DESC : MSA_3RF_DESC_BASE<"fseq.d", int_mips_fseq_d, MSA128DOpnd>; + +class FSLE_W_DESC : MSA_3RF_DESC_BASE<"fsle.w", int_mips_fsle_w, MSA128WOpnd>; +class FSLE_D_DESC : MSA_3RF_DESC_BASE<"fsle.d", int_mips_fsle_d, MSA128DOpnd>; + +class FSLT_W_DESC : MSA_3RF_DESC_BASE<"fslt.w", int_mips_fslt_w, MSA128WOpnd>; +class FSLT_D_DESC : MSA_3RF_DESC_BASE<"fslt.d", int_mips_fslt_d, MSA128DOpnd>; + +class FSNE_W_DESC : MSA_3RF_DESC_BASE<"fsne.w", int_mips_fsne_w, MSA128WOpnd>; +class FSNE_D_DESC : MSA_3RF_DESC_BASE<"fsne.d", int_mips_fsne_d, MSA128DOpnd>; + +class FSOR_W_DESC : MSA_3RF_DESC_BASE<"fsor.w", int_mips_fsor_w, MSA128WOpnd>; +class FSOR_D_DESC : MSA_3RF_DESC_BASE<"fsor.d", int_mips_fsor_d, MSA128DOpnd>; + +class FSQRT_W_DESC : MSA_2RF_DESC_BASE<"fsqrt.w", fsqrt, MSA128WOpnd>; +class FSQRT_D_DESC : MSA_2RF_DESC_BASE<"fsqrt.d", fsqrt, MSA128DOpnd>; + +class FSUB_W_DESC : MSA_3RF_DESC_BASE<"fsub.w", fsub, MSA128WOpnd>; +class FSUB_D_DESC : MSA_3RF_DESC_BASE<"fsub.d", fsub, MSA128DOpnd>; + +class FSUEQ_W_DESC : MSA_3RF_DESC_BASE<"fsueq.w", int_mips_fsueq_w, + MSA128WOpnd>; +class FSUEQ_D_DESC : MSA_3RF_DESC_BASE<"fsueq.d", int_mips_fsueq_d, + MSA128DOpnd>; + +class FSULE_W_DESC : MSA_3RF_DESC_BASE<"fsule.w", int_mips_fsule_w, + MSA128WOpnd>; +class FSULE_D_DESC : MSA_3RF_DESC_BASE<"fsule.d", int_mips_fsule_d, + MSA128DOpnd>; + +class FSULT_W_DESC : MSA_3RF_DESC_BASE<"fsult.w", int_mips_fsult_w, + MSA128WOpnd>; +class FSULT_D_DESC : MSA_3RF_DESC_BASE<"fsult.d", int_mips_fsult_d, + MSA128DOpnd>; + +class FSUN_W_DESC : MSA_3RF_DESC_BASE<"fsun.w", int_mips_fsun_w, + MSA128WOpnd>; +class FSUN_D_DESC : MSA_3RF_DESC_BASE<"fsun.d", int_mips_fsun_d, + MSA128DOpnd>; + +class FSUNE_W_DESC : MSA_3RF_DESC_BASE<"fsune.w", int_mips_fsune_w, + MSA128WOpnd>; +class FSUNE_D_DESC : MSA_3RF_DESC_BASE<"fsune.d", int_mips_fsune_d, + MSA128DOpnd>; + +class FTINT_S_W_DESC : MSA_2RF_DESC_BASE<"ftint_s.w", int_mips_ftint_s_w, + MSA128WOpnd>; +class FTINT_S_D_DESC : MSA_2RF_DESC_BASE<"ftint_s.d", int_mips_ftint_s_d, + MSA128DOpnd>; + +class FTINT_U_W_DESC : MSA_2RF_DESC_BASE<"ftint_u.w", int_mips_ftint_u_w, + MSA128WOpnd>; +class FTINT_U_D_DESC : MSA_2RF_DESC_BASE<"ftint_u.d", int_mips_ftint_u_d, + MSA128DOpnd>; + +class FTQ_H_DESC : MSA_3RF_DESC_BASE<"ftq.h", int_mips_ftq_h, + MSA128HOpnd, MSA128WOpnd, MSA128WOpnd>; +class FTQ_W_DESC : MSA_3RF_DESC_BASE<"ftq.w", int_mips_ftq_w, + MSA128WOpnd, MSA128DOpnd, MSA128DOpnd>; + +class FTRUNC_S_W_DESC : MSA_2RF_DESC_BASE<"ftrunc_s.w", fp_to_sint, + MSA128WOpnd>; +class FTRUNC_S_D_DESC : MSA_2RF_DESC_BASE<"ftrunc_s.d", fp_to_sint, + MSA128DOpnd>; + +class FTRUNC_U_W_DESC : MSA_2RF_DESC_BASE<"ftrunc_u.w", fp_to_uint, + MSA128WOpnd>; +class FTRUNC_U_D_DESC : MSA_2RF_DESC_BASE<"ftrunc_u.d", fp_to_uint, + MSA128DOpnd>; + +class HADD_S_H_DESC : MSA_3R_DESC_BASE<"hadd_s.h", int_mips_hadd_s_h, + MSA128HOpnd, MSA128BOpnd, MSA128BOpnd>; +class HADD_S_W_DESC : MSA_3R_DESC_BASE<"hadd_s.w", int_mips_hadd_s_w, + MSA128WOpnd, MSA128HOpnd, MSA128HOpnd>; +class HADD_S_D_DESC : MSA_3R_DESC_BASE<"hadd_s.d", int_mips_hadd_s_d, + MSA128DOpnd, MSA128WOpnd, MSA128WOpnd>; + +class HADD_U_H_DESC : MSA_3R_DESC_BASE<"hadd_u.h", int_mips_hadd_u_h, + MSA128HOpnd, MSA128BOpnd, MSA128BOpnd>; +class HADD_U_W_DESC : MSA_3R_DESC_BASE<"hadd_u.w", int_mips_hadd_u_w, + MSA128WOpnd, MSA128HOpnd, MSA128HOpnd>; +class HADD_U_D_DESC : MSA_3R_DESC_BASE<"hadd_u.d", int_mips_hadd_u_d, + MSA128DOpnd, MSA128WOpnd, MSA128WOpnd>; + +class HSUB_S_H_DESC : MSA_3R_DESC_BASE<"hsub_s.h", int_mips_hsub_s_h, + MSA128HOpnd, MSA128BOpnd, MSA128BOpnd>; +class HSUB_S_W_DESC : MSA_3R_DESC_BASE<"hsub_s.w", int_mips_hsub_s_w, + MSA128WOpnd, MSA128HOpnd, MSA128HOpnd>; +class HSUB_S_D_DESC : MSA_3R_DESC_BASE<"hsub_s.d", int_mips_hsub_s_d, + MSA128DOpnd, MSA128WOpnd, MSA128WOpnd>; + +class HSUB_U_H_DESC : MSA_3R_DESC_BASE<"hsub_u.h", int_mips_hsub_u_h, + MSA128HOpnd, MSA128BOpnd, MSA128BOpnd>; +class HSUB_U_W_DESC : MSA_3R_DESC_BASE<"hsub_u.w", int_mips_hsub_u_w, + MSA128WOpnd, MSA128HOpnd, MSA128HOpnd>; +class HSUB_U_D_DESC : MSA_3R_DESC_BASE<"hsub_u.d", int_mips_hsub_u_d, + MSA128DOpnd, MSA128WOpnd, MSA128WOpnd>; + +class ILVEV_B_DESC : MSA_3R_DESC_BASE<"ilvev.b", MipsILVEV, MSA128BOpnd>; +class ILVEV_H_DESC : MSA_3R_DESC_BASE<"ilvev.h", MipsILVEV, MSA128HOpnd>; +class ILVEV_W_DESC : MSA_3R_DESC_BASE<"ilvev.w", MipsILVEV, MSA128WOpnd>; +class ILVEV_D_DESC : MSA_3R_DESC_BASE<"ilvev.d", MipsILVEV, MSA128DOpnd>; + +class ILVL_B_DESC : MSA_3R_DESC_BASE<"ilvl.b", MipsILVL, MSA128BOpnd>; +class ILVL_H_DESC : MSA_3R_DESC_BASE<"ilvl.h", MipsILVL, MSA128HOpnd>; +class ILVL_W_DESC : MSA_3R_DESC_BASE<"ilvl.w", MipsILVL, MSA128WOpnd>; +class ILVL_D_DESC : MSA_3R_DESC_BASE<"ilvl.d", MipsILVL, MSA128DOpnd>; + +class ILVOD_B_DESC : MSA_3R_DESC_BASE<"ilvod.b", MipsILVOD, MSA128BOpnd>; +class ILVOD_H_DESC : MSA_3R_DESC_BASE<"ilvod.h", MipsILVOD, MSA128HOpnd>; +class ILVOD_W_DESC : MSA_3R_DESC_BASE<"ilvod.w", MipsILVOD, MSA128WOpnd>; +class ILVOD_D_DESC : MSA_3R_DESC_BASE<"ilvod.d", MipsILVOD, MSA128DOpnd>; + +class ILVR_B_DESC : MSA_3R_DESC_BASE<"ilvr.b", MipsILVR, MSA128BOpnd>; +class ILVR_H_DESC : MSA_3R_DESC_BASE<"ilvr.h", MipsILVR, MSA128HOpnd>; +class ILVR_W_DESC : MSA_3R_DESC_BASE<"ilvr.w", MipsILVR, MSA128WOpnd>; +class ILVR_D_DESC : MSA_3R_DESC_BASE<"ilvr.d", MipsILVR, MSA128DOpnd>; + +class INSERT_B_DESC : MSA_INSERT_DESC_BASE<"insert.b", vinsert_v16i8, + MSA128BOpnd, GPR32Opnd>; +class INSERT_H_DESC : MSA_INSERT_DESC_BASE<"insert.h", vinsert_v8i16, + MSA128HOpnd, GPR32Opnd>; +class INSERT_W_DESC : MSA_INSERT_DESC_BASE<"insert.w", vinsert_v4i32, + MSA128WOpnd, GPR32Opnd>; +class INSERT_D_DESC : MSA_INSERT_DESC_BASE<"insert.d", vinsert_v2i64, + MSA128DOpnd, GPR64Opnd>; + +class INSERT_B_VIDX_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v16i8, MSA128BOpnd, GPR32Opnd, GPR32Opnd>; +class INSERT_H_VIDX_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v8i16, MSA128HOpnd, GPR32Opnd, GPR32Opnd>; +class INSERT_W_VIDX_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v4i32, MSA128WOpnd, GPR32Opnd, GPR32Opnd>; +class INSERT_D_VIDX_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v2i64, MSA128DOpnd, GPR64Opnd, GPR32Opnd>; + +class INSERT_FW_PSEUDO_DESC : MSA_INSERT_PSEUDO_BASE<vector_insert, v4f32, + MSA128WOpnd, FGR32Opnd>; +class INSERT_FD_PSEUDO_DESC : MSA_INSERT_PSEUDO_BASE<vector_insert, v2f64, + MSA128DOpnd, FGR64Opnd>; + +class INSERT_FW_VIDX_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v4f32, MSA128WOpnd, FGR32Opnd, GPR32Opnd>; +class INSERT_FD_VIDX_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v2f64, MSA128DOpnd, FGR64Opnd, GPR32Opnd>; + +class INSERT_B_VIDX64_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v16i8, MSA128BOpnd, GPR32Opnd, GPR64Opnd>; +class INSERT_H_VIDX64_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v8i16, MSA128HOpnd, GPR32Opnd, GPR64Opnd>; +class INSERT_W_VIDX64_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v4i32, MSA128WOpnd, GPR32Opnd, GPR64Opnd>; +class INSERT_D_VIDX64_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v2i64, MSA128DOpnd, GPR64Opnd, GPR64Opnd>; + +class INSERT_FW_VIDX64_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v4f32, MSA128WOpnd, FGR32Opnd, GPR64Opnd>; +class INSERT_FD_VIDX64_PSEUDO_DESC : + MSA_INSERT_VIDX_PSEUDO_BASE<vector_insert, v2f64, MSA128DOpnd, FGR64Opnd, GPR64Opnd>; + +class INSVE_B_DESC : MSA_INSVE_DESC_BASE<"insve.b", insve_v16i8, uimm4, immZExt4, + MSA128BOpnd>; +class INSVE_H_DESC : MSA_INSVE_DESC_BASE<"insve.h", insve_v8i16, uimm3, immZExt3, + MSA128HOpnd>; +class INSVE_W_DESC : MSA_INSVE_DESC_BASE<"insve.w", insve_v4i32, uimm2, immZExt2, + MSA128WOpnd>; +class INSVE_D_DESC : MSA_INSVE_DESC_BASE<"insve.d", insve_v2i64, uimm1, immZExt1, + MSA128DOpnd>; + +class LD_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + ValueType TyNode, RegisterOperand ROWD, + Operand MemOpnd = mem_msa, ComplexPattern Addr = addrimm10, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins MemOpnd:$addr); + string AsmString = !strconcat(instr_asm, "\t$wd, $addr"); + list<dag> Pattern = [(set ROWD:$wd, (TyNode (OpNode Addr:$addr)))]; + InstrItinClass Itinerary = itin; + string DecoderMethod = "DecodeMSA128Mem"; +} + +class LD_B_DESC : LD_DESC_BASE<"ld.b", load, v16i8, MSA128BOpnd>; +class LD_H_DESC : LD_DESC_BASE<"ld.h", load, v8i16, MSA128HOpnd>; +class LD_W_DESC : LD_DESC_BASE<"ld.w", load, v4i32, MSA128WOpnd>; +class LD_D_DESC : LD_DESC_BASE<"ld.d", load, v2i64, MSA128DOpnd>; + +class LDI_B_DESC : MSA_I10_LDI_DESC_BASE<"ldi.b", MSA128BOpnd>; +class LDI_H_DESC : MSA_I10_LDI_DESC_BASE<"ldi.h", MSA128HOpnd>; +class LDI_W_DESC : MSA_I10_LDI_DESC_BASE<"ldi.w", MSA128WOpnd>; +class LDI_D_DESC : MSA_I10_LDI_DESC_BASE<"ldi.d", MSA128DOpnd>; + +class LSA_DESC_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, uimm2_plus1:$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 = 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, + MSA128WOpnd>; + +class MADDR_Q_H_DESC : MSA_3RF_4RF_DESC_BASE<"maddr_q.h", int_mips_maddr_q_h, + MSA128HOpnd>; +class MADDR_Q_W_DESC : MSA_3RF_4RF_DESC_BASE<"maddr_q.w", int_mips_maddr_q_w, + MSA128WOpnd>; + +class MADDV_B_DESC : MSA_3R_4R_DESC_BASE<"maddv.b", muladd, MSA128BOpnd>; +class MADDV_H_DESC : MSA_3R_4R_DESC_BASE<"maddv.h", muladd, MSA128HOpnd>; +class MADDV_W_DESC : MSA_3R_4R_DESC_BASE<"maddv.w", muladd, MSA128WOpnd>; +class MADDV_D_DESC : MSA_3R_4R_DESC_BASE<"maddv.d", muladd, MSA128DOpnd>; + +class MAX_A_B_DESC : MSA_3R_DESC_BASE<"max_a.b", int_mips_max_a_b, MSA128BOpnd>; +class MAX_A_H_DESC : MSA_3R_DESC_BASE<"max_a.h", int_mips_max_a_h, MSA128HOpnd>; +class MAX_A_W_DESC : MSA_3R_DESC_BASE<"max_a.w", int_mips_max_a_w, MSA128WOpnd>; +class MAX_A_D_DESC : MSA_3R_DESC_BASE<"max_a.d", int_mips_max_a_d, MSA128DOpnd>; + +class MAX_S_B_DESC : MSA_3R_DESC_BASE<"max_s.b", MipsVSMax, MSA128BOpnd>; +class MAX_S_H_DESC : MSA_3R_DESC_BASE<"max_s.h", MipsVSMax, MSA128HOpnd>; +class MAX_S_W_DESC : MSA_3R_DESC_BASE<"max_s.w", MipsVSMax, MSA128WOpnd>; +class MAX_S_D_DESC : MSA_3R_DESC_BASE<"max_s.d", MipsVSMax, MSA128DOpnd>; + +class MAX_U_B_DESC : MSA_3R_DESC_BASE<"max_u.b", MipsVUMax, MSA128BOpnd>; +class MAX_U_H_DESC : MSA_3R_DESC_BASE<"max_u.h", MipsVUMax, MSA128HOpnd>; +class MAX_U_W_DESC : MSA_3R_DESC_BASE<"max_u.w", MipsVUMax, MSA128WOpnd>; +class MAX_U_D_DESC : MSA_3R_DESC_BASE<"max_u.d", MipsVUMax, MSA128DOpnd>; + +class MAXI_S_B_DESC : MSA_I5_DESC_BASE<"maxi_s.b", MipsVSMax, vsplati8_simm5, + MSA128BOpnd>; +class MAXI_S_H_DESC : MSA_I5_DESC_BASE<"maxi_s.h", MipsVSMax, vsplati16_simm5, + MSA128HOpnd>; +class MAXI_S_W_DESC : MSA_I5_DESC_BASE<"maxi_s.w", MipsVSMax, vsplati32_simm5, + MSA128WOpnd>; +class MAXI_S_D_DESC : MSA_I5_DESC_BASE<"maxi_s.d", MipsVSMax, vsplati64_simm5, + MSA128DOpnd>; + +class MAXI_U_B_DESC : MSA_I5_DESC_BASE<"maxi_u.b", MipsVUMax, vsplati8_uimm5, + MSA128BOpnd>; +class MAXI_U_H_DESC : MSA_I5_DESC_BASE<"maxi_u.h", MipsVUMax, vsplati16_uimm5, + MSA128HOpnd>; +class MAXI_U_W_DESC : MSA_I5_DESC_BASE<"maxi_u.w", MipsVUMax, vsplati32_uimm5, + MSA128WOpnd>; +class MAXI_U_D_DESC : MSA_I5_DESC_BASE<"maxi_u.d", MipsVUMax, vsplati64_uimm5, + MSA128DOpnd>; + +class MIN_A_B_DESC : MSA_3R_DESC_BASE<"min_a.b", int_mips_min_a_b, MSA128BOpnd>; +class MIN_A_H_DESC : MSA_3R_DESC_BASE<"min_a.h", int_mips_min_a_h, MSA128HOpnd>; +class MIN_A_W_DESC : MSA_3R_DESC_BASE<"min_a.w", int_mips_min_a_w, MSA128WOpnd>; +class MIN_A_D_DESC : MSA_3R_DESC_BASE<"min_a.d", int_mips_min_a_d, MSA128DOpnd>; + +class MIN_S_B_DESC : MSA_3R_DESC_BASE<"min_s.b", MipsVSMin, MSA128BOpnd>; +class MIN_S_H_DESC : MSA_3R_DESC_BASE<"min_s.h", MipsVSMin, MSA128HOpnd>; +class MIN_S_W_DESC : MSA_3R_DESC_BASE<"min_s.w", MipsVSMin, MSA128WOpnd>; +class MIN_S_D_DESC : MSA_3R_DESC_BASE<"min_s.d", MipsVSMin, MSA128DOpnd>; + +class MIN_U_B_DESC : MSA_3R_DESC_BASE<"min_u.b", MipsVUMin, MSA128BOpnd>; +class MIN_U_H_DESC : MSA_3R_DESC_BASE<"min_u.h", MipsVUMin, MSA128HOpnd>; +class MIN_U_W_DESC : MSA_3R_DESC_BASE<"min_u.w", MipsVUMin, MSA128WOpnd>; +class MIN_U_D_DESC : MSA_3R_DESC_BASE<"min_u.d", MipsVUMin, MSA128DOpnd>; + +class MINI_S_B_DESC : MSA_I5_DESC_BASE<"mini_s.b", MipsVSMin, vsplati8_simm5, + MSA128BOpnd>; +class MINI_S_H_DESC : MSA_I5_DESC_BASE<"mini_s.h", MipsVSMin, vsplati16_simm5, + MSA128HOpnd>; +class MINI_S_W_DESC : MSA_I5_DESC_BASE<"mini_s.w", MipsVSMin, vsplati32_simm5, + MSA128WOpnd>; +class MINI_S_D_DESC : MSA_I5_DESC_BASE<"mini_s.d", MipsVSMin, vsplati64_simm5, + MSA128DOpnd>; + +class MINI_U_B_DESC : MSA_I5_DESC_BASE<"mini_u.b", MipsVUMin, vsplati8_uimm5, + MSA128BOpnd>; +class MINI_U_H_DESC : MSA_I5_DESC_BASE<"mini_u.h", MipsVUMin, vsplati16_uimm5, + MSA128HOpnd>; +class MINI_U_W_DESC : MSA_I5_DESC_BASE<"mini_u.w", MipsVUMin, vsplati32_uimm5, + MSA128WOpnd>; +class MINI_U_D_DESC : MSA_I5_DESC_BASE<"mini_u.d", MipsVUMin, vsplati64_uimm5, + MSA128DOpnd>; + +class MOD_S_B_DESC : MSA_3R_DESC_BASE<"mod_s.b", srem, MSA128BOpnd>; +class MOD_S_H_DESC : MSA_3R_DESC_BASE<"mod_s.h", srem, MSA128HOpnd>; +class MOD_S_W_DESC : MSA_3R_DESC_BASE<"mod_s.w", srem, MSA128WOpnd>; +class MOD_S_D_DESC : MSA_3R_DESC_BASE<"mod_s.d", srem, MSA128DOpnd>; + +class MOD_U_B_DESC : MSA_3R_DESC_BASE<"mod_u.b", urem, MSA128BOpnd>; +class MOD_U_H_DESC : MSA_3R_DESC_BASE<"mod_u.h", urem, MSA128HOpnd>; +class MOD_U_W_DESC : MSA_3R_DESC_BASE<"mod_u.w", urem, MSA128WOpnd>; +class MOD_U_D_DESC : MSA_3R_DESC_BASE<"mod_u.d", urem, MSA128DOpnd>; + +class MOVE_V_DESC { + dag OutOperandList = (outs MSA128BOpnd:$wd); + dag InOperandList = (ins MSA128BOpnd:$ws); + string AsmString = "move.v\t$wd, $ws"; + list<dag> Pattern = []; + InstrItinClass Itinerary = NoItinerary; +} + +class MSUB_Q_H_DESC : MSA_3RF_4RF_DESC_BASE<"msub_q.h", int_mips_msub_q_h, + MSA128HOpnd>; +class MSUB_Q_W_DESC : MSA_3RF_4RF_DESC_BASE<"msub_q.w", int_mips_msub_q_w, + MSA128WOpnd>; + +class MSUBR_Q_H_DESC : MSA_3RF_4RF_DESC_BASE<"msubr_q.h", int_mips_msubr_q_h, + MSA128HOpnd>; +class MSUBR_Q_W_DESC : MSA_3RF_4RF_DESC_BASE<"msubr_q.w", int_mips_msubr_q_w, + MSA128WOpnd>; + +class MSUBV_B_DESC : MSA_3R_4R_DESC_BASE<"msubv.b", mulsub, MSA128BOpnd>; +class MSUBV_H_DESC : MSA_3R_4R_DESC_BASE<"msubv.h", mulsub, MSA128HOpnd>; +class MSUBV_W_DESC : MSA_3R_4R_DESC_BASE<"msubv.w", mulsub, MSA128WOpnd>; +class MSUBV_D_DESC : MSA_3R_4R_DESC_BASE<"msubv.d", mulsub, MSA128DOpnd>; + +class MUL_Q_H_DESC : MSA_3RF_DESC_BASE<"mul_q.h", int_mips_mul_q_h, + MSA128HOpnd>; +class MUL_Q_W_DESC : MSA_3RF_DESC_BASE<"mul_q.w", int_mips_mul_q_w, + MSA128WOpnd>; + +class MULR_Q_H_DESC : MSA_3RF_DESC_BASE<"mulr_q.h", int_mips_mulr_q_h, + MSA128HOpnd>; +class MULR_Q_W_DESC : MSA_3RF_DESC_BASE<"mulr_q.w", int_mips_mulr_q_w, + MSA128WOpnd>; + +class MULV_B_DESC : MSA_3R_DESC_BASE<"mulv.b", mul, MSA128BOpnd>; +class MULV_H_DESC : MSA_3R_DESC_BASE<"mulv.h", mul, MSA128HOpnd>; +class MULV_W_DESC : MSA_3R_DESC_BASE<"mulv.w", mul, MSA128WOpnd>; +class MULV_D_DESC : MSA_3R_DESC_BASE<"mulv.d", mul, MSA128DOpnd>; + +class NLOC_B_DESC : MSA_2R_DESC_BASE<"nloc.b", int_mips_nloc_b, MSA128BOpnd>; +class NLOC_H_DESC : MSA_2R_DESC_BASE<"nloc.h", int_mips_nloc_h, MSA128HOpnd>; +class NLOC_W_DESC : MSA_2R_DESC_BASE<"nloc.w", int_mips_nloc_w, MSA128WOpnd>; +class NLOC_D_DESC : MSA_2R_DESC_BASE<"nloc.d", int_mips_nloc_d, MSA128DOpnd>; + +class NLZC_B_DESC : MSA_2R_DESC_BASE<"nlzc.b", ctlz, MSA128BOpnd>; +class NLZC_H_DESC : MSA_2R_DESC_BASE<"nlzc.h", ctlz, MSA128HOpnd>; +class NLZC_W_DESC : MSA_2R_DESC_BASE<"nlzc.w", ctlz, MSA128WOpnd>; +class NLZC_D_DESC : MSA_2R_DESC_BASE<"nlzc.d", ctlz, MSA128DOpnd>; + +class NOR_V_DESC : MSA_VEC_DESC_BASE<"nor.v", MipsVNOR, MSA128BOpnd>; +class NOR_V_H_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<MipsVNOR, MSA128HOpnd>; +class NOR_V_W_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<MipsVNOR, MSA128WOpnd>; +class NOR_V_D_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<MipsVNOR, MSA128DOpnd>; + +class NORI_B_DESC : MSA_I8_DESC_BASE<"nori.b", MipsVNOR, vsplati8_uimm8, + MSA128BOpnd>; + +class OR_V_DESC : MSA_VEC_DESC_BASE<"or.v", or, MSA128BOpnd>; +class OR_V_H_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<or, MSA128HOpnd>; +class OR_V_W_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<or, MSA128WOpnd>; +class OR_V_D_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<or, MSA128DOpnd>; + +class ORI_B_DESC : MSA_I8_DESC_BASE<"ori.b", or, vsplati8_uimm8, MSA128BOpnd>; + +class PCKEV_B_DESC : MSA_3R_DESC_BASE<"pckev.b", MipsPCKEV, MSA128BOpnd>; +class PCKEV_H_DESC : MSA_3R_DESC_BASE<"pckev.h", MipsPCKEV, MSA128HOpnd>; +class PCKEV_W_DESC : MSA_3R_DESC_BASE<"pckev.w", MipsPCKEV, MSA128WOpnd>; +class PCKEV_D_DESC : MSA_3R_DESC_BASE<"pckev.d", MipsPCKEV, MSA128DOpnd>; + +class PCKOD_B_DESC : MSA_3R_DESC_BASE<"pckod.b", MipsPCKOD, MSA128BOpnd>; +class PCKOD_H_DESC : MSA_3R_DESC_BASE<"pckod.h", MipsPCKOD, MSA128HOpnd>; +class PCKOD_W_DESC : MSA_3R_DESC_BASE<"pckod.w", MipsPCKOD, MSA128WOpnd>; +class PCKOD_D_DESC : MSA_3R_DESC_BASE<"pckod.d", MipsPCKOD, MSA128DOpnd>; + +class PCNT_B_DESC : MSA_2R_DESC_BASE<"pcnt.b", ctpop, MSA128BOpnd>; +class PCNT_H_DESC : MSA_2R_DESC_BASE<"pcnt.h", ctpop, MSA128HOpnd>; +class PCNT_W_DESC : MSA_2R_DESC_BASE<"pcnt.w", ctpop, MSA128WOpnd>; +class PCNT_D_DESC : MSA_2R_DESC_BASE<"pcnt.d", ctpop, MSA128DOpnd>; + +class SAT_S_B_DESC : MSA_BIT_X_DESC_BASE<"sat_s.b", int_mips_sat_s_b, uimm3, + immZExt3, MSA128BOpnd>; +class SAT_S_H_DESC : MSA_BIT_X_DESC_BASE<"sat_s.h", int_mips_sat_s_h, uimm4, + immZExt4, MSA128HOpnd>; +class SAT_S_W_DESC : MSA_BIT_X_DESC_BASE<"sat_s.w", int_mips_sat_s_w, uimm5, + immZExt5, MSA128WOpnd>; +class SAT_S_D_DESC : MSA_BIT_X_DESC_BASE<"sat_s.d", int_mips_sat_s_d, uimm6, + immZExt6, MSA128DOpnd>; + +class SAT_U_B_DESC : MSA_BIT_X_DESC_BASE<"sat_u.b", int_mips_sat_u_b, uimm3, + immZExt3, MSA128BOpnd>; +class SAT_U_H_DESC : MSA_BIT_X_DESC_BASE<"sat_u.h", int_mips_sat_u_h, uimm4, + immZExt4, MSA128HOpnd>; +class SAT_U_W_DESC : MSA_BIT_X_DESC_BASE<"sat_u.w", int_mips_sat_u_w, uimm5, + immZExt5, MSA128WOpnd>; +class SAT_U_D_DESC : MSA_BIT_X_DESC_BASE<"sat_u.d", int_mips_sat_u_d, uimm6, + immZExt6, MSA128DOpnd>; + +class SHF_B_DESC : MSA_I8_SHF_DESC_BASE<"shf.b", MSA128BOpnd>; +class SHF_H_DESC : MSA_I8_SHF_DESC_BASE<"shf.h", MSA128HOpnd>; +class SHF_W_DESC : MSA_I8_SHF_DESC_BASE<"shf.w", MSA128WOpnd>; + +class SLD_B_DESC : MSA_3R_SLD_DESC_BASE<"sld.b", int_mips_sld_b, MSA128BOpnd>; +class SLD_H_DESC : MSA_3R_SLD_DESC_BASE<"sld.h", int_mips_sld_h, MSA128HOpnd>; +class SLD_W_DESC : MSA_3R_SLD_DESC_BASE<"sld.w", int_mips_sld_w, MSA128WOpnd>; +class SLD_D_DESC : MSA_3R_SLD_DESC_BASE<"sld.d", int_mips_sld_d, MSA128DOpnd>; + +class SLDI_B_DESC : MSA_ELM_SLD_DESC_BASE<"sldi.b", int_mips_sldi_b, + MSA128BOpnd, MSA128BOpnd, uimm4, + immZExt4>; +class SLDI_H_DESC : MSA_ELM_SLD_DESC_BASE<"sldi.h", int_mips_sldi_h, + MSA128HOpnd, MSA128HOpnd, uimm3, + immZExt3>; +class SLDI_W_DESC : MSA_ELM_SLD_DESC_BASE<"sldi.w", int_mips_sldi_w, + MSA128WOpnd, MSA128WOpnd, uimm2, + immZExt2>; +class SLDI_D_DESC : MSA_ELM_SLD_DESC_BASE<"sldi.d", int_mips_sldi_d, + MSA128DOpnd, MSA128DOpnd, uimm1, + immZExt1>; + +class SLL_B_DESC : MSA_3R_DESC_BASE<"sll.b", shl, MSA128BOpnd>; +class SLL_H_DESC : MSA_3R_DESC_BASE<"sll.h", shl, MSA128HOpnd>; +class SLL_W_DESC : MSA_3R_DESC_BASE<"sll.w", shl, MSA128WOpnd>; +class SLL_D_DESC : MSA_3R_DESC_BASE<"sll.d", shl, MSA128DOpnd>; + +class SLLI_B_DESC : MSA_BIT_SPLAT_DESC_BASE<"slli.b", shl, vsplati8_uimm3, + MSA128BOpnd>; +class SLLI_H_DESC : MSA_BIT_SPLAT_DESC_BASE<"slli.h", shl, vsplati16_uimm4, + MSA128HOpnd>; +class SLLI_W_DESC : MSA_BIT_SPLAT_DESC_BASE<"slli.w", shl, vsplati32_uimm5, + MSA128WOpnd>; +class SLLI_D_DESC : MSA_BIT_SPLAT_DESC_BASE<"slli.d", shl, vsplati64_uimm6, + MSA128DOpnd>; + +class SPLAT_B_DESC : MSA_3R_SPLAT_DESC_BASE<"splat.b", vsplati8_elt, + MSA128BOpnd>; +class SPLAT_H_DESC : MSA_3R_SPLAT_DESC_BASE<"splat.h", vsplati16_elt, + MSA128HOpnd>; +class SPLAT_W_DESC : MSA_3R_SPLAT_DESC_BASE<"splat.w", vsplati32_elt, + MSA128WOpnd>; +class SPLAT_D_DESC : MSA_3R_SPLAT_DESC_BASE<"splat.d", vsplati64_elt, + MSA128DOpnd>; + +class SPLATI_B_DESC : MSA_ELM_SPLAT_DESC_BASE<"splati.b", vsplati8_uimm4, + MSA128BOpnd>; +class SPLATI_H_DESC : MSA_ELM_SPLAT_DESC_BASE<"splati.h", vsplati16_uimm3, + MSA128HOpnd>; +class SPLATI_W_DESC : MSA_ELM_SPLAT_DESC_BASE<"splati.w", vsplati32_uimm2, + MSA128WOpnd>; +class SPLATI_D_DESC : MSA_ELM_SPLAT_DESC_BASE<"splati.d", vsplati64_uimm1, + MSA128DOpnd>; + +class SRA_B_DESC : MSA_3R_DESC_BASE<"sra.b", sra, MSA128BOpnd>; +class SRA_H_DESC : MSA_3R_DESC_BASE<"sra.h", sra, MSA128HOpnd>; +class SRA_W_DESC : MSA_3R_DESC_BASE<"sra.w", sra, MSA128WOpnd>; +class SRA_D_DESC : MSA_3R_DESC_BASE<"sra.d", sra, MSA128DOpnd>; + +class SRAI_B_DESC : MSA_BIT_SPLAT_DESC_BASE<"srai.b", sra, vsplati8_uimm3, + MSA128BOpnd>; +class SRAI_H_DESC : MSA_BIT_SPLAT_DESC_BASE<"srai.h", sra, vsplati16_uimm4, + MSA128HOpnd>; +class SRAI_W_DESC : MSA_BIT_SPLAT_DESC_BASE<"srai.w", sra, vsplati32_uimm5, + MSA128WOpnd>; +class SRAI_D_DESC : MSA_BIT_SPLAT_DESC_BASE<"srai.d", sra, vsplati64_uimm6, + MSA128DOpnd>; + +class SRAR_B_DESC : MSA_3R_DESC_BASE<"srar.b", int_mips_srar_b, MSA128BOpnd>; +class SRAR_H_DESC : MSA_3R_DESC_BASE<"srar.h", int_mips_srar_h, MSA128HOpnd>; +class SRAR_W_DESC : MSA_3R_DESC_BASE<"srar.w", int_mips_srar_w, MSA128WOpnd>; +class SRAR_D_DESC : MSA_3R_DESC_BASE<"srar.d", int_mips_srar_d, MSA128DOpnd>; + +class SRARI_B_DESC : MSA_BIT_X_DESC_BASE<"srari.b", int_mips_srari_b, uimm3, + immZExt3, MSA128BOpnd>; +class SRARI_H_DESC : MSA_BIT_X_DESC_BASE<"srari.h", int_mips_srari_h, uimm4, + immZExt4, MSA128HOpnd>; +class SRARI_W_DESC : MSA_BIT_X_DESC_BASE<"srari.w", int_mips_srari_w, uimm5, + immZExt5, MSA128WOpnd>; +class SRARI_D_DESC : MSA_BIT_X_DESC_BASE<"srari.d", int_mips_srari_d, uimm6, + immZExt6, MSA128DOpnd>; + +class SRL_B_DESC : MSA_3R_DESC_BASE<"srl.b", srl, MSA128BOpnd>; +class SRL_H_DESC : MSA_3R_DESC_BASE<"srl.h", srl, MSA128HOpnd>; +class SRL_W_DESC : MSA_3R_DESC_BASE<"srl.w", srl, MSA128WOpnd>; +class SRL_D_DESC : MSA_3R_DESC_BASE<"srl.d", srl, MSA128DOpnd>; + +class SRLI_B_DESC : MSA_BIT_SPLAT_DESC_BASE<"srli.b", srl, vsplati8_uimm3, + MSA128BOpnd>; +class SRLI_H_DESC : MSA_BIT_SPLAT_DESC_BASE<"srli.h", srl, vsplati16_uimm4, + MSA128HOpnd>; +class SRLI_W_DESC : MSA_BIT_SPLAT_DESC_BASE<"srli.w", srl, vsplati32_uimm5, + MSA128WOpnd>; +class SRLI_D_DESC : MSA_BIT_SPLAT_DESC_BASE<"srli.d", srl, vsplati64_uimm6, + MSA128DOpnd>; + +class SRLR_B_DESC : MSA_3R_DESC_BASE<"srlr.b", int_mips_srlr_b, MSA128BOpnd>; +class SRLR_H_DESC : MSA_3R_DESC_BASE<"srlr.h", int_mips_srlr_h, MSA128HOpnd>; +class SRLR_W_DESC : MSA_3R_DESC_BASE<"srlr.w", int_mips_srlr_w, MSA128WOpnd>; +class SRLR_D_DESC : MSA_3R_DESC_BASE<"srlr.d", int_mips_srlr_d, MSA128DOpnd>; + +class SRLRI_B_DESC : MSA_BIT_X_DESC_BASE<"srlri.b", int_mips_srlri_b, uimm3, + immZExt3, MSA128BOpnd>; +class SRLRI_H_DESC : MSA_BIT_X_DESC_BASE<"srlri.h", int_mips_srlri_h, uimm4, + immZExt4, MSA128HOpnd>; +class SRLRI_W_DESC : MSA_BIT_X_DESC_BASE<"srlri.w", int_mips_srlri_w, uimm5, + immZExt5, MSA128WOpnd>; +class SRLRI_D_DESC : MSA_BIT_X_DESC_BASE<"srlri.d", int_mips_srlri_d, uimm6, + immZExt6, MSA128DOpnd>; + +class ST_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + ValueType TyNode, RegisterOperand ROWD, + Operand MemOpnd = mem_msa, ComplexPattern Addr = addrimm10, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs); + dag InOperandList = (ins ROWD:$wd, MemOpnd:$addr); + string AsmString = !strconcat(instr_asm, "\t$wd, $addr"); + list<dag> Pattern = [(OpNode (TyNode ROWD:$wd), Addr:$addr)]; + InstrItinClass Itinerary = itin; + string DecoderMethod = "DecodeMSA128Mem"; +} + +class ST_B_DESC : ST_DESC_BASE<"st.b", store, v16i8, MSA128BOpnd>; +class ST_H_DESC : ST_DESC_BASE<"st.h", store, v8i16, MSA128HOpnd>; +class ST_W_DESC : ST_DESC_BASE<"st.w", store, v4i32, MSA128WOpnd>; +class ST_D_DESC : ST_DESC_BASE<"st.d", store, v2i64, MSA128DOpnd>; + +class SUBS_S_B_DESC : MSA_3R_DESC_BASE<"subs_s.b", int_mips_subs_s_b, + MSA128BOpnd>; +class SUBS_S_H_DESC : MSA_3R_DESC_BASE<"subs_s.h", int_mips_subs_s_h, + MSA128HOpnd>; +class SUBS_S_W_DESC : MSA_3R_DESC_BASE<"subs_s.w", int_mips_subs_s_w, + MSA128WOpnd>; +class SUBS_S_D_DESC : MSA_3R_DESC_BASE<"subs_s.d", int_mips_subs_s_d, + MSA128DOpnd>; + +class SUBS_U_B_DESC : MSA_3R_DESC_BASE<"subs_u.b", int_mips_subs_u_b, + MSA128BOpnd>; +class SUBS_U_H_DESC : MSA_3R_DESC_BASE<"subs_u.h", int_mips_subs_u_h, + MSA128HOpnd>; +class SUBS_U_W_DESC : MSA_3R_DESC_BASE<"subs_u.w", int_mips_subs_u_w, + MSA128WOpnd>; +class SUBS_U_D_DESC : MSA_3R_DESC_BASE<"subs_u.d", int_mips_subs_u_d, + MSA128DOpnd>; + +class SUBSUS_U_B_DESC : MSA_3R_DESC_BASE<"subsus_u.b", int_mips_subsus_u_b, + MSA128BOpnd>; +class SUBSUS_U_H_DESC : MSA_3R_DESC_BASE<"subsus_u.h", int_mips_subsus_u_h, + MSA128HOpnd>; +class SUBSUS_U_W_DESC : MSA_3R_DESC_BASE<"subsus_u.w", int_mips_subsus_u_w, + MSA128WOpnd>; +class SUBSUS_U_D_DESC : MSA_3R_DESC_BASE<"subsus_u.d", int_mips_subsus_u_d, + MSA128DOpnd>; + +class SUBSUU_S_B_DESC : MSA_3R_DESC_BASE<"subsuu_s.b", int_mips_subsuu_s_b, + MSA128BOpnd>; +class SUBSUU_S_H_DESC : MSA_3R_DESC_BASE<"subsuu_s.h", int_mips_subsuu_s_h, + MSA128HOpnd>; +class SUBSUU_S_W_DESC : MSA_3R_DESC_BASE<"subsuu_s.w", int_mips_subsuu_s_w, + MSA128WOpnd>; +class SUBSUU_S_D_DESC : MSA_3R_DESC_BASE<"subsuu_s.d", int_mips_subsuu_s_d, + MSA128DOpnd>; + +class SUBV_B_DESC : MSA_3R_DESC_BASE<"subv.b", sub, MSA128BOpnd>; +class SUBV_H_DESC : MSA_3R_DESC_BASE<"subv.h", sub, MSA128HOpnd>; +class SUBV_W_DESC : MSA_3R_DESC_BASE<"subv.w", sub, MSA128WOpnd>; +class SUBV_D_DESC : MSA_3R_DESC_BASE<"subv.d", sub, MSA128DOpnd>; + +class SUBVI_B_DESC : MSA_I5_DESC_BASE<"subvi.b", sub, vsplati8_uimm5, + MSA128BOpnd>; +class SUBVI_H_DESC : MSA_I5_DESC_BASE<"subvi.h", sub, vsplati16_uimm5, + MSA128HOpnd>; +class SUBVI_W_DESC : MSA_I5_DESC_BASE<"subvi.w", sub, vsplati32_uimm5, + MSA128WOpnd>; +class SUBVI_D_DESC : MSA_I5_DESC_BASE<"subvi.d", sub, vsplati64_uimm5, + MSA128DOpnd>; + +class VSHF_B_DESC : MSA_3R_VSHF_DESC_BASE<"vshf.b", MSA128BOpnd>; +class VSHF_H_DESC : MSA_3R_VSHF_DESC_BASE<"vshf.h", MSA128HOpnd>; +class VSHF_W_DESC : MSA_3R_VSHF_DESC_BASE<"vshf.w", MSA128WOpnd>; +class VSHF_D_DESC : MSA_3R_VSHF_DESC_BASE<"vshf.d", MSA128DOpnd>; + +class XOR_V_DESC : MSA_VEC_DESC_BASE<"xor.v", xor, MSA128BOpnd>; +class XOR_V_H_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<xor, MSA128HOpnd>; +class XOR_V_W_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<xor, MSA128WOpnd>; +class XOR_V_D_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<xor, MSA128DOpnd>; + +class XORI_B_DESC : MSA_I8_DESC_BASE<"xori.b", xor, vsplati8_uimm8, + MSA128BOpnd>; + +// Instruction defs. +def ADD_A_B : ADD_A_B_ENC, ADD_A_B_DESC; +def ADD_A_H : ADD_A_H_ENC, ADD_A_H_DESC; +def ADD_A_W : ADD_A_W_ENC, ADD_A_W_DESC; +def ADD_A_D : ADD_A_D_ENC, ADD_A_D_DESC; + +def ADDS_A_B : ADDS_A_B_ENC, ADDS_A_B_DESC; +def ADDS_A_H : ADDS_A_H_ENC, ADDS_A_H_DESC; +def ADDS_A_W : ADDS_A_W_ENC, ADDS_A_W_DESC; +def ADDS_A_D : ADDS_A_D_ENC, ADDS_A_D_DESC; + +def ADDS_S_B : ADDS_S_B_ENC, ADDS_S_B_DESC; +def ADDS_S_H : ADDS_S_H_ENC, ADDS_S_H_DESC; +def ADDS_S_W : ADDS_S_W_ENC, ADDS_S_W_DESC; +def ADDS_S_D : ADDS_S_D_ENC, ADDS_S_D_DESC; + +def ADDS_U_B : ADDS_U_B_ENC, ADDS_U_B_DESC; +def ADDS_U_H : ADDS_U_H_ENC, ADDS_U_H_DESC; +def ADDS_U_W : ADDS_U_W_ENC, ADDS_U_W_DESC; +def ADDS_U_D : ADDS_U_D_ENC, ADDS_U_D_DESC; + +def ADDV_B : ADDV_B_ENC, ADDV_B_DESC; +def ADDV_H : ADDV_H_ENC, ADDV_H_DESC; +def ADDV_W : ADDV_W_ENC, ADDV_W_DESC; +def ADDV_D : ADDV_D_ENC, ADDV_D_DESC; + +def ADDVI_B : ADDVI_B_ENC, ADDVI_B_DESC; +def ADDVI_H : ADDVI_H_ENC, ADDVI_H_DESC; +def ADDVI_W : ADDVI_W_ENC, ADDVI_W_DESC; +def ADDVI_D : ADDVI_D_ENC, ADDVI_D_DESC; + +def AND_V : AND_V_ENC, AND_V_DESC; +def AND_V_H_PSEUDO : AND_V_H_PSEUDO_DESC, + PseudoInstExpansion<(AND_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; +def AND_V_W_PSEUDO : AND_V_W_PSEUDO_DESC, + PseudoInstExpansion<(AND_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; +def AND_V_D_PSEUDO : AND_V_D_PSEUDO_DESC, + PseudoInstExpansion<(AND_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; + +def ANDI_B : ANDI_B_ENC, ANDI_B_DESC; + +def ASUB_S_B : ASUB_S_B_ENC, ASUB_S_B_DESC; +def ASUB_S_H : ASUB_S_H_ENC, ASUB_S_H_DESC; +def ASUB_S_W : ASUB_S_W_ENC, ASUB_S_W_DESC; +def ASUB_S_D : ASUB_S_D_ENC, ASUB_S_D_DESC; + +def ASUB_U_B : ASUB_U_B_ENC, ASUB_U_B_DESC; +def ASUB_U_H : ASUB_U_H_ENC, ASUB_U_H_DESC; +def ASUB_U_W : ASUB_U_W_ENC, ASUB_U_W_DESC; +def ASUB_U_D : ASUB_U_D_ENC, ASUB_U_D_DESC; + +def AVE_S_B : AVE_S_B_ENC, AVE_S_B_DESC; +def AVE_S_H : AVE_S_H_ENC, AVE_S_H_DESC; +def AVE_S_W : AVE_S_W_ENC, AVE_S_W_DESC; +def AVE_S_D : AVE_S_D_ENC, AVE_S_D_DESC; + +def AVE_U_B : AVE_U_B_ENC, AVE_U_B_DESC; +def AVE_U_H : AVE_U_H_ENC, AVE_U_H_DESC; +def AVE_U_W : AVE_U_W_ENC, AVE_U_W_DESC; +def AVE_U_D : AVE_U_D_ENC, AVE_U_D_DESC; + +def AVER_S_B : AVER_S_B_ENC, AVER_S_B_DESC; +def AVER_S_H : AVER_S_H_ENC, AVER_S_H_DESC; +def AVER_S_W : AVER_S_W_ENC, AVER_S_W_DESC; +def AVER_S_D : AVER_S_D_ENC, AVER_S_D_DESC; + +def AVER_U_B : AVER_U_B_ENC, AVER_U_B_DESC; +def AVER_U_H : AVER_U_H_ENC, AVER_U_H_DESC; +def AVER_U_W : AVER_U_W_ENC, AVER_U_W_DESC; +def AVER_U_D : AVER_U_D_ENC, AVER_U_D_DESC; + +def BCLR_B : BCLR_B_ENC, BCLR_B_DESC; +def BCLR_H : BCLR_H_ENC, BCLR_H_DESC; +def BCLR_W : BCLR_W_ENC, BCLR_W_DESC; +def BCLR_D : BCLR_D_ENC, BCLR_D_DESC; + +def BCLRI_B : BCLRI_B_ENC, BCLRI_B_DESC; +def BCLRI_H : BCLRI_H_ENC, BCLRI_H_DESC; +def BCLRI_W : BCLRI_W_ENC, BCLRI_W_DESC; +def BCLRI_D : BCLRI_D_ENC, BCLRI_D_DESC; + +def BINSL_B : BINSL_B_ENC, BINSL_B_DESC; +def BINSL_H : BINSL_H_ENC, BINSL_H_DESC; +def BINSL_W : BINSL_W_ENC, BINSL_W_DESC; +def BINSL_D : BINSL_D_ENC, BINSL_D_DESC; + +def BINSLI_B : BINSLI_B_ENC, BINSLI_B_DESC; +def BINSLI_H : BINSLI_H_ENC, BINSLI_H_DESC; +def BINSLI_W : BINSLI_W_ENC, BINSLI_W_DESC; +def BINSLI_D : BINSLI_D_ENC, BINSLI_D_DESC; + +def BINSR_B : BINSR_B_ENC, BINSR_B_DESC; +def BINSR_H : BINSR_H_ENC, BINSR_H_DESC; +def BINSR_W : BINSR_W_ENC, BINSR_W_DESC; +def BINSR_D : BINSR_D_ENC, BINSR_D_DESC; + +def BINSRI_B : BINSRI_B_ENC, BINSRI_B_DESC; +def BINSRI_H : BINSRI_H_ENC, BINSRI_H_DESC; +def BINSRI_W : BINSRI_W_ENC, BINSRI_W_DESC; +def BINSRI_D : BINSRI_D_ENC, BINSRI_D_DESC; + +def BMNZ_V : BMNZ_V_ENC, BMNZ_V_DESC; + +def BMNZI_B : BMNZI_B_ENC, BMNZI_B_DESC; + +def BMZ_V : BMZ_V_ENC, BMZ_V_DESC; + +def BMZI_B : BMZI_B_ENC, BMZI_B_DESC; + +def BNEG_B : BNEG_B_ENC, BNEG_B_DESC; +def BNEG_H : BNEG_H_ENC, BNEG_H_DESC; +def BNEG_W : BNEG_W_ENC, BNEG_W_DESC; +def BNEG_D : BNEG_D_ENC, BNEG_D_DESC; + +def BNEGI_B : BNEGI_B_ENC, BNEGI_B_DESC; +def BNEGI_H : BNEGI_H_ENC, BNEGI_H_DESC; +def BNEGI_W : BNEGI_W_ENC, BNEGI_W_DESC; +def BNEGI_D : BNEGI_D_ENC, BNEGI_D_DESC; + +def BNZ_B : BNZ_B_ENC, BNZ_B_DESC; +def BNZ_H : BNZ_H_ENC, BNZ_H_DESC; +def BNZ_W : BNZ_W_ENC, BNZ_W_DESC; +def BNZ_D : BNZ_D_ENC, BNZ_D_DESC; + +def BNZ_V : BNZ_V_ENC, BNZ_V_DESC; + +def BSEL_V : BSEL_V_ENC, BSEL_V_DESC; + +class MSA_BSEL_PSEUDO_BASE<RegisterOperand RO, ValueType Ty> : + 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"; +} + +def BSEL_H_PSEUDO : MSA_BSEL_PSEUDO_BASE<MSA128HOpnd, v8i16>; +def BSEL_W_PSEUDO : MSA_BSEL_PSEUDO_BASE<MSA128WOpnd, v4i32>; +def BSEL_D_PSEUDO : MSA_BSEL_PSEUDO_BASE<MSA128DOpnd, v2i64>; +def BSEL_FW_PSEUDO : MSA_BSEL_PSEUDO_BASE<MSA128WOpnd, v4f32>; +def BSEL_FD_PSEUDO : MSA_BSEL_PSEUDO_BASE<MSA128DOpnd, v2f64>; + +def BSELI_B : BSELI_B_ENC, BSELI_B_DESC; + +def BSET_B : BSET_B_ENC, BSET_B_DESC; +def BSET_H : BSET_H_ENC, BSET_H_DESC; +def BSET_W : BSET_W_ENC, BSET_W_DESC; +def BSET_D : BSET_D_ENC, BSET_D_DESC; + +def BSETI_B : BSETI_B_ENC, BSETI_B_DESC; +def BSETI_H : BSETI_H_ENC, BSETI_H_DESC; +def BSETI_W : BSETI_W_ENC, BSETI_W_DESC; +def BSETI_D : BSETI_D_ENC, BSETI_D_DESC; + +def BZ_B : BZ_B_ENC, BZ_B_DESC; +def BZ_H : BZ_H_ENC, BZ_H_DESC; +def BZ_W : BZ_W_ENC, BZ_W_DESC; +def BZ_D : BZ_D_ENC, BZ_D_DESC; + +def BZ_V : BZ_V_ENC, BZ_V_DESC; + +def CEQ_B : CEQ_B_ENC, CEQ_B_DESC; +def CEQ_H : CEQ_H_ENC, CEQ_H_DESC; +def CEQ_W : CEQ_W_ENC, CEQ_W_DESC; +def CEQ_D : CEQ_D_ENC, CEQ_D_DESC; + +def CEQI_B : CEQI_B_ENC, CEQI_B_DESC; +def CEQI_H : CEQI_H_ENC, CEQI_H_DESC; +def CEQI_W : CEQI_W_ENC, CEQI_W_DESC; +def CEQI_D : CEQI_D_ENC, CEQI_D_DESC; + +def CFCMSA : CFCMSA_ENC, CFCMSA_DESC; + +def CLE_S_B : CLE_S_B_ENC, CLE_S_B_DESC; +def CLE_S_H : CLE_S_H_ENC, CLE_S_H_DESC; +def CLE_S_W : CLE_S_W_ENC, CLE_S_W_DESC; +def CLE_S_D : CLE_S_D_ENC, CLE_S_D_DESC; + +def CLE_U_B : CLE_U_B_ENC, CLE_U_B_DESC; +def CLE_U_H : CLE_U_H_ENC, CLE_U_H_DESC; +def CLE_U_W : CLE_U_W_ENC, CLE_U_W_DESC; +def CLE_U_D : CLE_U_D_ENC, CLE_U_D_DESC; + +def CLEI_S_B : CLEI_S_B_ENC, CLEI_S_B_DESC; +def CLEI_S_H : CLEI_S_H_ENC, CLEI_S_H_DESC; +def CLEI_S_W : CLEI_S_W_ENC, CLEI_S_W_DESC; +def CLEI_S_D : CLEI_S_D_ENC, CLEI_S_D_DESC; + +def CLEI_U_B : CLEI_U_B_ENC, CLEI_U_B_DESC; +def CLEI_U_H : CLEI_U_H_ENC, CLEI_U_H_DESC; +def CLEI_U_W : CLEI_U_W_ENC, CLEI_U_W_DESC; +def CLEI_U_D : CLEI_U_D_ENC, CLEI_U_D_DESC; + +def CLT_S_B : CLT_S_B_ENC, CLT_S_B_DESC; +def CLT_S_H : CLT_S_H_ENC, CLT_S_H_DESC; +def CLT_S_W : CLT_S_W_ENC, CLT_S_W_DESC; +def CLT_S_D : CLT_S_D_ENC, CLT_S_D_DESC; + +def CLT_U_B : CLT_U_B_ENC, CLT_U_B_DESC; +def CLT_U_H : CLT_U_H_ENC, CLT_U_H_DESC; +def CLT_U_W : CLT_U_W_ENC, CLT_U_W_DESC; +def CLT_U_D : CLT_U_D_ENC, CLT_U_D_DESC; + +def CLTI_S_B : CLTI_S_B_ENC, CLTI_S_B_DESC; +def CLTI_S_H : CLTI_S_H_ENC, CLTI_S_H_DESC; +def CLTI_S_W : CLTI_S_W_ENC, CLTI_S_W_DESC; +def CLTI_S_D : CLTI_S_D_ENC, CLTI_S_D_DESC; + +def CLTI_U_B : CLTI_U_B_ENC, CLTI_U_B_DESC; +def CLTI_U_H : CLTI_U_H_ENC, CLTI_U_H_DESC; +def CLTI_U_W : CLTI_U_W_ENC, CLTI_U_W_DESC; +def CLTI_U_D : CLTI_U_D_ENC, CLTI_U_D_DESC; + +def COPY_S_B : COPY_S_B_ENC, COPY_S_B_DESC; +def COPY_S_H : COPY_S_H_ENC, COPY_S_H_DESC; +def COPY_S_W : COPY_S_W_ENC, COPY_S_W_DESC; +def COPY_S_D : COPY_S_D_ENC, COPY_S_D_DESC, ASE_MSA64; + +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, ASE_MSA64; + +def COPY_FW_PSEUDO : COPY_FW_PSEUDO_DESC; +def COPY_FD_PSEUDO : COPY_FD_PSEUDO_DESC; + +def CTCMSA : CTCMSA_ENC, CTCMSA_DESC; + +def DIV_S_B : DIV_S_B_ENC, DIV_S_B_DESC; +def DIV_S_H : DIV_S_H_ENC, DIV_S_H_DESC; +def DIV_S_W : DIV_S_W_ENC, DIV_S_W_DESC; +def DIV_S_D : DIV_S_D_ENC, DIV_S_D_DESC; + +def DIV_U_B : DIV_U_B_ENC, DIV_U_B_DESC; +def DIV_U_H : DIV_U_H_ENC, DIV_U_H_DESC; +def DIV_U_W : DIV_U_W_ENC, DIV_U_W_DESC; +def DIV_U_D : DIV_U_D_ENC, DIV_U_D_DESC; + +def DOTP_S_H : DOTP_S_H_ENC, DOTP_S_H_DESC; +def DOTP_S_W : DOTP_S_W_ENC, DOTP_S_W_DESC; +def DOTP_S_D : DOTP_S_D_ENC, DOTP_S_D_DESC; + +def DOTP_U_H : DOTP_U_H_ENC, DOTP_U_H_DESC; +def DOTP_U_W : DOTP_U_W_ENC, DOTP_U_W_DESC; +def DOTP_U_D : DOTP_U_D_ENC, DOTP_U_D_DESC; + +def DPADD_S_H : DPADD_S_H_ENC, DPADD_S_H_DESC; +def DPADD_S_W : DPADD_S_W_ENC, DPADD_S_W_DESC; +def DPADD_S_D : DPADD_S_D_ENC, DPADD_S_D_DESC; + +def DPADD_U_H : DPADD_U_H_ENC, DPADD_U_H_DESC; +def DPADD_U_W : DPADD_U_W_ENC, DPADD_U_W_DESC; +def DPADD_U_D : DPADD_U_D_ENC, DPADD_U_D_DESC; + +def DPSUB_S_H : DPSUB_S_H_ENC, DPSUB_S_H_DESC; +def DPSUB_S_W : DPSUB_S_W_ENC, DPSUB_S_W_DESC; +def DPSUB_S_D : DPSUB_S_D_ENC, DPSUB_S_D_DESC; + +def DPSUB_U_H : DPSUB_U_H_ENC, DPSUB_U_H_DESC; +def DPSUB_U_W : DPSUB_U_W_ENC, DPSUB_U_W_DESC; +def DPSUB_U_D : DPSUB_U_D_ENC, DPSUB_U_D_DESC; + +def FADD_W : FADD_W_ENC, FADD_W_DESC; +def FADD_D : FADD_D_ENC, FADD_D_DESC; + +def FCAF_W : FCAF_W_ENC, FCAF_W_DESC; +def FCAF_D : FCAF_D_ENC, FCAF_D_DESC; + +def FCEQ_W : FCEQ_W_ENC, FCEQ_W_DESC; +def FCEQ_D : FCEQ_D_ENC, FCEQ_D_DESC; + +def FCLE_W : FCLE_W_ENC, FCLE_W_DESC; +def FCLE_D : FCLE_D_ENC, FCLE_D_DESC; + +def FCLT_W : FCLT_W_ENC, FCLT_W_DESC; +def FCLT_D : FCLT_D_ENC, FCLT_D_DESC; + +def FCLASS_W : FCLASS_W_ENC, FCLASS_W_DESC; +def FCLASS_D : FCLASS_D_ENC, FCLASS_D_DESC; + +def FCNE_W : FCNE_W_ENC, FCNE_W_DESC; +def FCNE_D : FCNE_D_ENC, FCNE_D_DESC; + +def FCOR_W : FCOR_W_ENC, FCOR_W_DESC; +def FCOR_D : FCOR_D_ENC, FCOR_D_DESC; + +def FCUEQ_W : FCUEQ_W_ENC, FCUEQ_W_DESC; +def FCUEQ_D : FCUEQ_D_ENC, FCUEQ_D_DESC; + +def FCULE_W : FCULE_W_ENC, FCULE_W_DESC; +def FCULE_D : FCULE_D_ENC, FCULE_D_DESC; + +def FCULT_W : FCULT_W_ENC, FCULT_W_DESC; +def FCULT_D : FCULT_D_ENC, FCULT_D_DESC; + +def FCUN_W : FCUN_W_ENC, FCUN_W_DESC; +def FCUN_D : FCUN_D_ENC, FCUN_D_DESC; + +def FCUNE_W : FCUNE_W_ENC, FCUNE_W_DESC; +def FCUNE_D : FCUNE_D_ENC, FCUNE_D_DESC; + +def FDIV_W : FDIV_W_ENC, FDIV_W_DESC; +def FDIV_D : FDIV_D_ENC, FDIV_D_DESC; + +def FEXDO_H : FEXDO_H_ENC, FEXDO_H_DESC; +def FEXDO_W : FEXDO_W_ENC, FEXDO_W_DESC; + +def FEXP2_W : FEXP2_W_ENC, FEXP2_W_DESC; +def FEXP2_D : FEXP2_D_ENC, FEXP2_D_DESC; +def FEXP2_W_1_PSEUDO : FEXP2_W_1_PSEUDO_DESC; +def FEXP2_D_1_PSEUDO : FEXP2_D_1_PSEUDO_DESC; + +def FEXUPL_W : FEXUPL_W_ENC, FEXUPL_W_DESC; +def FEXUPL_D : FEXUPL_D_ENC, FEXUPL_D_DESC; + +def FEXUPR_W : FEXUPR_W_ENC, FEXUPR_W_DESC; +def FEXUPR_D : FEXUPR_D_ENC, FEXUPR_D_DESC; + +def FFINT_S_W : FFINT_S_W_ENC, FFINT_S_W_DESC; +def FFINT_S_D : FFINT_S_D_ENC, FFINT_S_D_DESC; + +def FFINT_U_W : FFINT_U_W_ENC, FFINT_U_W_DESC; +def FFINT_U_D : FFINT_U_D_ENC, FFINT_U_D_DESC; + +def FFQL_W : FFQL_W_ENC, FFQL_W_DESC; +def FFQL_D : FFQL_D_ENC, FFQL_D_DESC; + +def FFQR_W : FFQR_W_ENC, FFQR_W_DESC; +def FFQR_D : FFQR_D_ENC, FFQR_D_DESC; + +def FILL_B : FILL_B_ENC, FILL_B_DESC; +def FILL_H : FILL_H_ENC, FILL_H_DESC; +def FILL_W : FILL_W_ENC, FILL_W_DESC; +def FILL_D : FILL_D_ENC, FILL_D_DESC, ASE_MSA64; +def FILL_FW_PSEUDO : FILL_FW_PSEUDO_DESC; +def FILL_FD_PSEUDO : FILL_FD_PSEUDO_DESC; + +def FLOG2_W : FLOG2_W_ENC, FLOG2_W_DESC; +def FLOG2_D : FLOG2_D_ENC, FLOG2_D_DESC; + +def FMADD_W : FMADD_W_ENC, FMADD_W_DESC; +def FMADD_D : FMADD_D_ENC, FMADD_D_DESC; + +def FMAX_W : FMAX_W_ENC, FMAX_W_DESC; +def FMAX_D : FMAX_D_ENC, FMAX_D_DESC; + +def FMAX_A_W : FMAX_A_W_ENC, FMAX_A_W_DESC; +def FMAX_A_D : FMAX_A_D_ENC, FMAX_A_D_DESC; + +def FMIN_W : FMIN_W_ENC, FMIN_W_DESC; +def FMIN_D : FMIN_D_ENC, FMIN_D_DESC; + +def FMIN_A_W : FMIN_A_W_ENC, FMIN_A_W_DESC; +def FMIN_A_D : FMIN_A_D_ENC, FMIN_A_D_DESC; + +def FMSUB_W : FMSUB_W_ENC, FMSUB_W_DESC; +def FMSUB_D : FMSUB_D_ENC, FMSUB_D_DESC; + +def FMUL_W : FMUL_W_ENC, FMUL_W_DESC; +def FMUL_D : FMUL_D_ENC, FMUL_D_DESC; + +def FRINT_W : FRINT_W_ENC, FRINT_W_DESC; +def FRINT_D : FRINT_D_ENC, FRINT_D_DESC; + +def FRCP_W : FRCP_W_ENC, FRCP_W_DESC; +def FRCP_D : FRCP_D_ENC, FRCP_D_DESC; + +def FRSQRT_W : FRSQRT_W_ENC, FRSQRT_W_DESC; +def FRSQRT_D : FRSQRT_D_ENC, FRSQRT_D_DESC; + +def FSAF_W : FSAF_W_ENC, FSAF_W_DESC; +def FSAF_D : FSAF_D_ENC, FSAF_D_DESC; + +def FSEQ_W : FSEQ_W_ENC, FSEQ_W_DESC; +def FSEQ_D : FSEQ_D_ENC, FSEQ_D_DESC; + +def FSLE_W : FSLE_W_ENC, FSLE_W_DESC; +def FSLE_D : FSLE_D_ENC, FSLE_D_DESC; + +def FSLT_W : FSLT_W_ENC, FSLT_W_DESC; +def FSLT_D : FSLT_D_ENC, FSLT_D_DESC; + +def FSNE_W : FSNE_W_ENC, FSNE_W_DESC; +def FSNE_D : FSNE_D_ENC, FSNE_D_DESC; + +def FSOR_W : FSOR_W_ENC, FSOR_W_DESC; +def FSOR_D : FSOR_D_ENC, FSOR_D_DESC; + +def FSQRT_W : FSQRT_W_ENC, FSQRT_W_DESC; +def FSQRT_D : FSQRT_D_ENC, FSQRT_D_DESC; + +def FSUB_W : FSUB_W_ENC, FSUB_W_DESC; +def FSUB_D : FSUB_D_ENC, FSUB_D_DESC; + +def FSUEQ_W : FSUEQ_W_ENC, FSUEQ_W_DESC; +def FSUEQ_D : FSUEQ_D_ENC, FSUEQ_D_DESC; + +def FSULE_W : FSULE_W_ENC, FSULE_W_DESC; +def FSULE_D : FSULE_D_ENC, FSULE_D_DESC; + +def FSULT_W : FSULT_W_ENC, FSULT_W_DESC; +def FSULT_D : FSULT_D_ENC, FSULT_D_DESC; + +def FSUN_W : FSUN_W_ENC, FSUN_W_DESC; +def FSUN_D : FSUN_D_ENC, FSUN_D_DESC; + +def FSUNE_W : FSUNE_W_ENC, FSUNE_W_DESC; +def FSUNE_D : FSUNE_D_ENC, FSUNE_D_DESC; + +def FTINT_S_W : FTINT_S_W_ENC, FTINT_S_W_DESC; +def FTINT_S_D : FTINT_S_D_ENC, FTINT_S_D_DESC; + +def FTINT_U_W : FTINT_U_W_ENC, FTINT_U_W_DESC; +def FTINT_U_D : FTINT_U_D_ENC, FTINT_U_D_DESC; + +def FTQ_H : FTQ_H_ENC, FTQ_H_DESC; +def FTQ_W : FTQ_W_ENC, FTQ_W_DESC; + +def FTRUNC_S_W : FTRUNC_S_W_ENC, FTRUNC_S_W_DESC; +def FTRUNC_S_D : FTRUNC_S_D_ENC, FTRUNC_S_D_DESC; + +def FTRUNC_U_W : FTRUNC_U_W_ENC, FTRUNC_U_W_DESC; +def FTRUNC_U_D : FTRUNC_U_D_ENC, FTRUNC_U_D_DESC; + +def HADD_S_H : HADD_S_H_ENC, HADD_S_H_DESC; +def HADD_S_W : HADD_S_W_ENC, HADD_S_W_DESC; +def HADD_S_D : HADD_S_D_ENC, HADD_S_D_DESC; + +def HADD_U_H : HADD_U_H_ENC, HADD_U_H_DESC; +def HADD_U_W : HADD_U_W_ENC, HADD_U_W_DESC; +def HADD_U_D : HADD_U_D_ENC, HADD_U_D_DESC; + +def HSUB_S_H : HSUB_S_H_ENC, HSUB_S_H_DESC; +def HSUB_S_W : HSUB_S_W_ENC, HSUB_S_W_DESC; +def HSUB_S_D : HSUB_S_D_ENC, HSUB_S_D_DESC; + +def HSUB_U_H : HSUB_U_H_ENC, HSUB_U_H_DESC; +def HSUB_U_W : HSUB_U_W_ENC, HSUB_U_W_DESC; +def HSUB_U_D : HSUB_U_D_ENC, HSUB_U_D_DESC; + +def ILVEV_B : ILVEV_B_ENC, ILVEV_B_DESC; +def ILVEV_H : ILVEV_H_ENC, ILVEV_H_DESC; +def ILVEV_W : ILVEV_W_ENC, ILVEV_W_DESC; +def ILVEV_D : ILVEV_D_ENC, ILVEV_D_DESC; + +def ILVL_B : ILVL_B_ENC, ILVL_B_DESC; +def ILVL_H : ILVL_H_ENC, ILVL_H_DESC; +def ILVL_W : ILVL_W_ENC, ILVL_W_DESC; +def ILVL_D : ILVL_D_ENC, ILVL_D_DESC; + +def ILVOD_B : ILVOD_B_ENC, ILVOD_B_DESC; +def ILVOD_H : ILVOD_H_ENC, ILVOD_H_DESC; +def ILVOD_W : ILVOD_W_ENC, ILVOD_W_DESC; +def ILVOD_D : ILVOD_D_ENC, ILVOD_D_DESC; + +def ILVR_B : ILVR_B_ENC, ILVR_B_DESC; +def ILVR_H : ILVR_H_ENC, ILVR_H_DESC; +def ILVR_W : ILVR_W_ENC, ILVR_W_DESC; +def ILVR_D : ILVR_D_ENC, ILVR_D_DESC; + +def INSERT_B : INSERT_B_ENC, INSERT_B_DESC; +def INSERT_H : INSERT_H_ENC, INSERT_H_DESC; +def INSERT_W : INSERT_W_ENC, INSERT_W_DESC; +def INSERT_D : INSERT_D_ENC, INSERT_D_DESC, ASE_MSA64; + +// INSERT_FW_PSEUDO defined after INSVE_W +// INSERT_FD_PSEUDO defined after INSVE_D + +// There is a fourth operand that is not present in the encoding. Use a +// custom decoder to get a chance to add it. +let DecoderMethod = "DecodeINSVE_DF" in { + def INSVE_B : INSVE_B_ENC, INSVE_B_DESC; + def INSVE_H : INSVE_H_ENC, INSVE_H_DESC; + def INSVE_W : INSVE_W_ENC, INSVE_W_DESC; + def INSVE_D : INSVE_D_ENC, INSVE_D_DESC; +} + +def INSERT_FW_PSEUDO : INSERT_FW_PSEUDO_DESC; +def INSERT_FD_PSEUDO : INSERT_FD_PSEUDO_DESC; + +def INSERT_B_VIDX_PSEUDO : INSERT_B_VIDX_PSEUDO_DESC; +def INSERT_H_VIDX_PSEUDO : INSERT_H_VIDX_PSEUDO_DESC; +def INSERT_W_VIDX_PSEUDO : INSERT_W_VIDX_PSEUDO_DESC; +def INSERT_D_VIDX_PSEUDO : INSERT_D_VIDX_PSEUDO_DESC; +def INSERT_FW_VIDX_PSEUDO : INSERT_FW_VIDX_PSEUDO_DESC; +def INSERT_FD_VIDX_PSEUDO : INSERT_FD_VIDX_PSEUDO_DESC; + +def INSERT_B_VIDX64_PSEUDO : INSERT_B_VIDX64_PSEUDO_DESC; +def INSERT_H_VIDX64_PSEUDO : INSERT_H_VIDX64_PSEUDO_DESC; +def INSERT_W_VIDX64_PSEUDO : INSERT_W_VIDX64_PSEUDO_DESC; +def INSERT_D_VIDX64_PSEUDO : INSERT_D_VIDX64_PSEUDO_DESC; +def INSERT_FW_VIDX64_PSEUDO : INSERT_FW_VIDX64_PSEUDO_DESC; +def INSERT_FD_VIDX64_PSEUDO : INSERT_FD_VIDX64_PSEUDO_DESC; + +def LD_B: LD_B_ENC, LD_B_DESC; +def LD_H: LD_H_ENC, LD_H_DESC; +def LD_W: LD_W_ENC, LD_W_DESC; +def LD_D: LD_D_ENC, LD_D_DESC; + +def LDI_B : LDI_B_ENC, LDI_B_DESC; +def LDI_H : LDI_H_ENC, LDI_H_DESC; +def LDI_W : LDI_W_ENC, LDI_W_DESC; +def LDI_D : LDI_D_ENC, LDI_D_DESC; + +def LSA : LSA_ENC, LSA_DESC; +def DLSA : DLSA_ENC, DLSA_DESC, ASE_MSA64; + +def MADD_Q_H : MADD_Q_H_ENC, MADD_Q_H_DESC; +def MADD_Q_W : MADD_Q_W_ENC, MADD_Q_W_DESC; + +def MADDR_Q_H : MADDR_Q_H_ENC, MADDR_Q_H_DESC; +def MADDR_Q_W : MADDR_Q_W_ENC, MADDR_Q_W_DESC; + +def MADDV_B : MADDV_B_ENC, MADDV_B_DESC; +def MADDV_H : MADDV_H_ENC, MADDV_H_DESC; +def MADDV_W : MADDV_W_ENC, MADDV_W_DESC; +def MADDV_D : MADDV_D_ENC, MADDV_D_DESC; + +def MAX_A_B : MAX_A_B_ENC, MAX_A_B_DESC; +def MAX_A_H : MAX_A_H_ENC, MAX_A_H_DESC; +def MAX_A_W : MAX_A_W_ENC, MAX_A_W_DESC; +def MAX_A_D : MAX_A_D_ENC, MAX_A_D_DESC; + +def MAX_S_B : MAX_S_B_ENC, MAX_S_B_DESC; +def MAX_S_H : MAX_S_H_ENC, MAX_S_H_DESC; +def MAX_S_W : MAX_S_W_ENC, MAX_S_W_DESC; +def MAX_S_D : MAX_S_D_ENC, MAX_S_D_DESC; + +def MAX_U_B : MAX_U_B_ENC, MAX_U_B_DESC; +def MAX_U_H : MAX_U_H_ENC, MAX_U_H_DESC; +def MAX_U_W : MAX_U_W_ENC, MAX_U_W_DESC; +def MAX_U_D : MAX_U_D_ENC, MAX_U_D_DESC; + +def MAXI_S_B : MAXI_S_B_ENC, MAXI_S_B_DESC; +def MAXI_S_H : MAXI_S_H_ENC, MAXI_S_H_DESC; +def MAXI_S_W : MAXI_S_W_ENC, MAXI_S_W_DESC; +def MAXI_S_D : MAXI_S_D_ENC, MAXI_S_D_DESC; + +def MAXI_U_B : MAXI_U_B_ENC, MAXI_U_B_DESC; +def MAXI_U_H : MAXI_U_H_ENC, MAXI_U_H_DESC; +def MAXI_U_W : MAXI_U_W_ENC, MAXI_U_W_DESC; +def MAXI_U_D : MAXI_U_D_ENC, MAXI_U_D_DESC; + +def MIN_A_B : MIN_A_B_ENC, MIN_A_B_DESC; +def MIN_A_H : MIN_A_H_ENC, MIN_A_H_DESC; +def MIN_A_W : MIN_A_W_ENC, MIN_A_W_DESC; +def MIN_A_D : MIN_A_D_ENC, MIN_A_D_DESC; + +def MIN_S_B : MIN_S_B_ENC, MIN_S_B_DESC; +def MIN_S_H : MIN_S_H_ENC, MIN_S_H_DESC; +def MIN_S_W : MIN_S_W_ENC, MIN_S_W_DESC; +def MIN_S_D : MIN_S_D_ENC, MIN_S_D_DESC; + +def MIN_U_B : MIN_U_B_ENC, MIN_U_B_DESC; +def MIN_U_H : MIN_U_H_ENC, MIN_U_H_DESC; +def MIN_U_W : MIN_U_W_ENC, MIN_U_W_DESC; +def MIN_U_D : MIN_U_D_ENC, MIN_U_D_DESC; + +def MINI_S_B : MINI_S_B_ENC, MINI_S_B_DESC; +def MINI_S_H : MINI_S_H_ENC, MINI_S_H_DESC; +def MINI_S_W : MINI_S_W_ENC, MINI_S_W_DESC; +def MINI_S_D : MINI_S_D_ENC, MINI_S_D_DESC; + +def MINI_U_B : MINI_U_B_ENC, MINI_U_B_DESC; +def MINI_U_H : MINI_U_H_ENC, MINI_U_H_DESC; +def MINI_U_W : MINI_U_W_ENC, MINI_U_W_DESC; +def MINI_U_D : MINI_U_D_ENC, MINI_U_D_DESC; + +def MOD_S_B : MOD_S_B_ENC, MOD_S_B_DESC; +def MOD_S_H : MOD_S_H_ENC, MOD_S_H_DESC; +def MOD_S_W : MOD_S_W_ENC, MOD_S_W_DESC; +def MOD_S_D : MOD_S_D_ENC, MOD_S_D_DESC; + +def MOD_U_B : MOD_U_B_ENC, MOD_U_B_DESC; +def MOD_U_H : MOD_U_H_ENC, MOD_U_H_DESC; +def MOD_U_W : MOD_U_W_ENC, MOD_U_W_DESC; +def MOD_U_D : MOD_U_D_ENC, MOD_U_D_DESC; + +def MOVE_V : MOVE_V_ENC, MOVE_V_DESC; + +def MSUB_Q_H : MSUB_Q_H_ENC, MSUB_Q_H_DESC; +def MSUB_Q_W : MSUB_Q_W_ENC, MSUB_Q_W_DESC; + +def MSUBR_Q_H : MSUBR_Q_H_ENC, MSUBR_Q_H_DESC; +def MSUBR_Q_W : MSUBR_Q_W_ENC, MSUBR_Q_W_DESC; + +def MSUBV_B : MSUBV_B_ENC, MSUBV_B_DESC; +def MSUBV_H : MSUBV_H_ENC, MSUBV_H_DESC; +def MSUBV_W : MSUBV_W_ENC, MSUBV_W_DESC; +def MSUBV_D : MSUBV_D_ENC, MSUBV_D_DESC; + +def MUL_Q_H : MUL_Q_H_ENC, MUL_Q_H_DESC; +def MUL_Q_W : MUL_Q_W_ENC, MUL_Q_W_DESC; + +def MULR_Q_H : MULR_Q_H_ENC, MULR_Q_H_DESC; +def MULR_Q_W : MULR_Q_W_ENC, MULR_Q_W_DESC; + +def MULV_B : MULV_B_ENC, MULV_B_DESC; +def MULV_H : MULV_H_ENC, MULV_H_DESC; +def MULV_W : MULV_W_ENC, MULV_W_DESC; +def MULV_D : MULV_D_ENC, MULV_D_DESC; + +def NLOC_B : NLOC_B_ENC, NLOC_B_DESC; +def NLOC_H : NLOC_H_ENC, NLOC_H_DESC; +def NLOC_W : NLOC_W_ENC, NLOC_W_DESC; +def NLOC_D : NLOC_D_ENC, NLOC_D_DESC; + +def NLZC_B : NLZC_B_ENC, NLZC_B_DESC; +def NLZC_H : NLZC_H_ENC, NLZC_H_DESC; +def NLZC_W : NLZC_W_ENC, NLZC_W_DESC; +def NLZC_D : NLZC_D_ENC, NLZC_D_DESC; + +def NOR_V : NOR_V_ENC, NOR_V_DESC; +def NOR_V_H_PSEUDO : NOR_V_H_PSEUDO_DESC, + PseudoInstExpansion<(NOR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; +def NOR_V_W_PSEUDO : NOR_V_W_PSEUDO_DESC, + PseudoInstExpansion<(NOR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; +def NOR_V_D_PSEUDO : NOR_V_D_PSEUDO_DESC, + PseudoInstExpansion<(NOR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; + +def NORI_B : NORI_B_ENC, NORI_B_DESC; + +def OR_V : OR_V_ENC, OR_V_DESC; +def OR_V_H_PSEUDO : OR_V_H_PSEUDO_DESC, + PseudoInstExpansion<(OR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; +def OR_V_W_PSEUDO : OR_V_W_PSEUDO_DESC, + PseudoInstExpansion<(OR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; +def OR_V_D_PSEUDO : OR_V_D_PSEUDO_DESC, + PseudoInstExpansion<(OR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; + +def ORI_B : ORI_B_ENC, ORI_B_DESC; + +def PCKEV_B : PCKEV_B_ENC, PCKEV_B_DESC; +def PCKEV_H : PCKEV_H_ENC, PCKEV_H_DESC; +def PCKEV_W : PCKEV_W_ENC, PCKEV_W_DESC; +def PCKEV_D : PCKEV_D_ENC, PCKEV_D_DESC; + +def PCKOD_B : PCKOD_B_ENC, PCKOD_B_DESC; +def PCKOD_H : PCKOD_H_ENC, PCKOD_H_DESC; +def PCKOD_W : PCKOD_W_ENC, PCKOD_W_DESC; +def PCKOD_D : PCKOD_D_ENC, PCKOD_D_DESC; + +def PCNT_B : PCNT_B_ENC, PCNT_B_DESC; +def PCNT_H : PCNT_H_ENC, PCNT_H_DESC; +def PCNT_W : PCNT_W_ENC, PCNT_W_DESC; +def PCNT_D : PCNT_D_ENC, PCNT_D_DESC; + +def SAT_S_B : SAT_S_B_ENC, SAT_S_B_DESC; +def SAT_S_H : SAT_S_H_ENC, SAT_S_H_DESC; +def SAT_S_W : SAT_S_W_ENC, SAT_S_W_DESC; +def SAT_S_D : SAT_S_D_ENC, SAT_S_D_DESC; + +def SAT_U_B : SAT_U_B_ENC, SAT_U_B_DESC; +def SAT_U_H : SAT_U_H_ENC, SAT_U_H_DESC; +def SAT_U_W : SAT_U_W_ENC, SAT_U_W_DESC; +def SAT_U_D : SAT_U_D_ENC, SAT_U_D_DESC; + +def SHF_B : SHF_B_ENC, SHF_B_DESC; +def SHF_H : SHF_H_ENC, SHF_H_DESC; +def SHF_W : SHF_W_ENC, SHF_W_DESC; + +def SLD_B : SLD_B_ENC, SLD_B_DESC; +def SLD_H : SLD_H_ENC, SLD_H_DESC; +def SLD_W : SLD_W_ENC, SLD_W_DESC; +def SLD_D : SLD_D_ENC, SLD_D_DESC; + +def SLDI_B : SLDI_B_ENC, SLDI_B_DESC; +def SLDI_H : SLDI_H_ENC, SLDI_H_DESC; +def SLDI_W : SLDI_W_ENC, SLDI_W_DESC; +def SLDI_D : SLDI_D_ENC, SLDI_D_DESC; + +def SLL_B : SLL_B_ENC, SLL_B_DESC; +def SLL_H : SLL_H_ENC, SLL_H_DESC; +def SLL_W : SLL_W_ENC, SLL_W_DESC; +def SLL_D : SLL_D_ENC, SLL_D_DESC; + +def SLLI_B : SLLI_B_ENC, SLLI_B_DESC; +def SLLI_H : SLLI_H_ENC, SLLI_H_DESC; +def SLLI_W : SLLI_W_ENC, SLLI_W_DESC; +def SLLI_D : SLLI_D_ENC, SLLI_D_DESC; + +def SPLAT_B : SPLAT_B_ENC, SPLAT_B_DESC; +def SPLAT_H : SPLAT_H_ENC, SPLAT_H_DESC; +def SPLAT_W : SPLAT_W_ENC, SPLAT_W_DESC; +def SPLAT_D : SPLAT_D_ENC, SPLAT_D_DESC; + +def SPLATI_B : SPLATI_B_ENC, SPLATI_B_DESC; +def SPLATI_H : SPLATI_H_ENC, SPLATI_H_DESC; +def SPLATI_W : SPLATI_W_ENC, SPLATI_W_DESC; +def SPLATI_D : SPLATI_D_ENC, SPLATI_D_DESC; + +def SRA_B : SRA_B_ENC, SRA_B_DESC; +def SRA_H : SRA_H_ENC, SRA_H_DESC; +def SRA_W : SRA_W_ENC, SRA_W_DESC; +def SRA_D : SRA_D_ENC, SRA_D_DESC; + +def SRAI_B : SRAI_B_ENC, SRAI_B_DESC; +def SRAI_H : SRAI_H_ENC, SRAI_H_DESC; +def SRAI_W : SRAI_W_ENC, SRAI_W_DESC; +def SRAI_D : SRAI_D_ENC, SRAI_D_DESC; + +def SRAR_B : SRAR_B_ENC, SRAR_B_DESC; +def SRAR_H : SRAR_H_ENC, SRAR_H_DESC; +def SRAR_W : SRAR_W_ENC, SRAR_W_DESC; +def SRAR_D : SRAR_D_ENC, SRAR_D_DESC; + +def SRARI_B : SRARI_B_ENC, SRARI_B_DESC; +def SRARI_H : SRARI_H_ENC, SRARI_H_DESC; +def SRARI_W : SRARI_W_ENC, SRARI_W_DESC; +def SRARI_D : SRARI_D_ENC, SRARI_D_DESC; + +def SRL_B : SRL_B_ENC, SRL_B_DESC; +def SRL_H : SRL_H_ENC, SRL_H_DESC; +def SRL_W : SRL_W_ENC, SRL_W_DESC; +def SRL_D : SRL_D_ENC, SRL_D_DESC; + +def SRLI_B : SRLI_B_ENC, SRLI_B_DESC; +def SRLI_H : SRLI_H_ENC, SRLI_H_DESC; +def SRLI_W : SRLI_W_ENC, SRLI_W_DESC; +def SRLI_D : SRLI_D_ENC, SRLI_D_DESC; + +def SRLR_B : SRLR_B_ENC, SRLR_B_DESC; +def SRLR_H : SRLR_H_ENC, SRLR_H_DESC; +def SRLR_W : SRLR_W_ENC, SRLR_W_DESC; +def SRLR_D : SRLR_D_ENC, SRLR_D_DESC; + +def SRLRI_B : SRLRI_B_ENC, SRLRI_B_DESC; +def SRLRI_H : SRLRI_H_ENC, SRLRI_H_DESC; +def SRLRI_W : SRLRI_W_ENC, SRLRI_W_DESC; +def SRLRI_D : SRLRI_D_ENC, SRLRI_D_DESC; + +def ST_B: ST_B_ENC, ST_B_DESC; +def ST_H: ST_H_ENC, ST_H_DESC; +def ST_W: ST_W_ENC, ST_W_DESC; +def ST_D: ST_D_ENC, ST_D_DESC; + +def SUBS_S_B : SUBS_S_B_ENC, SUBS_S_B_DESC; +def SUBS_S_H : SUBS_S_H_ENC, SUBS_S_H_DESC; +def SUBS_S_W : SUBS_S_W_ENC, SUBS_S_W_DESC; +def SUBS_S_D : SUBS_S_D_ENC, SUBS_S_D_DESC; + +def SUBS_U_B : SUBS_U_B_ENC, SUBS_U_B_DESC; +def SUBS_U_H : SUBS_U_H_ENC, SUBS_U_H_DESC; +def SUBS_U_W : SUBS_U_W_ENC, SUBS_U_W_DESC; +def SUBS_U_D : SUBS_U_D_ENC, SUBS_U_D_DESC; + +def SUBSUS_U_B : SUBSUS_U_B_ENC, SUBSUS_U_B_DESC; +def SUBSUS_U_H : SUBSUS_U_H_ENC, SUBSUS_U_H_DESC; +def SUBSUS_U_W : SUBSUS_U_W_ENC, SUBSUS_U_W_DESC; +def SUBSUS_U_D : SUBSUS_U_D_ENC, SUBSUS_U_D_DESC; + +def SUBSUU_S_B : SUBSUU_S_B_ENC, SUBSUU_S_B_DESC; +def SUBSUU_S_H : SUBSUU_S_H_ENC, SUBSUU_S_H_DESC; +def SUBSUU_S_W : SUBSUU_S_W_ENC, SUBSUU_S_W_DESC; +def SUBSUU_S_D : SUBSUU_S_D_ENC, SUBSUU_S_D_DESC; + +def SUBV_B : SUBV_B_ENC, SUBV_B_DESC; +def SUBV_H : SUBV_H_ENC, SUBV_H_DESC; +def SUBV_W : SUBV_W_ENC, SUBV_W_DESC; +def SUBV_D : SUBV_D_ENC, SUBV_D_DESC; + +def SUBVI_B : SUBVI_B_ENC, SUBVI_B_DESC; +def SUBVI_H : SUBVI_H_ENC, SUBVI_H_DESC; +def SUBVI_W : SUBVI_W_ENC, SUBVI_W_DESC; +def SUBVI_D : SUBVI_D_ENC, SUBVI_D_DESC; + +def VSHF_B : VSHF_B_ENC, VSHF_B_DESC; +def VSHF_H : VSHF_H_ENC, VSHF_H_DESC; +def VSHF_W : VSHF_W_ENC, VSHF_W_DESC; +def VSHF_D : VSHF_D_ENC, VSHF_D_DESC; + +def XOR_V : XOR_V_ENC, XOR_V_DESC; +def XOR_V_H_PSEUDO : XOR_V_H_PSEUDO_DESC, + PseudoInstExpansion<(XOR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; +def XOR_V_W_PSEUDO : XOR_V_W_PSEUDO_DESC, + PseudoInstExpansion<(XOR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; +def XOR_V_D_PSEUDO : XOR_V_D_PSEUDO_DESC, + PseudoInstExpansion<(XOR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; + +def XORI_B : XORI_B_ENC, XORI_B_DESC; + +// Patterns. +class MSAPat<dag pattern, dag result, list<Predicate> pred = [HasMSA]> : + Pat<pattern, result>, Requires<pred>; + +def : MSAPat<(extractelt (v4i32 MSA128W:$ws), immZExt4:$idx), + (COPY_S_W MSA128W:$ws, immZExt4:$idx)>; + +def : MSAPat<(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> : + 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>, + PseudoInstExpansion<(FMAX_A_W MSA128WOpnd:$wd, MSA128WOpnd:$ws, + MSA128WOpnd:$ws)>; +def FABS_D : MSA_FABS_PSEUDO_DESC_BASE<MSA128DOpnd>, + PseudoInstExpansion<(FMAX_A_D MSA128DOpnd:$wd, MSA128DOpnd:$ws, + MSA128DOpnd:$ws)>; + +class MSABitconvertPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC, list<Predicate> preds = [HasMSA]> : + MSAPat<(DstVT (bitconvert SrcVT:$src)), + (COPY_TO_REGCLASS SrcVT:$src, DstRC), preds>; + +// These are endian-independent because the element size doesnt change +def : MSABitconvertPat<v8i16, v8f16, MSA128H>; +def : MSABitconvertPat<v4i32, v4f32, MSA128W>; +def : MSABitconvertPat<v2i64, v2f64, MSA128D>; +def : MSABitconvertPat<v8f16, v8i16, MSA128H>; +def : MSABitconvertPat<v4f32, v4i32, MSA128W>; +def : MSABitconvertPat<v2f64, v2i64, MSA128D>; + +// Little endian bitcasts are always no-ops +def : MSABitconvertPat<v16i8, v8i16, MSA128B, [HasMSA, IsLE]>; +def : MSABitconvertPat<v16i8, v4i32, MSA128B, [HasMSA, IsLE]>; +def : MSABitconvertPat<v16i8, v2i64, MSA128B, [HasMSA, IsLE]>; +def : MSABitconvertPat<v16i8, v8f16, MSA128B, [HasMSA, IsLE]>; +def : MSABitconvertPat<v16i8, v4f32, MSA128B, [HasMSA, IsLE]>; +def : MSABitconvertPat<v16i8, v2f64, MSA128B, [HasMSA, IsLE]>; + +def : MSABitconvertPat<v8i16, v16i8, MSA128H, [HasMSA, IsLE]>; +def : MSABitconvertPat<v8i16, v4i32, MSA128H, [HasMSA, IsLE]>; +def : MSABitconvertPat<v8i16, v2i64, MSA128H, [HasMSA, IsLE]>; +def : MSABitconvertPat<v8i16, v4f32, MSA128H, [HasMSA, IsLE]>; +def : MSABitconvertPat<v8i16, v2f64, MSA128H, [HasMSA, IsLE]>; + +def : MSABitconvertPat<v4i32, v16i8, MSA128W, [HasMSA, IsLE]>; +def : MSABitconvertPat<v4i32, v8i16, MSA128W, [HasMSA, IsLE]>; +def : MSABitconvertPat<v4i32, v2i64, MSA128W, [HasMSA, IsLE]>; +def : MSABitconvertPat<v4i32, v8f16, MSA128W, [HasMSA, IsLE]>; +def : MSABitconvertPat<v4i32, v2f64, MSA128W, [HasMSA, IsLE]>; + +def : MSABitconvertPat<v2i64, v16i8, MSA128D, [HasMSA, IsLE]>; +def : MSABitconvertPat<v2i64, v8i16, MSA128D, [HasMSA, IsLE]>; +def : MSABitconvertPat<v2i64, v4i32, MSA128D, [HasMSA, IsLE]>; +def : MSABitconvertPat<v2i64, v8f16, MSA128D, [HasMSA, IsLE]>; +def : MSABitconvertPat<v2i64, v4f32, MSA128D, [HasMSA, IsLE]>; + +def : MSABitconvertPat<v4f32, v16i8, MSA128W, [HasMSA, IsLE]>; +def : MSABitconvertPat<v4f32, v8i16, MSA128W, [HasMSA, IsLE]>; +def : MSABitconvertPat<v4f32, v2i64, MSA128W, [HasMSA, IsLE]>; +def : MSABitconvertPat<v4f32, v8f16, MSA128W, [HasMSA, IsLE]>; +def : MSABitconvertPat<v4f32, v2f64, MSA128W, [HasMSA, IsLE]>; + +def : MSABitconvertPat<v2f64, v16i8, MSA128D, [HasMSA, IsLE]>; +def : MSABitconvertPat<v2f64, v8i16, MSA128D, [HasMSA, IsLE]>; +def : MSABitconvertPat<v2f64, v4i32, MSA128D, [HasMSA, IsLE]>; +def : MSABitconvertPat<v2f64, v8f16, MSA128D, [HasMSA, IsLE]>; +def : MSABitconvertPat<v2f64, v4f32, MSA128D, [HasMSA, IsLE]>; + +// Big endian bitcasts expand to shuffle instructions. +// This is because bitcast is defined to be a store/load sequence and the +// vector store/load instructions are mixed-endian with respect to the vector +// as a whole (little endian with respect to element order, but big endian +// elements). + +class MSABitconvertReverseQuartersPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC, MSAInst Insn, + RegisterClass ViaRC> : + MSAPat<(DstVT (bitconvert SrcVT:$src)), + (COPY_TO_REGCLASS (Insn (COPY_TO_REGCLASS SrcVT:$src, ViaRC), 27), + DstRC), + [HasMSA, IsBE]>; + +class MSABitconvertReverseHalvesPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC, MSAInst Insn, + RegisterClass ViaRC> : + MSAPat<(DstVT (bitconvert SrcVT:$src)), + (COPY_TO_REGCLASS (Insn (COPY_TO_REGCLASS SrcVT:$src, ViaRC), 177), + DstRC), + [HasMSA, IsBE]>; + +class MSABitconvertReverseBInHPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC> : + MSABitconvertReverseHalvesPat<DstVT, SrcVT, DstRC, SHF_B, MSA128B>; + +class MSABitconvertReverseBInWPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC> : + MSABitconvertReverseQuartersPat<DstVT, SrcVT, DstRC, SHF_B, MSA128B>; + +class MSABitconvertReverseBInDPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC> : + MSAPat<(DstVT (bitconvert SrcVT:$src)), + (COPY_TO_REGCLASS + (SHF_W + (COPY_TO_REGCLASS + (SHF_B (COPY_TO_REGCLASS SrcVT:$src, MSA128B), 27), + MSA128W), 177), + DstRC), + [HasMSA, IsBE]>; + +class MSABitconvertReverseHInWPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC> : + MSABitconvertReverseHalvesPat<DstVT, SrcVT, DstRC, SHF_H, MSA128H>; + +class MSABitconvertReverseHInDPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC> : + MSABitconvertReverseQuartersPat<DstVT, SrcVT, DstRC, SHF_H, MSA128H>; + +class MSABitconvertReverseWInDPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC> : + MSABitconvertReverseHalvesPat<DstVT, SrcVT, DstRC, SHF_W, MSA128W>; + +def : MSABitconvertReverseBInHPat<v8i16, v16i8, MSA128H>; +def : MSABitconvertReverseBInHPat<v8f16, v16i8, MSA128H>; +def : MSABitconvertReverseBInWPat<v4i32, v16i8, MSA128W>; +def : MSABitconvertReverseBInWPat<v4f32, v16i8, MSA128W>; +def : MSABitconvertReverseBInDPat<v2i64, v16i8, MSA128D>; +def : MSABitconvertReverseBInDPat<v2f64, v16i8, MSA128D>; + +def : MSABitconvertReverseBInHPat<v16i8, v8i16, MSA128B>; +def : MSABitconvertReverseHInWPat<v4i32, v8i16, MSA128W>; +def : MSABitconvertReverseHInWPat<v4f32, v8i16, MSA128W>; +def : MSABitconvertReverseHInDPat<v2i64, v8i16, MSA128D>; +def : MSABitconvertReverseHInDPat<v2f64, v8i16, MSA128D>; + +def : MSABitconvertReverseBInHPat<v16i8, v8f16, MSA128B>; +def : MSABitconvertReverseHInWPat<v4i32, v8f16, MSA128W>; +def : MSABitconvertReverseHInWPat<v4f32, v8f16, MSA128W>; +def : MSABitconvertReverseHInDPat<v2i64, v8f16, MSA128D>; +def : MSABitconvertReverseHInDPat<v2f64, v8f16, MSA128D>; + +def : MSABitconvertReverseBInWPat<v16i8, v4i32, MSA128B>; +def : MSABitconvertReverseHInWPat<v8i16, v4i32, MSA128H>; +def : MSABitconvertReverseHInWPat<v8f16, v4i32, MSA128H>; +def : MSABitconvertReverseWInDPat<v2i64, v4i32, MSA128D>; +def : MSABitconvertReverseWInDPat<v2f64, v4i32, MSA128D>; + +def : MSABitconvertReverseBInWPat<v16i8, v4f32, MSA128B>; +def : MSABitconvertReverseHInWPat<v8i16, v4f32, MSA128H>; +def : MSABitconvertReverseHInWPat<v8f16, v4f32, MSA128H>; +def : MSABitconvertReverseWInDPat<v2i64, v4f32, MSA128D>; +def : MSABitconvertReverseWInDPat<v2f64, v4f32, MSA128D>; + +def : MSABitconvertReverseBInDPat<v16i8, v2i64, MSA128B>; +def : MSABitconvertReverseHInDPat<v8i16, v2i64, MSA128H>; +def : MSABitconvertReverseHInDPat<v8f16, v2i64, MSA128H>; +def : MSABitconvertReverseWInDPat<v4i32, v2i64, MSA128W>; +def : MSABitconvertReverseWInDPat<v4f32, v2i64, MSA128W>; + +def : MSABitconvertReverseBInDPat<v16i8, v2f64, MSA128B>; +def : MSABitconvertReverseHInDPat<v8i16, v2f64, MSA128H>; +def : MSABitconvertReverseHInDPat<v8f16, v2f64, MSA128H>; +def : MSABitconvertReverseWInDPat<v4i32, v2f64, MSA128W>; +def : MSABitconvertReverseWInDPat<v4f32, v2f64, MSA128W>; + +// Pseudos used to implement BNZ.df, and BZ.df + +class MSA_CBRANCH_PSEUDO_DESC_BASE<SDPatternOperator OpNode, ValueType TyNode, + RegisterClass RCWS, + InstrItinClass itin = NoItinerary> : + MipsPseudo<(outs GPR32:$dst), + (ins RCWS:$ws), + [(set GPR32:$dst, (OpNode (TyNode RCWS:$ws)))]> { + bit usesCustomInserter = 1; +} + +def SNZ_B_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAllNonZero, v16i8, + MSA128B, NoItinerary>; +def SNZ_H_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAllNonZero, v8i16, + MSA128H, NoItinerary>; +def SNZ_W_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAllNonZero, v4i32, + MSA128W, NoItinerary>; +def SNZ_D_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAllNonZero, v2i64, + MSA128D, NoItinerary>; +def SNZ_V_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAnyNonZero, v16i8, + MSA128B, NoItinerary>; + +def SZ_B_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAllZero, v16i8, + MSA128B, NoItinerary>; +def SZ_H_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAllZero, v8i16, + MSA128H, NoItinerary>; +def SZ_W_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAllZero, v4i32, + MSA128W, NoItinerary>; +def SZ_D_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAllZero, v2i64, + MSA128D, NoItinerary>; +def SZ_V_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAnyZero, v16i8, + MSA128B, NoItinerary>; + +// Vector extraction with fixed index. +// +// Extracting 32-bit values on MSA32 should always use COPY_S_W rather than +// COPY_U_W, even for the zero-extended case. This is because our forward +// compatibility strategy is to consider registers to be infinitely +// sign-extended so that a MIPS64 can execute MIPS32 code without getting +// different register values. +def : MSAPat<(vextract_zext_i32 (v4i32 MSA128W:$ws), immZExt2Ptr:$idx), + (COPY_S_W MSA128W:$ws, immZExt2:$idx)>, ASE_MSA_NOT_MSA64; +def : MSAPat<(vextract_zext_i32 (v4f32 MSA128W:$ws), immZExt2Ptr:$idx), + (COPY_S_W MSA128W:$ws, immZExt2:$idx)>, ASE_MSA_NOT_MSA64; + +// Extracting 64-bit values on MSA64 should always use COPY_S_D rather than +// COPY_U_D, even for the zero-extended case. This is because our forward +// compatibility strategy is to consider registers to be infinitely +// sign-extended so that a hypothetical MIPS128 would be able to execute MIPS64 +// code without getting different register values. +def : MSAPat<(vextract_zext_i64 (v2i64 MSA128D:$ws), immZExt1Ptr:$idx), + (COPY_S_D MSA128D:$ws, immZExt1:$idx)>, ASE_MSA64; +def : MSAPat<(vextract_zext_i64 (v2f64 MSA128D:$ws), immZExt1Ptr:$idx), + (COPY_S_D MSA128D:$ws, immZExt1:$idx)>, ASE_MSA64; + +// Vector extraction with variable index +def : MSAPat<(i32 (vextract_sext_i8 v16i8:$ws, i32:$idx)), + (SRA (COPY_TO_REGCLASS (i32 (EXTRACT_SUBREG (SPLAT_B v16i8:$ws, + i32:$idx), + sub_lo)), + GPR32), (i32 24))>; +def : MSAPat<(i32 (vextract_sext_i16 v8i16:$ws, i32:$idx)), + (SRA (COPY_TO_REGCLASS (i32 (EXTRACT_SUBREG (SPLAT_H v8i16:$ws, + i32:$idx), + sub_lo)), + GPR32), (i32 16))>; +def : MSAPat<(i32 (vextract_sext_i32 v4i32:$ws, i32:$idx)), + (COPY_TO_REGCLASS (i32 (EXTRACT_SUBREG (SPLAT_W v4i32:$ws, + i32:$idx), + sub_lo)), + GPR32)>; +def : MSAPat<(i64 (vextract_sext_i64 v2i64:$ws, i32:$idx)), + (COPY_TO_REGCLASS (i64 (EXTRACT_SUBREG (SPLAT_D v2i64:$ws, + i32:$idx), + sub_64)), + GPR64), [HasMSA, IsGP64bit]>; + +def : MSAPat<(i32 (vextract_zext_i8 v16i8:$ws, i32:$idx)), + (SRL (COPY_TO_REGCLASS (i32 (EXTRACT_SUBREG (SPLAT_B v16i8:$ws, + i32:$idx), + sub_lo)), + GPR32), (i32 24))>; +def : MSAPat<(i32 (vextract_zext_i16 v8i16:$ws, i32:$idx)), + (SRL (COPY_TO_REGCLASS (i32 (EXTRACT_SUBREG (SPLAT_H v8i16:$ws, + i32:$idx), + sub_lo)), + GPR32), (i32 16))>; +def : MSAPat<(i32 (vextract_zext_i32 v4i32:$ws, i32:$idx)), + (COPY_TO_REGCLASS (i32 (EXTRACT_SUBREG (SPLAT_W v4i32:$ws, + i32:$idx), + sub_lo)), + GPR32)>; +def : MSAPat<(i64 (vextract_zext_i64 v2i64:$ws, i32:$idx)), + (COPY_TO_REGCLASS (i64 (EXTRACT_SUBREG (SPLAT_D v2i64:$ws, + i32:$idx), + sub_64)), + GPR64), [HasMSA, IsGP64bit]>; + +def : MSAPat<(f32 (vector_extract v4f32:$ws, i32:$idx)), + (f32 (EXTRACT_SUBREG (SPLAT_W v4f32:$ws, + i32:$idx), + sub_lo))>; +def : MSAPat<(f64 (vector_extract v2f64:$ws, i32:$idx)), + (f64 (EXTRACT_SUBREG (SPLAT_D v2f64:$ws, + i32:$idx), + sub_64))>; + +// Vector extraction with variable index (N64 ABI) +def : MSAPat< + (i32 (vextract_sext_i8 v16i8:$ws, i64:$idx)), + (SRA (COPY_TO_REGCLASS + (i32 (EXTRACT_SUBREG + (SPLAT_B v16i8:$ws, + (COPY_TO_REGCLASS + (i32 (EXTRACT_SUBREG i64:$idx, sub_32)), GPR32)), + sub_lo)), + GPR32), + (i32 24))>; +def : MSAPat< + (i32 (vextract_sext_i16 v8i16:$ws, i64:$idx)), + (SRA (COPY_TO_REGCLASS + (i32 (EXTRACT_SUBREG + (SPLAT_H v8i16:$ws, + (COPY_TO_REGCLASS + (i32 (EXTRACT_SUBREG i64:$idx, sub_32)), GPR32)), + sub_lo)), + GPR32), + (i32 16))>; +def : MSAPat< + (i32 (vextract_sext_i32 v4i32:$ws, i64:$idx)), + (COPY_TO_REGCLASS + (i32 (EXTRACT_SUBREG + (SPLAT_W v4i32:$ws, + (COPY_TO_REGCLASS + (i32 (EXTRACT_SUBREG i64:$idx, sub_32)), GPR32)), + sub_lo)), + GPR32)>; +def : MSAPat< + (i64 (vextract_sext_i64 v2i64:$ws, i64:$idx)), + (COPY_TO_REGCLASS + (i64 (EXTRACT_SUBREG + (SPLAT_D v2i64:$ws, + (COPY_TO_REGCLASS (i32 (EXTRACT_SUBREG i64:$idx, sub_32)), GPR32)), + sub_64)), + GPR64), [HasMSA, IsGP64bit]>; + +def : MSAPat< + (i32 (vextract_zext_i8 v16i8:$ws, i64:$idx)), + (SRL (COPY_TO_REGCLASS + (i32 (EXTRACT_SUBREG + (SPLAT_B v16i8:$ws, + (COPY_TO_REGCLASS + (i32 (EXTRACT_SUBREG i64:$idx, sub_32)), GPR32)), + sub_lo)), + GPR32), + (i32 24))>; +def : MSAPat< + (i32 (vextract_zext_i16 v8i16:$ws, i64:$idx)), + (SRL (COPY_TO_REGCLASS + (i32 (EXTRACT_SUBREG + (SPLAT_H v8i16:$ws, + (COPY_TO_REGCLASS + (i32 (EXTRACT_SUBREG i64:$idx, sub_32)), GPR32)), + sub_lo)), + GPR32), + (i32 16))>; +def : MSAPat< + (i32 (vextract_zext_i32 v4i32:$ws, i64:$idx)), + (COPY_TO_REGCLASS + (i32 (EXTRACT_SUBREG + (SPLAT_W v4i32:$ws, + (COPY_TO_REGCLASS (i32 (EXTRACT_SUBREG i64:$idx, sub_32)), GPR32)), + sub_lo)), + GPR32)>; +def : MSAPat< + (i64 (vextract_zext_i64 v2i64:$ws, i64:$idx)), + (COPY_TO_REGCLASS + (i64 (EXTRACT_SUBREG + (SPLAT_D v2i64:$ws, + (COPY_TO_REGCLASS (i32 (EXTRACT_SUBREG i64:$idx, sub_32)), GPR32)), + sub_64)), + GPR64), + [HasMSA, IsGP64bit]>; + +def : MSAPat< + (f32 (vector_extract v4f32:$ws, i64:$idx)), + (f32 (EXTRACT_SUBREG + (SPLAT_W v4f32:$ws, + (COPY_TO_REGCLASS (i32 (EXTRACT_SUBREG i64:$idx, sub_32)), GPR32)), + sub_lo))>; +def : MSAPat< + (f64 (vector_extract v2f64:$ws, i64:$idx)), + (f64 (EXTRACT_SUBREG + (SPLAT_D v2f64:$ws, + (COPY_TO_REGCLASS (i32 (EXTRACT_SUBREG i64:$idx, sub_32)), GPR32)), + sub_64))>; diff --git a/contrib/llvm/lib/Target/Mips/MipsMachineFunction.cpp b/contrib/llvm/lib/Target/Mips/MipsMachineFunction.cpp new file mode 100644 index 0000000..c7d2738 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsMachineFunction.cpp @@ -0,0 +1,114 @@ +//===-- MipsMachineFunctionInfo.cpp - Private data used for Mips ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsInstrInfo.h" +#include "MipsMachineFunction.h" +#include "MipsSubtarget.h" +#include "MipsTargetMachine.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +static cl::opt<bool> +FixGlobalBaseReg("mips-fix-global-base-reg", cl::Hidden, cl::init(true), + cl::desc("Always use $gp as the global base register.")); + +MipsFunctionInfo::~MipsFunctionInfo() {} + +bool MipsFunctionInfo::globalBaseRegSet() const { + return GlobalBaseReg; +} + +unsigned MipsFunctionInfo::getGlobalBaseReg() { + // Return if it has already been initialized. + if (GlobalBaseReg) + return GlobalBaseReg; + + MipsSubtarget const &STI = + static_cast<const MipsSubtarget &>(MF.getSubtarget()); + + const TargetRegisterClass *RC = + STI.inMips16Mode() + ? &Mips::CPU16RegsRegClass + : STI.inMicroMipsMode() + ? &Mips::GPRMM16RegClass + : static_cast<const MipsTargetMachine &>(MF.getTarget()) + .getABI() + .IsN64() + ? &Mips::GPR64RegClass + : &Mips::GPR32RegClass; + return GlobalBaseReg = MF.getRegInfo().createVirtualRegister(RC); +} + +bool MipsFunctionInfo::mips16SPAliasRegSet() const { + return Mips16SPAliasReg; +} +unsigned MipsFunctionInfo::getMips16SPAliasReg() { + // Return if it has already been initialized. + if (Mips16SPAliasReg) + return Mips16SPAliasReg; + + const TargetRegisterClass *RC = &Mips::CPU16RegsRegClass; + return Mips16SPAliasReg = MF.getRegInfo().createVirtualRegister(RC); +} + +void MipsFunctionInfo::createEhDataRegsFI() { + for (int I = 0; I < 4; ++I) { + const TargetRegisterClass *RC = + static_cast<const MipsTargetMachine &>(MF.getTarget()).getABI().IsN64() + ? &Mips::GPR64RegClass + : &Mips::GPR32RegClass; + + EhDataRegFI[I] = MF.getFrameInfo()->CreateStackObject(RC->getSize(), + RC->getAlignment(), false); + } +} + +void MipsFunctionInfo::createISRRegFI() { + // ISRs require spill slots for Status & ErrorPC Coprocessor 0 registers. + // The current implementation only supports Mips32r2+ not Mips64rX. Status + // is always 32 bits, ErrorPC is 32 or 64 bits dependant on architecture, + // however Mips32r2+ is the supported architecture. + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + + for (int I = 0; I < 2; ++I) + ISRDataRegFI[I] = MF.getFrameInfo()->CreateStackObject( + RC->getSize(), RC->getAlignment(), false); +} + +bool MipsFunctionInfo::isEhDataRegFI(int FI) const { + return CallsEhReturn && (FI == EhDataRegFI[0] || FI == EhDataRegFI[1] + || FI == EhDataRegFI[2] || FI == EhDataRegFI[3]); +} + +bool MipsFunctionInfo::isISRRegFI(int FI) const { + return IsISR && (FI == ISRDataRegFI[0] || FI == ISRDataRegFI[1]); +} +MachinePointerInfo MipsFunctionInfo::callPtrInfo(const char *ES) { + return MachinePointerInfo(MF.getPSVManager().getExternalSymbolCallEntry(ES)); +} + +MachinePointerInfo MipsFunctionInfo::callPtrInfo(const GlobalValue *GV) { + return MachinePointerInfo(MF.getPSVManager().getGlobalValueCallEntry(GV)); +} + +int MipsFunctionInfo::getMoveF64ViaSpillFI(const TargetRegisterClass *RC) { + if (MoveF64ViaSpillFI == -1) { + MoveF64ViaSpillFI = MF.getFrameInfo()->CreateStackObject( + RC->getSize(), RC->getAlignment(), false); + } + return MoveF64ViaSpillFI; +} + +void MipsFunctionInfo::anchor() { } diff --git a/contrib/llvm/lib/Target/Mips/MipsMachineFunction.h b/contrib/llvm/lib/Target/Mips/MipsMachineFunction.h new file mode 100644 index 0000000..a2f6ee0 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsMachineFunction.h @@ -0,0 +1,143 @@ +//===-- MipsMachineFunctionInfo.h - Private data used for Mips ----*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the Mips specific subclass of MachineFunctionInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSMACHINEFUNCTION_H +#define LLVM_LIB_TARGET_MIPS_MIPSMACHINEFUNCTION_H + +#include "Mips16HardFloatInfo.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/CodeGen/PseudoSourceValue.h" +#include "llvm/IR/ValueMap.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetMachine.h" +#include <map> +#include <string> +#include <utility> + +namespace llvm { + +/// MipsFunctionInfo - This class is derived from MachineFunction private +/// Mips target-specific information for each MachineFunction. +class MipsFunctionInfo : public MachineFunctionInfo { +public: + MipsFunctionInfo(MachineFunction &MF) + : MF(MF), SRetReturnReg(0), GlobalBaseReg(0), Mips16SPAliasReg(0), + VarArgsFrameIndex(0), CallsEhReturn(false), IsISR(false), SaveS2(false), + MoveF64ViaSpillFI(-1) {} + + ~MipsFunctionInfo(); + + unsigned getSRetReturnReg() const { return SRetReturnReg; } + void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; } + + bool globalBaseRegSet() const; + unsigned getGlobalBaseReg(); + + bool mips16SPAliasRegSet() const; + unsigned getMips16SPAliasReg(); + + int getVarArgsFrameIndex() const { return VarArgsFrameIndex; } + void setVarArgsFrameIndex(int Index) { VarArgsFrameIndex = Index; } + + bool hasByvalArg() const { return HasByvalArg; } + void setFormalArgInfo(unsigned Size, bool HasByval) { + IncomingArgSize = Size; + HasByvalArg = HasByval; + } + + unsigned getIncomingArgSize() const { return IncomingArgSize; } + + bool callsEhReturn() const { return CallsEhReturn; } + void setCallsEhReturn() { CallsEhReturn = true; } + + void createEhDataRegsFI(); + int getEhDataRegFI(unsigned Reg) const { return EhDataRegFI[Reg]; } + bool isEhDataRegFI(int FI) const; + + /// Create a MachinePointerInfo that has an ExternalSymbolPseudoSourceValue + /// object representing a GOT entry for an external function. + MachinePointerInfo callPtrInfo(const char *ES); + + // Functions with the "interrupt" attribute require special prologues, + // epilogues and additional spill slots. + bool isISR() const { return IsISR; } + void setISR() { IsISR = true; } + void createISRRegFI(); + int getISRRegFI(unsigned Reg) const { return ISRDataRegFI[Reg]; } + bool isISRRegFI(int FI) const; + + /// Create a MachinePointerInfo that has a GlobalValuePseudoSourceValue object + /// representing a GOT entry for a global function. + MachinePointerInfo callPtrInfo(const GlobalValue *GV); + + void setSaveS2() { SaveS2 = true; } + bool hasSaveS2() const { return SaveS2; } + + int getMoveF64ViaSpillFI(const TargetRegisterClass *RC); + + std::map<const char *, const llvm::Mips16HardFloatInfo::FuncSignature *> + StubsNeeded; + +private: + virtual void anchor(); + + MachineFunction& MF; + /// SRetReturnReg - Some subtargets require that sret lowering includes + /// returning the value of the returned struct in a register. This field + /// holds the virtual register into which the sret argument is passed. + unsigned SRetReturnReg; + + /// GlobalBaseReg - keeps track of the virtual register initialized for + /// use as the global base register. This is used for PIC in some PIC + /// relocation models. + unsigned GlobalBaseReg; + + /// Mips16SPAliasReg - keeps track of the virtual register initialized for + /// use as an alias for SP for use in load/store of halfword/byte from/to + /// the stack + unsigned Mips16SPAliasReg; + + /// VarArgsFrameIndex - FrameIndex for start of varargs area. + int VarArgsFrameIndex; + + /// True if function has a byval argument. + bool HasByvalArg; + + /// Size of incoming argument area. + unsigned IncomingArgSize; + + /// CallsEhReturn - Whether the function calls llvm.eh.return. + bool CallsEhReturn; + + /// Frame objects for spilling eh data registers. + int EhDataRegFI[4]; + + /// ISR - Whether the function is an Interrupt Service Routine. + bool IsISR; + + /// Frame objects for spilling C0_STATUS, C0_EPC + int ISRDataRegFI[2]; + + // saveS2 + bool SaveS2; + + /// FrameIndex for expanding BuildPairF64 nodes to spill and reload when the + /// O32 FPXX ABI is enabled. -1 is used to denote invalid index. + int MoveF64ViaSpillFI; +}; + +} // end of namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsModuleISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Mips/MipsModuleISelDAGToDAG.cpp new file mode 100644 index 0000000..b18a673 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsModuleISelDAGToDAG.cpp @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// Instruction Selector Subtarget Control +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// This file defines a pass used to change the subtarget for the +// Mips Instruction selector. +// +//===----------------------------------------------------------------------===// + +#include "Mips.h" +#include "MipsTargetMachine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#define DEBUG_TYPE "mips-isel" + +namespace { + class MipsModuleDAGToDAGISel : public MachineFunctionPass { + public: + static char ID; + + explicit MipsModuleDAGToDAGISel(MipsTargetMachine &TM_) + : MachineFunctionPass(ID), TM(TM_) {} + + // Pass Name + const char *getPassName() const override { + return "MIPS DAG->DAG Pattern Instruction Selection"; + } + + bool runOnMachineFunction(MachineFunction &MF) override; + + protected: + MipsTargetMachine &TM; + }; + + char MipsModuleDAGToDAGISel::ID = 0; +} + +bool MipsModuleDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { + DEBUG(errs() << "In MipsModuleDAGToDAGISel::runMachineFunction\n"); + TM.resetSubtarget(&MF); + return false; +} + +llvm::FunctionPass *llvm::createMipsModuleISelDagPass(MipsTargetMachine &TM) { + return new MipsModuleDAGToDAGISel(TM); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsOptimizePICCall.cpp b/contrib/llvm/lib/Target/Mips/MipsOptimizePICCall.cpp new file mode 100644 index 0000000..7c940ee --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsOptimizePICCall.cpp @@ -0,0 +1,301 @@ +//===--------- MipsOptimizePICCall.cpp - Optimize PIC Calls ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass eliminates unnecessary instructions that set up $gp and replace +// instructions that load target function addresses with copy instructions. +// +//===----------------------------------------------------------------------===// + +#include "Mips.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsMachineFunction.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/ScopedHashTable.h" +#include "llvm/CodeGen/MachineDominators.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/CommandLine.h" + +using namespace llvm; + +#define DEBUG_TYPE "optimize-mips-pic-call" + +static cl::opt<bool> LoadTargetFromGOT("mips-load-target-from-got", + cl::init(true), + cl::desc("Load target address from GOT"), + cl::Hidden); + +static cl::opt<bool> EraseGPOpnd("mips-erase-gp-opnd", + cl::init(true), cl::desc("Erase GP Operand"), + cl::Hidden); + +namespace { +typedef PointerUnion<const Value *, const PseudoSourceValue *> ValueType; + +typedef std::pair<unsigned, unsigned> CntRegP; +typedef RecyclingAllocator<BumpPtrAllocator, + ScopedHashTableVal<ValueType, CntRegP> > +AllocatorTy; +typedef ScopedHashTable<ValueType, CntRegP, DenseMapInfo<ValueType>, + AllocatorTy> ScopedHTType; + +class MBBInfo { +public: + MBBInfo(MachineDomTreeNode *N); + const MachineDomTreeNode *getNode() const; + bool isVisited() const; + void preVisit(ScopedHTType &ScopedHT); + void postVisit(); + +private: + MachineDomTreeNode *Node; + ScopedHTType::ScopeTy *HTScope; +}; + +class OptimizePICCall : public MachineFunctionPass { +public: + OptimizePICCall(TargetMachine &tm) : MachineFunctionPass(ID) {} + + const char *getPassName() const override { return "Mips OptimizePICCall"; } + + bool runOnMachineFunction(MachineFunction &F) override; + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired<MachineDominatorTree>(); + MachineFunctionPass::getAnalysisUsage(AU); + } + +private: + /// \brief Visit MBB. + bool visitNode(MBBInfo &MBBI); + + /// \brief Test if MI jumps to a function via a register. + /// + /// Also, return the virtual register containing the target function's address + /// and the underlying object in Reg and Val respectively, if the function's + /// address can be resolved lazily. + bool isCallViaRegister(MachineInstr &MI, unsigned &Reg, + ValueType &Val) const; + + /// \brief Return the number of instructions that dominate the current + /// instruction and load the function address from object Entry. + unsigned getCount(ValueType Entry); + + /// \brief Return the destination virtual register of the last instruction + /// that loads from object Entry. + unsigned getReg(ValueType Entry); + + /// \brief Update ScopedHT. + void incCntAndSetReg(ValueType Entry, unsigned Reg); + + ScopedHTType ScopedHT; + static char ID; +}; + +char OptimizePICCall::ID = 0; +} // end of anonymous namespace + +/// Return the first MachineOperand of MI if it is a used virtual register. +static MachineOperand *getCallTargetRegOpnd(MachineInstr &MI) { + if (MI.getNumOperands() == 0) + return nullptr; + + MachineOperand &MO = MI.getOperand(0); + + if (!MO.isReg() || !MO.isUse() || + !TargetRegisterInfo::isVirtualRegister(MO.getReg())) + return nullptr; + + return &MO; +} + +/// Return type of register Reg. +static MVT::SimpleValueType getRegTy(unsigned Reg, MachineFunction &MF) { + const TargetRegisterClass *RC = MF.getRegInfo().getRegClass(Reg); + assert(RC->vt_end() - RC->vt_begin() == 1); + return *RC->vt_begin(); +} + +/// Do the following transformation: +/// +/// jalr $vreg +/// => +/// copy $t9, $vreg +/// jalr $t9 +static void setCallTargetReg(MachineBasicBlock *MBB, + MachineBasicBlock::iterator I) { + MachineFunction &MF = *MBB->getParent(); + const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); + unsigned SrcReg = I->getOperand(0).getReg(); + unsigned DstReg = getRegTy(SrcReg, MF) == MVT::i32 ? Mips::T9 : Mips::T9_64; + BuildMI(*MBB, I, I->getDebugLoc(), TII.get(TargetOpcode::COPY), DstReg) + .addReg(SrcReg); + I->getOperand(0).setReg(DstReg); +} + +/// Search MI's operands for register GP and erase it. +static void eraseGPOpnd(MachineInstr &MI) { + if (!EraseGPOpnd) + return; + + MachineFunction &MF = *MI.getParent()->getParent(); + MVT::SimpleValueType Ty = getRegTy(MI.getOperand(0).getReg(), MF); + unsigned Reg = Ty == MVT::i32 ? Mips::GP : Mips::GP_64; + + for (unsigned I = 0; I < MI.getNumOperands(); ++I) { + MachineOperand &MO = MI.getOperand(I); + if (MO.isReg() && MO.getReg() == Reg) { + MI.RemoveOperand(I); + return; + } + } + + llvm_unreachable(nullptr); +} + +MBBInfo::MBBInfo(MachineDomTreeNode *N) : Node(N), HTScope(nullptr) {} + +const MachineDomTreeNode *MBBInfo::getNode() const { return Node; } + +bool MBBInfo::isVisited() const { return HTScope; } + +void MBBInfo::preVisit(ScopedHTType &ScopedHT) { + HTScope = new ScopedHTType::ScopeTy(ScopedHT); +} + +void MBBInfo::postVisit() { + delete HTScope; +} + +// OptimizePICCall methods. +bool OptimizePICCall::runOnMachineFunction(MachineFunction &F) { + if (static_cast<const MipsSubtarget &>(F.getSubtarget()).inMips16Mode()) + return false; + + // Do a pre-order traversal of the dominator tree. + MachineDominatorTree *MDT = &getAnalysis<MachineDominatorTree>(); + bool Changed = false; + + SmallVector<MBBInfo, 8> WorkList(1, MBBInfo(MDT->getRootNode())); + + while (!WorkList.empty()) { + MBBInfo &MBBI = WorkList.back(); + + // If this MBB has already been visited, destroy the scope for the MBB and + // pop it from the work list. + if (MBBI.isVisited()) { + MBBI.postVisit(); + WorkList.pop_back(); + continue; + } + + // Visit the MBB and add its children to the work list. + MBBI.preVisit(ScopedHT); + Changed |= visitNode(MBBI); + const MachineDomTreeNode *Node = MBBI.getNode(); + const std::vector<MachineDomTreeNode *> &Children = Node->getChildren(); + WorkList.append(Children.begin(), Children.end()); + } + + return Changed; +} + +bool OptimizePICCall::visitNode(MBBInfo &MBBI) { + bool Changed = false; + MachineBasicBlock *MBB = MBBI.getNode()->getBlock(); + + for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E; + ++I) { + unsigned Reg; + ValueType Entry; + + // Skip instructions that are not call instructions via registers. + if (!isCallViaRegister(*I, Reg, Entry)) + continue; + + Changed = true; + unsigned N = getCount(Entry); + + if (N != 0) { + // If a function has been called more than twice, we do not have to emit a + // load instruction to get the function address from the GOT, but can + // instead reuse the address that has been loaded before. + if (N >= 2 && !LoadTargetFromGOT) + getCallTargetRegOpnd(*I)->setReg(getReg(Entry)); + + // Erase the $gp operand if this isn't the first time a function has + // been called. $gp needs to be set up only if the function call can go + // through a lazy binding stub. + eraseGPOpnd(*I); + } + + if (Entry) + incCntAndSetReg(Entry, Reg); + + setCallTargetReg(MBB, I); + } + + return Changed; +} + +bool OptimizePICCall::isCallViaRegister(MachineInstr &MI, unsigned &Reg, + ValueType &Val) const { + if (!MI.isCall()) + return false; + + MachineOperand *MO = getCallTargetRegOpnd(MI); + + // Return if MI is not a function call via a register. + if (!MO) + return false; + + // Get the instruction that loads the function address from the GOT. + Reg = MO->getReg(); + Val = (Value*)nullptr; + MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo(); + MachineInstr *DefMI = MRI.getVRegDef(Reg); + + assert(DefMI); + + // See if DefMI is an instruction that loads from a GOT entry that holds the + // address of a lazy binding stub. + if (!DefMI->mayLoad() || DefMI->getNumOperands() < 3) + return true; + + unsigned Flags = DefMI->getOperand(2).getTargetFlags(); + + if (Flags != MipsII::MO_GOT_CALL && Flags != MipsII::MO_CALL_LO16) + return true; + + // Return the underlying object for the GOT entry in Val. + assert(DefMI->hasOneMemOperand()); + Val = (*DefMI->memoperands_begin())->getValue(); + if (!Val) + Val = (*DefMI->memoperands_begin())->getPseudoValue(); + return true; +} + +unsigned OptimizePICCall::getCount(ValueType Entry) { + return ScopedHT.lookup(Entry).first; +} + +unsigned OptimizePICCall::getReg(ValueType Entry) { + unsigned Reg = ScopedHT.lookup(Entry).second; + assert(Reg); + return Reg; +} + +void OptimizePICCall::incCntAndSetReg(ValueType Entry, unsigned Reg) { + CntRegP P = ScopedHT.lookup(Entry); + ScopedHT.insert(Entry, std::make_pair(P.first + 1, Reg)); +} + +/// Return an OptimizeCall object. +FunctionPass *llvm::createMipsOptimizePICCallPass(MipsTargetMachine &TM) { + return new OptimizePICCall(TM); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsOptionRecord.h b/contrib/llvm/lib/Target/Mips/MipsOptionRecord.h new file mode 100644 index 0000000..23f0b70 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsOptionRecord.h @@ -0,0 +1,78 @@ +//===-- MipsOptionRecord.h - Abstraction for storing information ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// MipsOptionRecord - Abstraction for storing arbitrary information in +// ELF files. Arbitrary information (e.g. register usage) can be stored in Mips +// specific ELF sections like .Mips.options. Specific records should subclass +// MipsOptionRecord and provide an implementation to EmitMipsOptionRecord which +// basically just dumps the information into an ELF section. More information +// about .Mips.option can be found in the SysV ABI and the 64-bit ELF Object +// specification. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSOPTIONRECORD_H +#define LLVM_LIB_TARGET_MIPS_MIPSOPTIONRECORD_H + +#include "MCTargetDesc/MipsMCTargetDesc.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCRegisterInfo.h" + +namespace llvm { +class MipsELFStreamer; +class MCSubtargetInfo; + +class MipsOptionRecord { +public: + virtual ~MipsOptionRecord(){}; + virtual void EmitMipsOptionRecord() = 0; +}; + +class MipsRegInfoRecord : public MipsOptionRecord { +public: + MipsRegInfoRecord(MipsELFStreamer *S, MCContext &Context) + : Streamer(S), Context(Context) { + ri_gprmask = 0; + ri_cprmask[0] = ri_cprmask[1] = ri_cprmask[2] = ri_cprmask[3] = 0; + ri_gp_value = 0; + + const MCRegisterInfo *TRI = Context.getRegisterInfo(); + GPR32RegClass = &(TRI->getRegClass(Mips::GPR32RegClassID)); + GPR64RegClass = &(TRI->getRegClass(Mips::GPR64RegClassID)); + FGR32RegClass = &(TRI->getRegClass(Mips::FGR32RegClassID)); + FGR64RegClass = &(TRI->getRegClass(Mips::FGR64RegClassID)); + AFGR64RegClass = &(TRI->getRegClass(Mips::AFGR64RegClassID)); + MSA128BRegClass = &(TRI->getRegClass(Mips::MSA128BRegClassID)); + COP0RegClass = &(TRI->getRegClass(Mips::COP0RegClassID)); + COP2RegClass = &(TRI->getRegClass(Mips::COP2RegClassID)); + COP3RegClass = &(TRI->getRegClass(Mips::COP3RegClassID)); + } + ~MipsRegInfoRecord() override {} + + void EmitMipsOptionRecord() override; + void SetPhysRegUsed(unsigned Reg, const MCRegisterInfo *MCRegInfo); + +private: + MipsELFStreamer *Streamer; + MCContext &Context; + const MCRegisterClass *GPR32RegClass; + const MCRegisterClass *GPR64RegClass; + const MCRegisterClass *FGR32RegClass; + const MCRegisterClass *FGR64RegClass; + const MCRegisterClass *AFGR64RegClass; + const MCRegisterClass *MSA128BRegClass; + const MCRegisterClass *COP0RegClass; + const MCRegisterClass *COP2RegClass; + const MCRegisterClass *COP3RegClass; + uint32_t ri_gprmask; + uint32_t ri_cprmask[4]; + int64_t ri_gp_value; +}; +} // namespace llvm +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsOs16.cpp b/contrib/llvm/lib/Target/Mips/MipsOs16.cpp new file mode 100644 index 0000000..b6cd791 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsOs16.cpp @@ -0,0 +1,156 @@ +//===---- MipsOs16.cpp for Mips Option -Os16 --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an optimization phase for the MIPS target. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Instructions.h" +#include "Mips.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#define DEBUG_TYPE "mips-os16" + +static cl::opt<std::string> Mips32FunctionMask( + "mips32-function-mask", + cl::init(""), + cl::desc("Force function to be mips32"), + cl::Hidden); + +namespace { + class MipsOs16 : public ModulePass { + public: + static char ID; + + MipsOs16() : ModulePass(ID) {} + + const char *getPassName() const override { + return "MIPS Os16 Optimization"; + } + + bool runOnModule(Module &M) override; + }; + + char MipsOs16::ID = 0; +} + +// Figure out if we need float point based on the function signature. +// We need to move variables in and/or out of floating point +// registers because of the ABI +// +static bool needsFPFromSig(Function &F) { + Type* RetType = F.getReturnType(); + switch (RetType->getTypeID()) { + case Type::FloatTyID: + case Type::DoubleTyID: + return true; + default: + ; + } + if (F.arg_size() >=1) { + Argument &Arg = F.getArgumentList().front(); + switch (Arg.getType()->getTypeID()) { + case Type::FloatTyID: + case Type::DoubleTyID: + return true; + default: + ; + } + } + return false; +} + +// Figure out if the function will need floating point operations +// +static bool needsFP(Function &F) { + if (needsFPFromSig(F)) + return true; + for (Function::const_iterator BB = F.begin(), E = F.end(); BB != E; ++BB) + for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); + I != E; ++I) { + const Instruction &Inst = *I; + switch (Inst.getOpcode()) { + case Instruction::FAdd: + case Instruction::FSub: + case Instruction::FMul: + case Instruction::FDiv: + case Instruction::FRem: + case Instruction::FPToUI: + case Instruction::FPToSI: + case Instruction::UIToFP: + case Instruction::SIToFP: + case Instruction::FPTrunc: + case Instruction::FPExt: + case Instruction::FCmp: + return true; + default: + ; + } + if (const CallInst *CI = dyn_cast<CallInst>(I)) { + DEBUG(dbgs() << "Working on call" << "\n"); + Function &F_ = *CI->getCalledFunction(); + if (needsFPFromSig(F_)) + return true; + } + } + return false; +} + + +bool MipsOs16::runOnModule(Module &M) { + bool usingMask = Mips32FunctionMask.length() > 0; + bool doneUsingMask = false; // this will make it stop repeating + DEBUG(dbgs() << "Run on Module MipsOs16 \n" << Mips32FunctionMask << "\n"); + if (usingMask) + DEBUG(dbgs() << "using mask \n" << Mips32FunctionMask << "\n"); + unsigned int functionIndex = 0; + bool modified = false; + for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { + if (F->isDeclaration()) continue; + DEBUG(dbgs() << "Working on " << F->getName() << "\n"); + if (usingMask) { + if (!doneUsingMask) { + if (functionIndex == Mips32FunctionMask.length()) + functionIndex = 0; + switch (Mips32FunctionMask[functionIndex]) { + case '1': + DEBUG(dbgs() << "mask forced mips32: " << F->getName() << "\n"); + F->addFnAttr("nomips16"); + break; + case '.': + doneUsingMask = true; + break; + default: + break; + } + functionIndex++; + } + } + else { + if (needsFP(*F)) { + DEBUG(dbgs() << "os16 forced mips32: " << F->getName() << "\n"); + F->addFnAttr("nomips16"); + } + else { + DEBUG(dbgs() << "os16 forced mips16: " << F->getName() << "\n"); + F->addFnAttr("mips16"); + } + } + } + return modified; +} + +ModulePass *llvm::createMipsOs16Pass(MipsTargetMachine &TM) { + return new MipsOs16; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.cpp new file mode 100644 index 0000000..28e5a42 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.cpp @@ -0,0 +1,328 @@ +//===-- MipsRegisterInfo.cpp - MIPS Register Information -== --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the MIPS implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#include "MipsRegisterInfo.h" +#include "Mips.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsInstrInfo.h" +#include "MipsMachineFunction.h" +#include "MipsSubtarget.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.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" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" + +using namespace llvm; + +#define DEBUG_TYPE "mips-reg-info" + +#define GET_REGINFO_TARGET_DESC +#include "MipsGenRegisterInfo.inc" + +MipsRegisterInfo::MipsRegisterInfo() : MipsGenRegisterInfo(Mips::RA) {} + +unsigned MipsRegisterInfo::getPICCallReg() { return Mips::T9; } + +const TargetRegisterClass * +MipsRegisterInfo::getPointerRegClass(const MachineFunction &MF, + unsigned Kind) const { + MipsABIInfo ABI = MF.getSubtarget<MipsSubtarget>().getABI(); + return ABI.ArePtrs64bit() ? &Mips::GPR64RegClass : &Mips::GPR32RegClass; +} + +unsigned +MipsRegisterInfo::getRegPressureLimit(const TargetRegisterClass *RC, + MachineFunction &MF) const { + switch (RC->getID()) { + default: + return 0; + case Mips::GPR32RegClassID: + case Mips::GPR64RegClassID: + case Mips::DSPRRegClassID: { + const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering(); + return 28 - TFI->hasFP(MF); + } + case Mips::FGR32RegClassID: + return 32; + case Mips::AFGR64RegClassID: + return 16; + case Mips::FGR64RegClassID: + return 32; + } +} + +//===----------------------------------------------------------------------===// +// Callee Saved Registers methods +//===----------------------------------------------------------------------===// + +/// Mips Callee Saved Registers +const MCPhysReg * +MipsRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { + const MipsSubtarget &Subtarget = MF->getSubtarget<MipsSubtarget>(); + const Function *F = MF->getFunction(); + if (F->hasFnAttribute("interrupt")) { + if (Subtarget.hasMips64()) + return Subtarget.hasMips64r6() ? CSR_Interrupt_64R6_SaveList + : CSR_Interrupt_64_SaveList; + else + return Subtarget.hasMips32r6() ? CSR_Interrupt_32R6_SaveList + : CSR_Interrupt_32_SaveList; + } + + if (Subtarget.isSingleFloat()) + return CSR_SingleFloatOnly_SaveList; + + if (Subtarget.isABI_N64()) + return CSR_N64_SaveList; + + if (Subtarget.isABI_N32()) + return CSR_N32_SaveList; + + if (Subtarget.isFP64bit()) + return CSR_O32_FP64_SaveList; + + if (Subtarget.isFPXX()) + return CSR_O32_FPXX_SaveList; + + return CSR_O32_SaveList; +} + +const uint32_t * +MipsRegisterInfo::getCallPreservedMask(const MachineFunction &MF, + CallingConv::ID) const { + const MipsSubtarget &Subtarget = MF.getSubtarget<MipsSubtarget>(); + if (Subtarget.isSingleFloat()) + return CSR_SingleFloatOnly_RegMask; + + if (Subtarget.isABI_N64()) + return CSR_N64_RegMask; + + if (Subtarget.isABI_N32()) + return CSR_N32_RegMask; + + if (Subtarget.isFP64bit()) + return CSR_O32_FP64_RegMask; + + if (Subtarget.isFPXX()) + return CSR_O32_FPXX_RegMask; + + return CSR_O32_RegMask; +} + +const uint32_t *MipsRegisterInfo::getMips16RetHelperMask() { + return CSR_Mips16RetHelper_RegMask; +} + +BitVector MipsRegisterInfo:: +getReservedRegs(const MachineFunction &MF) const { + static const MCPhysReg ReservedGPR32[] = { + Mips::ZERO, Mips::K0, Mips::K1, Mips::SP + }; + + static const MCPhysReg ReservedGPR64[] = { + Mips::ZERO_64, Mips::K0_64, Mips::K1_64, Mips::SP_64 + }; + + BitVector Reserved(getNumRegs()); + const MipsSubtarget &Subtarget = MF.getSubtarget<MipsSubtarget>(); + typedef TargetRegisterClass::const_iterator RegIter; + + 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]); + + // For mno-abicalls, GP is a program invariant! + if (!Subtarget.isABICalls()) { + Reserved.set(Mips::GP); + Reserved.set(Mips::GP_64); + } + + if (Subtarget.isFP64bit()) { + // Reserve all registers in AFGR64. + for (RegIter Reg = Mips::AFGR64RegClass.begin(), + EReg = Mips::AFGR64RegClass.end(); Reg != EReg; ++Reg) + Reserved.set(*Reg); + } else { + // Reserve all registers in FGR64. + for (RegIter Reg = Mips::FGR64RegClass.begin(), + EReg = Mips::FGR64RegClass.end(); Reg != EReg; ++Reg) + Reserved.set(*Reg); + } + // Reserve FP if this function should have a dedicated frame pointer register. + if (Subtarget.getFrameLowering()->hasFP(MF)) { + if (Subtarget.inMips16Mode()) + Reserved.set(Mips::S0); + else { + Reserved.set(Mips::FP); + Reserved.set(Mips::FP_64); + + // Reserve the base register if we need to both realign the stack and + // allocate variable-sized objects at runtime. This should test the + // same conditions as MipsFrameLowering::hasBP(). + if (needsStackRealignment(MF) && + MF.getFrameInfo()->hasVarSizedObjects()) { + Reserved.set(Mips::S7); + Reserved.set(Mips::S7_64); + } + } + } + + // Reserve hardware registers. + Reserved.set(Mips::HWR29); + + // Reserve DSP control register. + Reserved.set(Mips::DSPPos); + Reserved.set(Mips::DSPSCount); + Reserved.set(Mips::DSPCarry); + Reserved.set(Mips::DSPEFI); + Reserved.set(Mips::DSPOutFlag); + + // Reserve MSA control registers. + Reserved.set(Mips::MSAIR); + Reserved.set(Mips::MSACSR); + Reserved.set(Mips::MSAAccess); + Reserved.set(Mips::MSASave); + Reserved.set(Mips::MSAModify); + Reserved.set(Mips::MSARequest); + Reserved.set(Mips::MSAMap); + Reserved.set(Mips::MSAUnmap); + + // Reserve RA if in mips16 mode. + if (Subtarget.inMips16Mode()) { + 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. + if (Subtarget.useSmallSection()) { + Reserved.set(Mips::GP); + Reserved.set(Mips::GP_64); + } + + if (Subtarget.isABI_O32() && !Subtarget.useOddSPReg()) { + for (const auto &Reg : Mips::OddSPRegClass) + Reserved.set(Reg); + } + + return Reserved; +} + +bool +MipsRegisterInfo::requiresRegisterScavenging(const MachineFunction &MF) const { + return true; +} + +bool +MipsRegisterInfo::trackLivenessAfterRegAlloc(const MachineFunction &MF) const { + return true; +} + +// FrameIndex represent objects inside a abstract stack. +// We must replace FrameIndex with an stack/frame pointer +// direct reference. +void MipsRegisterInfo:: +eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, + unsigned FIOperandNum, RegScavenger *RS) const { + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + + DEBUG(errs() << "\nFunction : " << MF.getName() << "\n"; + errs() << "<--------->\n" << MI); + + int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); + uint64_t stackSize = MF.getFrameInfo()->getStackSize(); + int64_t spOffset = MF.getFrameInfo()->getObjectOffset(FrameIndex); + + DEBUG(errs() << "FrameIndex : " << FrameIndex << "\n" + << "spOffset : " << spOffset << "\n" + << "stackSize : " << stackSize << "\n"); + + eliminateFI(MI, FIOperandNum, FrameIndex, stackSize, spOffset); +} + +unsigned MipsRegisterInfo:: +getFrameRegister(const MachineFunction &MF) const { + const MipsSubtarget &Subtarget = MF.getSubtarget<MipsSubtarget>(); + const TargetFrameLowering *TFI = Subtarget.getFrameLowering(); + bool IsN64 = + static_cast<const MipsTargetMachine &>(MF.getTarget()).getABI().IsN64(); + + if (Subtarget.inMips16Mode()) + return TFI->hasFP(MF) ? Mips::S0 : Mips::SP; + else + return TFI->hasFP(MF) ? (IsN64 ? Mips::FP_64 : Mips::FP) : + (IsN64 ? Mips::SP_64 : Mips::SP); +} + +bool MipsRegisterInfo::canRealignStack(const MachineFunction &MF) const { + // Avoid realigning functions that explicitly do not want to be realigned. + // Normally, we should report an error when a function should be dynamically + // realigned but also has the attribute no-realign-stack. Unfortunately, + // with this attribute, MachineFrameInfo clamps each new object's alignment + // to that of the stack's alignment as specified by the ABI. As a result, + // the information of whether we have objects with larger alignment + // requirement than the stack's alignment is already lost at this point. + if (!TargetRegisterInfo::canRealignStack(MF)) + return false; + + const MipsSubtarget &Subtarget = MF.getSubtarget<MipsSubtarget>(); + unsigned FP = Subtarget.isGP32bit() ? Mips::FP : Mips::FP_64; + unsigned BP = Subtarget.isGP32bit() ? Mips::S7 : Mips::S7_64; + + // Support dynamic stack realignment only for targets with standard encoding. + if (!Subtarget.hasStandardEncoding()) + return false; + + // We can't perform dynamic stack realignment if we can't reserve the + // frame pointer register. + if (!MF.getRegInfo().canReserveReg(FP)) + return false; + + // We can realign the stack if we know the maximum call frame size and we + // don't have variable sized objects. + if (Subtarget.getFrameLowering()->hasReservedCallFrame(MF)) + return true; + + // We have to reserve the base pointer register in the presence of variable + // sized objects. + return MF.getRegInfo().canReserveReg(BP); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.h b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.h new file mode 100644 index 0000000..5de68a2 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.h @@ -0,0 +1,80 @@ +//===-- MipsRegisterInfo.h - Mips Register Information Impl -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSREGISTERINFO_H +#define LLVM_LIB_TARGET_MIPS_MIPSREGISTERINFO_H + +#include "Mips.h" +#include "llvm/Target/TargetRegisterInfo.h" + +#define GET_REGINFO_HEADER +#include "MipsGenRegisterInfo.inc" + +namespace llvm { +class MipsRegisterInfo : public MipsGenRegisterInfo { +public: + MipsRegisterInfo(); + + /// getRegisterNumbering - Given the enum value for some register, e.g. + /// Mips::RA, return the number that it corresponds to (e.g. 31). + static unsigned getRegisterNumbering(unsigned RegEnum); + + /// Get PIC indirect call register + static unsigned getPICCallReg(); + + /// Adjust the Mips stack frame. + void adjustMipsStackFrame(MachineFunction &MF) const; + + /// Code Generation virtual methods... + const TargetRegisterClass *getPointerRegClass(const MachineFunction &MF, + unsigned Kind) const override; + + unsigned getRegPressureLimit(const TargetRegisterClass *RC, + MachineFunction &MF) const override; + const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override; + const uint32_t *getCallPreservedMask(const MachineFunction &MF, + CallingConv::ID) const override; + static const uint32_t *getMips16RetHelperMask(); + + BitVector getReservedRegs(const MachineFunction &MF) const override; + + bool requiresRegisterScavenging(const MachineFunction &MF) const override; + + bool trackLivenessAfterRegAlloc(const MachineFunction &MF) const override; + + /// Stack Frame Processing Methods + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, unsigned FIOperandNum, + RegScavenger *RS = nullptr) const override; + + void processFunctionBeforeFrameFinalized(MachineFunction &MF, + RegScavenger *RS = nullptr) const; + + // Stack realignment queries. + bool canRealignStack(const MachineFunction &MF) const override; + + /// Debug information queries. + unsigned getFrameRegister(const MachineFunction &MF) const override; + + /// \brief Return GPR register class. + virtual const TargetRegisterClass *intRegClass(unsigned Size) const = 0; + +private: + virtual void eliminateFI(MachineBasicBlock::iterator II, unsigned OpNo, + int FrameIndex, uint64_t StackSize, + int64_t SPOffset) const = 0; +}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.td b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.td new file mode 100644 index 0000000..02bcac5 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.td @@ -0,0 +1,654 @@ +//===-- MipsRegisterInfo.td - Mips Register defs -----------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Declarations that describe the MIPS register file +//===----------------------------------------------------------------------===// +let Namespace = "Mips" in { +def sub_32 : SubRegIndex<32>; +def sub_64 : SubRegIndex<64>; +def sub_lo : SubRegIndex<32>; +def sub_hi : SubRegIndex<32, 32>; +def sub_dsp16_19 : SubRegIndex<4, 16>; +def sub_dsp20 : SubRegIndex<1, 20>; +def sub_dsp21 : SubRegIndex<1, 21>; +def sub_dsp22 : SubRegIndex<1, 22>; +def sub_dsp23 : SubRegIndex<1, 23>; +} + +class Unallocatable { + bit isAllocatable = 0; +} + +// We have banks of 32 registers each. +class MipsReg<bits<16> Enc, string n> : Register<n> { + let HWEncoding = Enc; + let Namespace = "Mips"; +} + +class MipsRegWithSubRegs<bits<16> Enc, string n, list<Register> subregs> + : RegisterWithSubRegs<n, subregs> { + let HWEncoding = Enc; + let Namespace = "Mips"; +} + +// Mips CPU Registers +class MipsGPRReg<bits<16> Enc, string n> : MipsReg<Enc, n>; + +// Mips 64-bit CPU Registers +class Mips64GPRReg<bits<16> Enc, string n, list<Register> subregs> + : MipsRegWithSubRegs<Enc, n, subregs> { + let SubRegIndices = [sub_32]; +} + +// Mips 32-bit FPU Registers +class FPR<bits<16> Enc, string n> : MipsReg<Enc, n>; + +// Mips 64-bit (aliased) FPU Registers +class AFPR<bits<16> Enc, string n, list<Register> subregs> + : MipsRegWithSubRegs<Enc, n, subregs> { + let SubRegIndices = [sub_lo, sub_hi]; + let CoveredBySubRegs = 1; +} + +class AFPR64<bits<16> Enc, string n, list<Register> subregs> + : MipsRegWithSubRegs<Enc, n, subregs> { + let SubRegIndices = [sub_lo, sub_hi]; + let CoveredBySubRegs = 1; +} + +// Mips 128-bit (aliased) MSA Registers +class AFPR128<bits<16> Enc, string n, list<Register> subregs> + : MipsRegWithSubRegs<Enc, n, subregs> { + let SubRegIndices = [sub_64]; +} + +// Accumulator Registers +class ACCReg<bits<16> Enc, string n, list<Register> subregs> + : MipsRegWithSubRegs<Enc, n, subregs> { + let SubRegIndices = [sub_lo, sub_hi]; + let CoveredBySubRegs = 1; +} + +// Mips Hardware Registers +class HWR<bits<16> Enc, string n> : MipsReg<Enc, n>; + +//===----------------------------------------------------------------------===// +// Registers +//===----------------------------------------------------------------------===// + +let Namespace = "Mips" in { + // General Purpose Registers + def ZERO : MipsGPRReg< 0, "zero">, DwarfRegNum<[0]>; + def AT : MipsGPRReg< 1, "1">, DwarfRegNum<[1]>; + def V0 : MipsGPRReg< 2, "2">, DwarfRegNum<[2]>; + def V1 : MipsGPRReg< 3, "3">, DwarfRegNum<[3]>; + def A0 : MipsGPRReg< 4, "4">, DwarfRegNum<[4]>; + def A1 : MipsGPRReg< 5, "5">, DwarfRegNum<[5]>; + def A2 : MipsGPRReg< 6, "6">, DwarfRegNum<[6]>; + def A3 : MipsGPRReg< 7, "7">, DwarfRegNum<[7]>; + def T0 : MipsGPRReg< 8, "8">, DwarfRegNum<[8]>; + def T1 : MipsGPRReg< 9, "9">, DwarfRegNum<[9]>; + def T2 : MipsGPRReg< 10, "10">, DwarfRegNum<[10]>; + def T3 : MipsGPRReg< 11, "11">, DwarfRegNum<[11]>; + def T4 : MipsGPRReg< 12, "12">, DwarfRegNum<[12]>; + def T5 : MipsGPRReg< 13, "13">, DwarfRegNum<[13]>; + def T6 : MipsGPRReg< 14, "14">, DwarfRegNum<[14]>; + def T7 : MipsGPRReg< 15, "15">, DwarfRegNum<[15]>; + def S0 : MipsGPRReg< 16, "16">, DwarfRegNum<[16]>; + def S1 : MipsGPRReg< 17, "17">, DwarfRegNum<[17]>; + def S2 : MipsGPRReg< 18, "18">, DwarfRegNum<[18]>; + def S3 : MipsGPRReg< 19, "19">, DwarfRegNum<[19]>; + def S4 : MipsGPRReg< 20, "20">, DwarfRegNum<[20]>; + def S5 : MipsGPRReg< 21, "21">, DwarfRegNum<[21]>; + def S6 : MipsGPRReg< 22, "22">, DwarfRegNum<[22]>; + def S7 : MipsGPRReg< 23, "23">, DwarfRegNum<[23]>; + def T8 : MipsGPRReg< 24, "24">, DwarfRegNum<[24]>; + def T9 : MipsGPRReg< 25, "25">, DwarfRegNum<[25]>; + def K0 : MipsGPRReg< 26, "26">, DwarfRegNum<[26]>; + def K1 : MipsGPRReg< 27, "27">, DwarfRegNum<[27]>; + def GP : MipsGPRReg< 28, "gp">, DwarfRegNum<[28]>; + def SP : MipsGPRReg< 29, "sp">, DwarfRegNum<[29]>; + def FP : MipsGPRReg< 30, "fp">, DwarfRegNum<[30]>; + def RA : MipsGPRReg< 31, "ra">, DwarfRegNum<[31]>; + + // General Purpose 64-bit Registers + def ZERO_64 : Mips64GPRReg< 0, "zero", [ZERO]>, DwarfRegNum<[0]>; + def AT_64 : Mips64GPRReg< 1, "1", [AT]>, DwarfRegNum<[1]>; + def V0_64 : Mips64GPRReg< 2, "2", [V0]>, DwarfRegNum<[2]>; + def V1_64 : Mips64GPRReg< 3, "3", [V1]>, DwarfRegNum<[3]>; + def A0_64 : Mips64GPRReg< 4, "4", [A0]>, DwarfRegNum<[4]>; + def A1_64 : Mips64GPRReg< 5, "5", [A1]>, DwarfRegNum<[5]>; + def A2_64 : Mips64GPRReg< 6, "6", [A2]>, DwarfRegNum<[6]>; + def A3_64 : Mips64GPRReg< 7, "7", [A3]>, DwarfRegNum<[7]>; + def T0_64 : Mips64GPRReg< 8, "8", [T0]>, DwarfRegNum<[8]>; + def T1_64 : Mips64GPRReg< 9, "9", [T1]>, DwarfRegNum<[9]>; + def T2_64 : Mips64GPRReg< 10, "10", [T2]>, DwarfRegNum<[10]>; + def T3_64 : Mips64GPRReg< 11, "11", [T3]>, DwarfRegNum<[11]>; + def T4_64 : Mips64GPRReg< 12, "12", [T4]>, DwarfRegNum<[12]>; + def T5_64 : Mips64GPRReg< 13, "13", [T5]>, DwarfRegNum<[13]>; + def T6_64 : Mips64GPRReg< 14, "14", [T6]>, DwarfRegNum<[14]>; + def T7_64 : Mips64GPRReg< 15, "15", [T7]>, DwarfRegNum<[15]>; + def S0_64 : Mips64GPRReg< 16, "16", [S0]>, DwarfRegNum<[16]>; + def S1_64 : Mips64GPRReg< 17, "17", [S1]>, DwarfRegNum<[17]>; + def S2_64 : Mips64GPRReg< 18, "18", [S2]>, DwarfRegNum<[18]>; + def S3_64 : Mips64GPRReg< 19, "19", [S3]>, DwarfRegNum<[19]>; + def S4_64 : Mips64GPRReg< 20, "20", [S4]>, DwarfRegNum<[20]>; + def S5_64 : Mips64GPRReg< 21, "21", [S5]>, DwarfRegNum<[21]>; + def S6_64 : Mips64GPRReg< 22, "22", [S6]>, DwarfRegNum<[22]>; + def S7_64 : Mips64GPRReg< 23, "23", [S7]>, DwarfRegNum<[23]>; + def T8_64 : Mips64GPRReg< 24, "24", [T8]>, DwarfRegNum<[24]>; + def T9_64 : Mips64GPRReg< 25, "25", [T9]>, DwarfRegNum<[25]>; + def K0_64 : Mips64GPRReg< 26, "26", [K0]>, DwarfRegNum<[26]>; + def K1_64 : Mips64GPRReg< 27, "27", [K1]>, DwarfRegNum<[27]>; + def GP_64 : Mips64GPRReg< 28, "gp", [GP]>, DwarfRegNum<[28]>; + def SP_64 : Mips64GPRReg< 29, "sp", [SP]>, DwarfRegNum<[29]>; + def FP_64 : Mips64GPRReg< 30, "fp", [FP]>, DwarfRegNum<[30]>; + def RA_64 : Mips64GPRReg< 31, "ra", [RA]>, DwarfRegNum<[31]>; + + /// Mips Single point precision FPU Registers + foreach I = 0-31 in + def F#I : FPR<I, "f"#I>, DwarfRegNum<[!add(I, 32)]>; + + // Higher half of 64-bit FP registers. + foreach I = 0-31 in + def F_HI#I : FPR<I, "f"#I>, DwarfRegNum<[!add(I, 32)]>; + + /// Mips Double point precision FPU Registers (aliased + /// with the single precision to hold 64 bit values) + foreach I = 0-15 in + def D#I : AFPR<!shl(I, 1), "f"#!shl(I, 1), + [!cast<FPR>("F"#!shl(I, 1)), + !cast<FPR>("F"#!add(!shl(I, 1), 1))]>; + + /// Mips Double point precision FPU Registers in MFP64 mode. + foreach I = 0-31 in + def D#I#_64 : AFPR64<I, "f"#I, [!cast<FPR>("F"#I), !cast<FPR>("F_HI"#I)]>, + DwarfRegNum<[!add(I, 32)]>; + + /// Mips MSA registers + /// MSA and FPU cannot both be present unless the FPU has 64-bit registers + foreach I = 0-31 in + def W#I : AFPR128<I, "w"#I, [!cast<AFPR64>("D"#I#"_64")]>, + DwarfRegNum<[!add(I, 32)]>; + + // Hi/Lo registers + def HI0 : MipsReg<0, "ac0">, DwarfRegNum<[64]>; + def HI1 : MipsReg<1, "ac1">, DwarfRegNum<[176]>; + def HI2 : MipsReg<2, "ac2">, DwarfRegNum<[178]>; + def HI3 : MipsReg<3, "ac3">, DwarfRegNum<[180]>; + def LO0 : MipsReg<0, "ac0">, DwarfRegNum<[65]>; + def LO1 : MipsReg<1, "ac1">, DwarfRegNum<[177]>; + def LO2 : MipsReg<2, "ac2">, DwarfRegNum<[179]>; + def LO3 : MipsReg<3, "ac3">, DwarfRegNum<[181]>; + + let SubRegIndices = [sub_32] in { + def HI0_64 : RegisterWithSubRegs<"hi", [HI0]>; + def LO0_64 : RegisterWithSubRegs<"lo", [LO0]>; + } + + // FP control registers. + foreach I = 0-31 in + def FCR#I : MipsReg<#I, ""#I>; + + // FP condition code registers. + foreach I = 0-7 in + def FCC#I : MipsReg<#I, "fcc"#I>; + + // COP0 registers. + foreach I = 0-31 in + def COP0#I : MipsReg<#I, ""#I>; + + // COP2 registers. + foreach I = 0-31 in + def COP2#I : MipsReg<#I, ""#I>; + + // COP3 registers. + foreach I = 0-31 in + def COP3#I : MipsReg<#I, ""#I>; + + // PC register + def PC : Register<"pc">; + + // Hardware registers + def HWR0 : MipsReg<0, "hwr_cpunum">; + def HWR1 : MipsReg<1, "hwr_synci_step">; + def HWR2 : MipsReg<2, "hwr_cc">; + def HWR3 : MipsReg<3, "hwr_ccres">; + + foreach I = 4-31 in + def HWR#I : MipsReg<#I, ""#I>; + + // Accum registers + foreach I = 0-3 in + def AC#I : ACCReg<#I, "ac"#I, + [!cast<Register>("LO"#I), !cast<Register>("HI"#I)]>; + + def AC0_64 : ACCReg<0, "ac0", [LO0_64, HI0_64]>; + + // DSP-ASE control register fields. + def DSPPos : Register<"">; + def DSPSCount : Register<"">; + def DSPCarry : Register<"">; + def DSPEFI : Register<"">; + def DSPOutFlag16_19 : Register<"">; + def DSPOutFlag20 : Register<"">; + def DSPOutFlag21 : Register<"">; + def DSPOutFlag22 : Register<"">; + def DSPOutFlag23 : Register<"">; + def DSPCCond : Register<"">; + + let SubRegIndices = [sub_dsp16_19, sub_dsp20, sub_dsp21, sub_dsp22, + sub_dsp23] in + def DSPOutFlag : RegisterWithSubRegs<"", [DSPOutFlag16_19, DSPOutFlag20, + DSPOutFlag21, DSPOutFlag22, + DSPOutFlag23]>; + + // MSA-ASE control registers. + def MSAIR : MipsReg<0, "0">; + def MSACSR : MipsReg<1, "1">; + def MSAAccess : MipsReg<2, "2">; + def MSASave : MipsReg<3, "3">; + def MSAModify : MipsReg<4, "4">; + def MSARequest : MipsReg<5, "5">; + def MSAMap : MipsReg<6, "6">; + def MSAUnmap : MipsReg<7, "7">; + + // 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">; + +} + +//===----------------------------------------------------------------------===// +// Register Classes +//===----------------------------------------------------------------------===// + +class GPR32Class<list<ValueType> regTypes> : + RegisterClass<"Mips", regTypes, 32, (add + // Reserved + ZERO, AT, + // Return Values and Arguments + V0, V1, A0, A1, A2, A3, + // Not preserved across procedure calls + T0, T1, T2, T3, T4, T5, T6, T7, + // Callee save + S0, S1, S2, S3, S4, S5, S6, S7, + // Not preserved across procedure calls + T8, T9, + // Reserved + K0, K1, GP, SP, FP, RA)>; + +def GPR32 : GPR32Class<[i32]>; +def DSPR : GPR32Class<[v4i8, v2i16]>; + +def GPRMM16 : RegisterClass<"Mips", [i32], 32, (add + // Callee save + S0, S1, + // Return Values and Arguments + V0, V1, A0, A1, A2, A3)>; + +def GPRMM16Zero : RegisterClass<"Mips", [i32], 32, (add + // Reserved + ZERO, + // Callee save + S1, + // Return Values and Arguments + V0, V1, A0, A1, A2, A3)>; + +def GPRMM16MoveP : RegisterClass<"Mips", [i32], 32, (add + // Reserved + ZERO, + // Callee save + S1, + // Return Values and Arguments + V0, V1, + // Callee save + S0, S2, S3, S4)>; + +def GPR64 : RegisterClass<"Mips", [i64], 64, (add +// Reserved + ZERO_64, AT_64, + // Return Values and Arguments + V0_64, V1_64, A0_64, A1_64, A2_64, A3_64, + // Not preserved across procedure calls + T0_64, T1_64, T2_64, T3_64, T4_64, T5_64, T6_64, T7_64, + // Callee save + S0_64, S1_64, S2_64, S3_64, S4_64, S5_64, S6_64, S7_64, + // Not preserved across procedure calls + T8_64, T9_64, + // Reserved + K0_64, K1_64, GP_64, SP_64, FP_64, RA_64)>; + +def CPU16Regs : RegisterClass<"Mips", [i32], 32, (add + // Return Values and Arguments + V0, V1, A0, A1, A2, A3, + // Callee save + S0, S1)>; + +def CPU16RegsPlusSP : RegisterClass<"Mips", [i32], 32, (add + // Return Values and Arguments + V0, V1, A0, A1, A2, A3, + // Callee save + S0, S1, + SP)>; + +def CPURAReg : RegisterClass<"Mips", [i32], 32, (add RA)>, Unallocatable; + +def CPUSPReg : RegisterClass<"Mips", [i32], 32, (add SP)>, Unallocatable; + +// 64bit fp: +// * FGR64 - 32 64-bit registers +// * AFGR64 - 16 32-bit even registers (32-bit FP Mode) +// +// 32bit fp: +// * FGR32 - 16 32-bit even registers +// * FGR32 - 32 32-bit registers (single float only mode) +def FGR32 : RegisterClass<"Mips", [f32], 32, (sequence "F%u", 0, 31)>; + +def FGRH32 : RegisterClass<"Mips", [f32], 32, (sequence "F_HI%u", 0, 31)>, + Unallocatable; + +def AFGR64 : RegisterClass<"Mips", [f64], 64, (add + // Return Values and Arguments + D0, D1, + // Not preserved across procedure calls + D2, D3, D4, D5, + // Return Values and Arguments + D6, D7, + // Not preserved across procedure calls + D8, D9, + // Callee save + D10, D11, D12, D13, D14, D15)>; + +def FGR64 : RegisterClass<"Mips", [f64], 64, (sequence "D%u_64", 0, 31)>; + +// Used to reserve odd registers when given -mattr=+nooddspreg +// FIXME: Remove double precision registers from this set. +def OddSP : RegisterClass<"Mips", [f32], 32, + (add (decimate (sequence "F%u", 1, 31), 2), + (decimate (sequence "F_HI%u", 1, 31), 2), + (decimate (sequence "D%u", 1, 15), 2), + (decimate (sequence "D%u_64", 1, 31), 2))>, + Unallocatable; + +// FP control registers. +def CCR : RegisterClass<"Mips", [i32], 32, (sequence "FCR%u", 0, 31)>, + Unallocatable; + +// FP condition code registers. +def FCC : RegisterClass<"Mips", [i32], 32, (sequence "FCC%u", 0, 7)>, + Unallocatable; + +// MIPS32r6/MIPS64r6 store FPU condition codes in normal FGR registers. +// This class allows us to represent this in codegen patterns. +def FGRCC : RegisterClass<"Mips", [i32], 32, (sequence "F%u", 0, 31)>; + +def MSA128B: RegisterClass<"Mips", [v16i8], 128, + (sequence "W%u", 0, 31)>; +def MSA128H: RegisterClass<"Mips", [v8i16, v8f16], 128, + (sequence "W%u", 0, 31)>; +def MSA128W: RegisterClass<"Mips", [v4i32, v4f32], 128, + (sequence "W%u", 0, 31)>; +def MSA128D: RegisterClass<"Mips", [v2i64, v2f64], 128, + (sequence "W%u", 0, 31)>; +def MSA128WEvens: RegisterClass<"Mips", [v4i32, v4f32], 128, + (decimate (sequence "W%u", 0, 31), 2)>; + +def MSACtrl: RegisterClass<"Mips", [i32], 32, (add + MSAIR, MSACSR, MSAAccess, MSASave, MSAModify, MSARequest, MSAMap, MSAUnmap)>; + +// Hi/Lo Registers +def LO32 : RegisterClass<"Mips", [i32], 32, (add LO0)>; +def HI32 : RegisterClass<"Mips", [i32], 32, (add HI0)>; +def LO32DSP : RegisterClass<"Mips", [i32], 32, (sequence "LO%u", 0, 3)>; +def HI32DSP : RegisterClass<"Mips", [i32], 32, (sequence "HI%u", 0, 3)>; +def LO64 : RegisterClass<"Mips", [i64], 64, (add LO0_64)>; +def HI64 : RegisterClass<"Mips", [i64], 64, (add HI0_64)>; + +// Hardware registers +def HWRegs : RegisterClass<"Mips", [i32], 32, (sequence "HWR%u", 0, 31)>, + Unallocatable; + +// Accumulator Registers +def ACC64 : RegisterClass<"Mips", [untyped], 64, (add AC0)> { + let Size = 64; +} + +def ACC128 : RegisterClass<"Mips", [untyped], 128, (add AC0_64)> { + let Size = 128; +} + +def ACC64DSP : RegisterClass<"Mips", [untyped], 64, (sequence "AC%u", 0, 3)> { + let Size = 64; +} + +def DSPCC : RegisterClass<"Mips", [v4i8, v2i16], 32, (add DSPCCond)>; + +// Coprocessor 0 registers. +def COP0 : RegisterClass<"Mips", [i32], 32, (sequence "COP0%u", 0, 31)>, + Unallocatable; + +// Coprocessor 2 registers. +def COP2 : RegisterClass<"Mips", [i32], 32, (sequence "COP2%u", 0, 31)>, + Unallocatable; + +// Coprocessor 3 registers. +def COP3 : RegisterClass<"Mips", [i32], 32, (sequence "COP3%u", 0, 31)>, + Unallocatable; + +// Octeon multiplier and product registers +def OCTEON_MPL : RegisterClass<"Mips", [i64], 64, (add MPL0, MPL1, MPL2)>, + Unallocatable; +def OCTEON_P : RegisterClass<"Mips", [i64], 64, (add P0, P1, P2)>, + Unallocatable; + +// Register Operands. + +class MipsAsmRegOperand : AsmOperandClass { + let ParserMethod = "parseAnyRegister"; +} + +def GPR64AsmOperand : MipsAsmRegOperand { + let Name = "GPR64AsmReg"; + let PredicateMethod = "isGPRAsmReg"; +} + +def GPR32AsmOperand : MipsAsmRegOperand { + let Name = "GPR32AsmReg"; + let PredicateMethod = "isGPRAsmReg"; +} + +def GPRMM16AsmOperand : MipsAsmRegOperand { + let Name = "GPRMM16AsmReg"; + let PredicateMethod = "isMM16AsmReg"; +} + +def GPRMM16AsmOperandZero : MipsAsmRegOperand { + let Name = "GPRMM16AsmRegZero"; + let PredicateMethod = "isMM16AsmRegZero"; +} + +def GPRMM16AsmOperandMoveP : MipsAsmRegOperand { + let Name = "GPRMM16AsmRegMoveP"; + let PredicateMethod = "isMM16AsmRegMoveP"; +} + +def ACC64DSPAsmOperand : MipsAsmRegOperand { + let Name = "ACC64DSPAsmReg"; + let PredicateMethod = "isACCAsmReg"; +} + +def HI32DSPAsmOperand : MipsAsmRegOperand { + let Name = "HI32DSPAsmReg"; + let PredicateMethod = "isACCAsmReg"; +} + +def LO32DSPAsmOperand : MipsAsmRegOperand { + let Name = "LO32DSPAsmReg"; + let PredicateMethod = "isACCAsmReg"; +} + +def CCRAsmOperand : MipsAsmRegOperand { + let Name = "CCRAsmReg"; +} + +def AFGR64AsmOperand : MipsAsmRegOperand { + let Name = "AFGR64AsmReg"; + let PredicateMethod = "isFGRAsmReg"; +} + +def FGR64AsmOperand : MipsAsmRegOperand { + let Name = "FGR64AsmReg"; + let PredicateMethod = "isFGRAsmReg"; +} + +def FGR32AsmOperand : MipsAsmRegOperand { + let Name = "FGR32AsmReg"; + let PredicateMethod = "isFGRAsmReg"; +} + +def FGRH32AsmOperand : MipsAsmRegOperand { + let Name = "FGRH32AsmReg"; + let PredicateMethod = "isFGRAsmReg"; +} + +def FCCRegsAsmOperand : MipsAsmRegOperand { + let Name = "FCCAsmReg"; +} + +def MSA128AsmOperand : MipsAsmRegOperand { + let Name = "MSA128AsmReg"; +} + +def MSACtrlAsmOperand : MipsAsmRegOperand { + let Name = "MSACtrlAsmReg"; +} + +def GPR32Opnd : RegisterOperand<GPR32> { + let ParserMatchClass = GPR32AsmOperand; +} + +def GPRMM16Opnd : RegisterOperand<GPRMM16> { + let ParserMatchClass = GPRMM16AsmOperand; +} + +def GPRMM16OpndZero : RegisterOperand<GPRMM16Zero> { + let ParserMatchClass = GPRMM16AsmOperandZero; +} + +def GPRMM16OpndMoveP : RegisterOperand<GPRMM16MoveP> { + let ParserMatchClass = GPRMM16AsmOperandMoveP; +} + +def GPR64Opnd : RegisterOperand<GPR64> { + let ParserMatchClass = GPR64AsmOperand; +} + +def DSPROpnd : RegisterOperand<DSPR> { + let ParserMatchClass = GPR32AsmOperand; +} + +def CCROpnd : RegisterOperand<CCR> { + let ParserMatchClass = CCRAsmOperand; +} + +def HWRegsAsmOperand : MipsAsmRegOperand { + let Name = "HWRegsAsmReg"; +} + +def COP0AsmOperand : MipsAsmRegOperand { + let Name = "COP0AsmReg"; +} + +def COP2AsmOperand : MipsAsmRegOperand { + let Name = "COP2AsmReg"; +} + +def COP3AsmOperand : MipsAsmRegOperand { + let Name = "COP3AsmReg"; +} + +def HWRegsOpnd : RegisterOperand<HWRegs> { + let ParserMatchClass = HWRegsAsmOperand; +} + +def AFGR64Opnd : RegisterOperand<AFGR64> { + let ParserMatchClass = AFGR64AsmOperand; +} + +def FGR64Opnd : RegisterOperand<FGR64> { + let ParserMatchClass = FGR64AsmOperand; +} + +def FGR32Opnd : RegisterOperand<FGR32> { + let ParserMatchClass = FGR32AsmOperand; +} + +def FGRCCOpnd : RegisterOperand<FGRCC> { + // The assembler doesn't use register classes so we can re-use + // FGR32AsmOperand. + let ParserMatchClass = FGR32AsmOperand; +} + +def FGRH32Opnd : RegisterOperand<FGRH32> { + let ParserMatchClass = FGRH32AsmOperand; +} + +def FCCRegsOpnd : RegisterOperand<FCC> { + let ParserMatchClass = FCCRegsAsmOperand; +} + +def LO32DSPOpnd : RegisterOperand<LO32DSP> { + let ParserMatchClass = LO32DSPAsmOperand; +} + +def HI32DSPOpnd : RegisterOperand<HI32DSP> { + let ParserMatchClass = HI32DSPAsmOperand; +} + +def ACC64DSPOpnd : RegisterOperand<ACC64DSP> { + let ParserMatchClass = ACC64DSPAsmOperand; +} + +def COP0Opnd : RegisterOperand<COP0> { + let ParserMatchClass = COP0AsmOperand; +} + +def COP2Opnd : RegisterOperand<COP2> { + let ParserMatchClass = COP2AsmOperand; +} + +def COP3Opnd : RegisterOperand<COP3> { + let ParserMatchClass = COP3AsmOperand; +} + +def MSA128BOpnd : RegisterOperand<MSA128B> { + let ParserMatchClass = MSA128AsmOperand; +} + +def MSA128HOpnd : RegisterOperand<MSA128H> { + let ParserMatchClass = MSA128AsmOperand; +} + +def MSA128WOpnd : RegisterOperand<MSA128W> { + let ParserMatchClass = MSA128AsmOperand; +} + +def MSA128DOpnd : RegisterOperand<MSA128D> { + let ParserMatchClass = MSA128AsmOperand; +} + +def MSA128CROpnd : RegisterOperand<MSACtrl> { + let ParserMatchClass = MSACtrlAsmOperand; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp b/contrib/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp new file mode 100644 index 0000000..a4abd62 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp @@ -0,0 +1,895 @@ +//===-- MipsSEFrameLowering.cpp - Mips32/64 Frame Information -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips32/64 implementation of TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#include "MipsSEFrameLowering.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsMachineFunction.h" +#include "MipsSEInstrInfo.h" +#include "MipsSubtarget.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetOptions.h" + +using namespace llvm; + +namespace { +typedef MachineBasicBlock::iterator Iter; + +static std::pair<unsigned, unsigned> getMFHiLoOpc(unsigned Src) { + if (Mips::ACC64RegClass.contains(Src)) + return std::make_pair((unsigned)Mips::PseudoMFHI, + (unsigned)Mips::PseudoMFLO); + + if (Mips::ACC64DSPRegClass.contains(Src)) + return std::make_pair((unsigned)Mips::MFHI_DSP, (unsigned)Mips::MFLO_DSP); + + if (Mips::ACC128RegClass.contains(Src)) + return std::make_pair((unsigned)Mips::PseudoMFHI64, + (unsigned)Mips::PseudoMFLO64); + + return std::make_pair(0, 0); +} + +/// Helper class to expand pseudos. +class ExpandPseudo { +public: + ExpandPseudo(MachineFunction &MF); + bool expand(); + +private: + bool expandInstr(MachineBasicBlock &MBB, Iter I); + void expandLoadCCond(MachineBasicBlock &MBB, Iter I); + void expandStoreCCond(MachineBasicBlock &MBB, Iter I); + void expandLoadACC(MachineBasicBlock &MBB, Iter I, unsigned RegSize); + void expandStoreACC(MachineBasicBlock &MBB, Iter I, unsigned MFHiOpc, + unsigned MFLoOpc, unsigned RegSize); + bool expandCopy(MachineBasicBlock &MBB, Iter I); + bool expandCopyACC(MachineBasicBlock &MBB, Iter I, unsigned MFHiOpc, + unsigned MFLoOpc); + bool expandBuildPairF64(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, bool FP64) const; + bool expandExtractElementF64(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, bool FP64) const; + + MachineFunction &MF; + MachineRegisterInfo &MRI; + const MipsSubtarget &Subtarget; + const MipsSEInstrInfo &TII; + const MipsRegisterInfo &RegInfo; +}; +} + +ExpandPseudo::ExpandPseudo(MachineFunction &MF_) + : MF(MF_), MRI(MF.getRegInfo()), + Subtarget(static_cast<const MipsSubtarget &>(MF.getSubtarget())), + TII(*static_cast<const MipsSEInstrInfo *>(Subtarget.getInstrInfo())), + RegInfo(*Subtarget.getRegisterInfo()) {} + +bool ExpandPseudo::expand() { + bool Expanded = false; + + for (MachineFunction::iterator BB = MF.begin(), BBEnd = MF.end(); + BB != BBEnd; ++BB) + for (Iter I = BB->begin(), End = BB->end(); I != End;) + Expanded |= expandInstr(*BB, I++); + + return Expanded; +} + +bool ExpandPseudo::expandInstr(MachineBasicBlock &MBB, Iter I) { + switch(I->getOpcode()) { + case Mips::LOAD_CCOND_DSP: + expandLoadCCond(MBB, I); + break; + case Mips::STORE_CCOND_DSP: + expandStoreCCond(MBB, I); + break; + case Mips::LOAD_ACC64: + case Mips::LOAD_ACC64DSP: + expandLoadACC(MBB, I, 4); + break; + case Mips::LOAD_ACC128: + expandLoadACC(MBB, I, 8); + break; + case Mips::STORE_ACC64: + expandStoreACC(MBB, I, Mips::PseudoMFHI, Mips::PseudoMFLO, 4); + break; + case Mips::STORE_ACC64DSP: + expandStoreACC(MBB, I, Mips::MFHI_DSP, Mips::MFLO_DSP, 4); + break; + case Mips::STORE_ACC128: + expandStoreACC(MBB, I, Mips::PseudoMFHI64, Mips::PseudoMFLO64, 8); + break; + case Mips::BuildPairF64: + if (expandBuildPairF64(MBB, I, false)) + MBB.erase(I); + return false; + case Mips::BuildPairF64_64: + if (expandBuildPairF64(MBB, I, true)) + MBB.erase(I); + return false; + case Mips::ExtractElementF64: + if (expandExtractElementF64(MBB, I, false)) + MBB.erase(I); + return false; + case Mips::ExtractElementF64_64: + if (expandExtractElementF64(MBB, I, true)) + MBB.erase(I); + return false; + case TargetOpcode::COPY: + if (!expandCopy(MBB, I)) + return false; + break; + default: + return false; + } + + MBB.erase(I); + return true; +} + +void ExpandPseudo::expandLoadCCond(MachineBasicBlock &MBB, Iter I) { + // load $vr, FI + // copy ccond, $vr + + assert(I->getOperand(0).isReg() && I->getOperand(1).isFI()); + + const TargetRegisterClass *RC = RegInfo.intRegClass(4); + unsigned VR = MRI.createVirtualRegister(RC); + unsigned Dst = I->getOperand(0).getReg(), FI = I->getOperand(1).getIndex(); + + TII.loadRegFromStack(MBB, I, VR, FI, RC, &RegInfo, 0); + BuildMI(MBB, I, I->getDebugLoc(), TII.get(TargetOpcode::COPY), Dst) + .addReg(VR, RegState::Kill); +} + +void ExpandPseudo::expandStoreCCond(MachineBasicBlock &MBB, Iter I) { + // copy $vr, ccond + // store $vr, FI + + assert(I->getOperand(0).isReg() && I->getOperand(1).isFI()); + + const TargetRegisterClass *RC = RegInfo.intRegClass(4); + unsigned VR = MRI.createVirtualRegister(RC); + unsigned Src = I->getOperand(0).getReg(), FI = I->getOperand(1).getIndex(); + + BuildMI(MBB, I, I->getDebugLoc(), TII.get(TargetOpcode::COPY), VR) + .addReg(Src, getKillRegState(I->getOperand(0).isKill())); + TII.storeRegToStack(MBB, I, VR, true, FI, RC, &RegInfo, 0); +} + +void ExpandPseudo::expandLoadACC(MachineBasicBlock &MBB, Iter I, + unsigned RegSize) { + // load $vr0, FI + // copy lo, $vr0 + // load $vr1, FI + 4 + // copy hi, $vr1 + + assert(I->getOperand(0).isReg() && I->getOperand(1).isFI()); + + const TargetRegisterClass *RC = RegInfo.intRegClass(RegSize); + unsigned VR0 = MRI.createVirtualRegister(RC); + unsigned VR1 = MRI.createVirtualRegister(RC); + unsigned Dst = I->getOperand(0).getReg(), FI = I->getOperand(1).getIndex(); + unsigned Lo = RegInfo.getSubReg(Dst, Mips::sub_lo); + unsigned Hi = RegInfo.getSubReg(Dst, Mips::sub_hi); + DebugLoc DL = I->getDebugLoc(); + const MCInstrDesc &Desc = TII.get(TargetOpcode::COPY); + + TII.loadRegFromStack(MBB, I, VR0, FI, RC, &RegInfo, 0); + BuildMI(MBB, I, DL, Desc, Lo).addReg(VR0, RegState::Kill); + TII.loadRegFromStack(MBB, I, VR1, FI, RC, &RegInfo, RegSize); + BuildMI(MBB, I, DL, Desc, Hi).addReg(VR1, RegState::Kill); +} + +void ExpandPseudo::expandStoreACC(MachineBasicBlock &MBB, Iter I, + unsigned MFHiOpc, unsigned MFLoOpc, + unsigned RegSize) { + // mflo $vr0, src + // store $vr0, FI + // mfhi $vr1, src + // store $vr1, FI + 4 + + assert(I->getOperand(0).isReg() && I->getOperand(1).isFI()); + + const TargetRegisterClass *RC = RegInfo.intRegClass(RegSize); + unsigned VR0 = MRI.createVirtualRegister(RC); + unsigned VR1 = MRI.createVirtualRegister(RC); + unsigned Src = I->getOperand(0).getReg(), FI = I->getOperand(1).getIndex(); + unsigned SrcKill = getKillRegState(I->getOperand(0).isKill()); + DebugLoc DL = I->getDebugLoc(); + + BuildMI(MBB, I, DL, TII.get(MFLoOpc), VR0).addReg(Src); + TII.storeRegToStack(MBB, I, VR0, true, FI, RC, &RegInfo, 0); + BuildMI(MBB, I, DL, TII.get(MFHiOpc), VR1).addReg(Src, SrcKill); + TII.storeRegToStack(MBB, I, VR1, true, FI, RC, &RegInfo, RegSize); +} + +bool ExpandPseudo::expandCopy(MachineBasicBlock &MBB, Iter I) { + unsigned Src = I->getOperand(1).getReg(); + std::pair<unsigned, unsigned> Opcodes = getMFHiLoOpc(Src); + + if (!Opcodes.first) + return false; + + return expandCopyACC(MBB, I, Opcodes.first, Opcodes.second); +} + +bool ExpandPseudo::expandCopyACC(MachineBasicBlock &MBB, Iter I, + unsigned MFHiOpc, unsigned MFLoOpc) { + // mflo $vr0, src + // copy dst_lo, $vr0 + // mfhi $vr1, src + // copy dst_hi, $vr1 + + unsigned Dst = I->getOperand(0).getReg(), Src = I->getOperand(1).getReg(); + unsigned VRegSize = RegInfo.getMinimalPhysRegClass(Dst)->getSize() / 2; + const TargetRegisterClass *RC = RegInfo.intRegClass(VRegSize); + unsigned VR0 = MRI.createVirtualRegister(RC); + unsigned VR1 = MRI.createVirtualRegister(RC); + unsigned SrcKill = getKillRegState(I->getOperand(1).isKill()); + unsigned DstLo = RegInfo.getSubReg(Dst, Mips::sub_lo); + unsigned DstHi = RegInfo.getSubReg(Dst, Mips::sub_hi); + DebugLoc DL = I->getDebugLoc(); + + BuildMI(MBB, I, DL, TII.get(MFLoOpc), VR0).addReg(Src); + BuildMI(MBB, I, DL, TII.get(TargetOpcode::COPY), DstLo) + .addReg(VR0, RegState::Kill); + BuildMI(MBB, I, DL, TII.get(MFHiOpc), VR1).addReg(Src, SrcKill); + BuildMI(MBB, I, DL, TII.get(TargetOpcode::COPY), DstHi) + .addReg(VR1, RegState::Kill); + return true; +} + +/// This method expands the same instruction that MipsSEInstrInfo:: +/// expandBuildPairF64 does, for the case when ABI is fpxx and mthc1 is not +/// available and the case where the ABI is FP64A. It is implemented here +/// because frame indexes are eliminated before MipsSEInstrInfo:: +/// expandBuildPairF64 is called. +bool ExpandPseudo::expandBuildPairF64(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + bool FP64) const { + // For fpxx and when mthc1 is not available, use: + // spill + reload via ldc1 + // + // The case where dmtc1 is available doesn't need to be handled here + // because it never creates a BuildPairF64 node. + // + // The FP64A ABI (fp64 with nooddspreg) must also use a spill/reload sequence + // for odd-numbered double precision values (because the lower 32-bits is + // transferred with mtc1 which is redirected to the upper half of the even + // register). Unfortunately, we have to make this decision before register + // allocation so for now we use a spill/reload sequence for all + // double-precision values in regardless of being an odd/even register. + if ((Subtarget.isABI_FPXX() && !Subtarget.hasMTHC1()) || + (FP64 && !Subtarget.useOddSPReg())) { + unsigned DstReg = I->getOperand(0).getReg(); + unsigned LoReg = I->getOperand(1).getReg(); + unsigned HiReg = I->getOperand(2).getReg(); + + // It should be impossible to have FGR64 on MIPS-II or MIPS32r1 (which are + // the cases where mthc1 is not available). 64-bit architectures and + // MIPS32r2 or later can use FGR64 though. + assert(Subtarget.isGP64bit() || Subtarget.hasMTHC1() || + !Subtarget.isFP64bit()); + + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + const TargetRegisterClass *RC2 = + FP64 ? &Mips::FGR64RegClass : &Mips::AFGR64RegClass; + + // We re-use the same spill slot each time so that the stack frame doesn't + // grow too much in functions with a large number of moves. + int FI = MF.getInfo<MipsFunctionInfo>()->getMoveF64ViaSpillFI(RC2); + if (!Subtarget.isLittle()) + std::swap(LoReg, HiReg); + TII.storeRegToStack(MBB, I, LoReg, I->getOperand(1).isKill(), FI, RC, + &RegInfo, 0); + TII.storeRegToStack(MBB, I, HiReg, I->getOperand(2).isKill(), FI, RC, + &RegInfo, 4); + TII.loadRegFromStack(MBB, I, DstReg, FI, RC2, &RegInfo, 0); + return true; + } + + return false; +} + +/// This method expands the same instruction that MipsSEInstrInfo:: +/// expandExtractElementF64 does, for the case when ABI is fpxx and mfhc1 is not +/// available and the case where the ABI is FP64A. It is implemented here +/// because frame indexes are eliminated before MipsSEInstrInfo:: +/// expandExtractElementF64 is called. +bool ExpandPseudo::expandExtractElementF64(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + bool FP64) const { + const MachineOperand &Op1 = I->getOperand(1); + const MachineOperand &Op2 = I->getOperand(2); + + if ((Op1.isReg() && Op1.isUndef()) || (Op2.isReg() && Op2.isUndef())) { + unsigned DstReg = I->getOperand(0).getReg(); + BuildMI(MBB, I, I->getDebugLoc(), TII.get(Mips::IMPLICIT_DEF), DstReg); + return true; + } + + // For fpxx and when mfhc1 is not available, use: + // spill + reload via ldc1 + // + // The case where dmfc1 is available doesn't need to be handled here + // because it never creates a ExtractElementF64 node. + // + // The FP64A ABI (fp64 with nooddspreg) must also use a spill/reload sequence + // for odd-numbered double precision values (because the lower 32-bits is + // transferred with mfc1 which is redirected to the upper half of the even + // register). Unfortunately, we have to make this decision before register + // allocation so for now we use a spill/reload sequence for all + // double-precision values in regardless of being an odd/even register. + + if ((Subtarget.isABI_FPXX() && !Subtarget.hasMTHC1()) || + (FP64 && !Subtarget.useOddSPReg())) { + unsigned DstReg = I->getOperand(0).getReg(); + unsigned SrcReg = Op1.getReg(); + unsigned N = Op2.getImm(); + int64_t Offset = 4 * (Subtarget.isLittle() ? N : (1 - N)); + + // It should be impossible to have FGR64 on MIPS-II or MIPS32r1 (which are + // the cases where mfhc1 is not available). 64-bit architectures and + // MIPS32r2 or later can use FGR64 though. + assert(Subtarget.isGP64bit() || Subtarget.hasMTHC1() || + !Subtarget.isFP64bit()); + + const TargetRegisterClass *RC = + FP64 ? &Mips::FGR64RegClass : &Mips::AFGR64RegClass; + const TargetRegisterClass *RC2 = &Mips::GPR32RegClass; + + // We re-use the same spill slot each time so that the stack frame doesn't + // grow too much in functions with a large number of moves. + int FI = MF.getInfo<MipsFunctionInfo>()->getMoveF64ViaSpillFI(RC); + TII.storeRegToStack(MBB, I, SrcReg, Op1.isKill(), FI, RC, &RegInfo, 0); + TII.loadRegFromStack(MBB, I, DstReg, FI, RC2, &RegInfo, Offset); + return true; + } + + return false; +} + +MipsSEFrameLowering::MipsSEFrameLowering(const MipsSubtarget &STI) + : MipsFrameLowering(STI, STI.stackAlignment()) {} + +void MipsSEFrameLowering::emitPrologue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported"); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + const MipsSEInstrInfo &TII = + *static_cast<const MipsSEInstrInfo *>(STI.getInstrInfo()); + const MipsRegisterInfo &RegInfo = + *static_cast<const MipsRegisterInfo *>(STI.getRegisterInfo()); + + MachineBasicBlock::iterator MBBI = MBB.begin(); + DebugLoc dl; + MipsABIInfo ABI = STI.getABI(); + unsigned SP = ABI.GetStackPtr(); + unsigned FP = ABI.GetFramePtr(); + unsigned ZERO = ABI.GetNullPtr(); + unsigned MOVE = ABI.GetGPRMoveOp(); + unsigned ADDiu = ABI.GetPtrAddiuOp(); + unsigned AND = ABI.IsN64() ? Mips::AND64 : Mips::AND; + + const TargetRegisterClass *RC = ABI.ArePtrs64bit() ? + &Mips::GPR64RegClass : &Mips::GPR32RegClass; + + // First, compute final stack size. + uint64_t StackSize = MFI->getStackSize(); + + // No need to allocate space on the stack. + if (StackSize == 0 && !MFI->adjustsStack()) return; + + MachineModuleInfo &MMI = MF.getMMI(); + const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); + MachineLocation DstML, SrcML; + + // Adjust stack. + TII.adjustStackPtr(SP, -StackSize, MBB, MBBI); + + // emit ".cfi_def_cfa_offset StackSize" + unsigned CFIIndex = MMI.addFrameInst( + MCCFIInstruction::createDefCfaOffset(nullptr, -StackSize)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + + if (MF.getFunction()->hasFnAttribute("interrupt")) + emitInterruptPrologueStub(MF, MBB); + + const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); + + if (CSI.size()) { + // Find the instruction past the last instruction that saves a callee-saved + // register to the stack. + for (unsigned i = 0; i < CSI.size(); ++i) + ++MBBI; + + // Iterate over list of callee-saved registers and emit .cfi_offset + // directives. + for (std::vector<CalleeSavedInfo>::const_iterator I = CSI.begin(), + E = CSI.end(); I != E; ++I) { + int64_t Offset = MFI->getObjectOffset(I->getFrameIdx()); + unsigned Reg = I->getReg(); + + // If Reg is a double precision register, emit two cfa_offsets, + // one for each of the paired single precision registers. + if (Mips::AFGR64RegClass.contains(Reg)) { + unsigned Reg0 = + MRI->getDwarfRegNum(RegInfo.getSubReg(Reg, Mips::sub_lo), true); + unsigned Reg1 = + MRI->getDwarfRegNum(RegInfo.getSubReg(Reg, Mips::sub_hi), true); + + if (!STI.isLittle()) + std::swap(Reg0, Reg1); + + unsigned CFIIndex = MMI.addFrameInst( + MCCFIInstruction::createOffset(nullptr, Reg0, Offset)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + + CFIIndex = MMI.addFrameInst( + MCCFIInstruction::createOffset(nullptr, Reg1, Offset + 4)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } else if (Mips::FGR64RegClass.contains(Reg)) { + unsigned Reg0 = MRI->getDwarfRegNum(Reg, true); + unsigned Reg1 = MRI->getDwarfRegNum(Reg, true) + 1; + + if (!STI.isLittle()) + std::swap(Reg0, Reg1); + + unsigned CFIIndex = MMI.addFrameInst( + MCCFIInstruction::createOffset(nullptr, Reg0, Offset)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + + CFIIndex = MMI.addFrameInst( + MCCFIInstruction::createOffset(nullptr, Reg1, Offset + 4)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } else { + // Reg is either in GPR32 or FGR32. + unsigned CFIIndex = MMI.addFrameInst(MCCFIInstruction::createOffset( + nullptr, MRI->getDwarfRegNum(Reg, 1), Offset)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } + } + } + + if (MipsFI->callsEhReturn()) { + // Insert instructions that spill eh data registers. + for (int I = 0; I < 4; ++I) { + if (!MBB.isLiveIn(ABI.GetEhDataReg(I))) + MBB.addLiveIn(ABI.GetEhDataReg(I)); + TII.storeRegToStackSlot(MBB, MBBI, ABI.GetEhDataReg(I), false, + MipsFI->getEhDataRegFI(I), RC, &RegInfo); + } + + // Emit .cfi_offset directives for eh data registers. + for (int I = 0; I < 4; ++I) { + int64_t Offset = MFI->getObjectOffset(MipsFI->getEhDataRegFI(I)); + unsigned Reg = MRI->getDwarfRegNum(ABI.GetEhDataReg(I), true); + unsigned CFIIndex = MMI.addFrameInst( + MCCFIInstruction::createOffset(nullptr, Reg, Offset)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } + } + + // if framepointer enabled, set it to point to the stack pointer. + if (hasFP(MF)) { + // Insert instruction "move $fp, $sp" at this location. + BuildMI(MBB, MBBI, dl, TII.get(MOVE), FP).addReg(SP).addReg(ZERO) + .setMIFlag(MachineInstr::FrameSetup); + + // emit ".cfi_def_cfa_register $fp" + unsigned CFIIndex = MMI.addFrameInst(MCCFIInstruction::createDefCfaRegister( + nullptr, MRI->getDwarfRegNum(FP, true))); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + + if (RegInfo.needsStackRealignment(MF)) { + // addiu $Reg, $zero, -MaxAlignment + // andi $sp, $sp, $Reg + unsigned VR = MF.getRegInfo().createVirtualRegister(RC); + assert(isInt<16>(MFI->getMaxAlignment()) && + "Function's alignment size requirement is not supported."); + int MaxAlign = - (signed) MFI->getMaxAlignment(); + + BuildMI(MBB, MBBI, dl, TII.get(ADDiu), VR).addReg(ZERO) .addImm(MaxAlign); + BuildMI(MBB, MBBI, dl, TII.get(AND), SP).addReg(SP).addReg(VR); + + if (hasBP(MF)) { + // move $s7, $sp + unsigned BP = STI.isABI_N64() ? Mips::S7_64 : Mips::S7; + BuildMI(MBB, MBBI, dl, TII.get(MOVE), BP) + .addReg(SP) + .addReg(ZERO); + } + } + } +} + +void MipsSEFrameLowering::emitInterruptPrologueStub( + MachineFunction &MF, MachineBasicBlock &MBB) const { + + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + MachineBasicBlock::iterator MBBI = MBB.begin(); + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + + // Report an error the target doesn't support Mips32r2 or later. + // The epilogue relies on the use of the "ehb" to clear execution + // hazards. Pre R2 Mips relies on an implementation defined number + // of "ssnop"s to clear the execution hazard. Support for ssnop hazard + // clearing is not provided so reject that configuration. + if (!STI.hasMips32r2()) + report_fatal_error( + "\"interrupt\" attribute is not supported on pre-MIPS32R2 or " + "MIPS16 targets."); + + // The GP register contains the "user" value, so we cannot perform + // any gp relative loads until we restore the "kernel" or "system" gp + // value. Until support is written we shall only accept the static + // relocation model. + if ((STI.getRelocationModel() != Reloc::Static)) + report_fatal_error("\"interrupt\" attribute is only supported for the " + "static relocation model on MIPS at the present time."); + + if (!STI.isABI_O32() || STI.hasMips64()) + report_fatal_error("\"interrupt\" attribute is only supported for the " + "O32 ABI on MIPS32R2+ at the present time."); + + // Perform ISR handling like GCC + StringRef IntKind = + MF.getFunction()->getFnAttribute("interrupt").getValueAsString(); + const TargetRegisterClass *PtrRC = &Mips::GPR32RegClass; + + // EIC interrupt handling needs to read the Cause register to disable + // interrupts. + if (IntKind == "eic") { + // Coprocessor registers are always live per se. + MBB.addLiveIn(Mips::COP013); + BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::MFC0), Mips::K0) + .addReg(Mips::COP013) + .addImm(0) + .setMIFlag(MachineInstr::FrameSetup); + + BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::EXT), Mips::K0) + .addReg(Mips::K0) + .addImm(10) + .addImm(6) + .setMIFlag(MachineInstr::FrameSetup); + } + + // Fetch and spill EPC + MBB.addLiveIn(Mips::COP014); + BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::MFC0), Mips::K1) + .addReg(Mips::COP014) + .addImm(0) + .setMIFlag(MachineInstr::FrameSetup); + + STI.getInstrInfo()->storeRegToStack(MBB, MBBI, Mips::K1, false, + MipsFI->getISRRegFI(0), PtrRC, + STI.getRegisterInfo(), 0); + + // Fetch and Spill Status + MBB.addLiveIn(Mips::COP012); + BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::MFC0), Mips::K1) + .addReg(Mips::COP012) + .addImm(0) + .setMIFlag(MachineInstr::FrameSetup); + + STI.getInstrInfo()->storeRegToStack(MBB, MBBI, Mips::K1, false, + MipsFI->getISRRegFI(1), PtrRC, + STI.getRegisterInfo(), 0); + + // Build the configuration for disabling lower priority interrupts. Non EIC + // interrupts need to be masked off with zero, EIC from the Cause register. + unsigned InsPosition = 8; + unsigned InsSize = 0; + unsigned SrcReg = Mips::ZERO; + + // If the interrupt we're tied to is the EIC, switch the source for the + // masking off interrupts to the cause register. + if (IntKind == "eic") { + SrcReg = Mips::K0; + InsPosition = 10; + InsSize = 6; + } else + InsSize = StringSwitch<unsigned>(IntKind) + .Case("sw0", 1) + .Case("sw1", 2) + .Case("hw0", 3) + .Case("hw1", 4) + .Case("hw2", 5) + .Case("hw3", 6) + .Case("hw4", 7) + .Case("hw5", 8) + .Default(0); + assert(InsSize != 0 && "Unknown interrupt type!"); + + BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::INS), Mips::K1) + .addReg(SrcReg) + .addImm(InsPosition) + .addImm(InsSize) + .addReg(Mips::K1) + .setMIFlag(MachineInstr::FrameSetup); + + // Mask off KSU, ERL, EXL + BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::INS), Mips::K1) + .addReg(Mips::ZERO) + .addImm(1) + .addImm(4) + .addReg(Mips::K1) + .setMIFlag(MachineInstr::FrameSetup); + + // Disable the FPU as we are not spilling those register sets. + if (!STI.useSoftFloat()) + BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::INS), Mips::K1) + .addReg(Mips::ZERO) + .addImm(29) + .addImm(1) + .addReg(Mips::K1) + .setMIFlag(MachineInstr::FrameSetup); + + // Set the new status + BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::MTC0), Mips::COP012) + .addReg(Mips::K1) + .addImm(0) + .setMIFlag(MachineInstr::FrameSetup); +} + +void MipsSEFrameLowering::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + const MipsSEInstrInfo &TII = + *static_cast<const MipsSEInstrInfo *>(STI.getInstrInfo()); + const MipsRegisterInfo &RegInfo = + *static_cast<const MipsRegisterInfo *>(STI.getRegisterInfo()); + + DebugLoc DL = MBBI->getDebugLoc(); + MipsABIInfo ABI = STI.getABI(); + unsigned SP = ABI.GetStackPtr(); + unsigned FP = ABI.GetFramePtr(); + unsigned ZERO = ABI.GetNullPtr(); + unsigned MOVE = ABI.GetGPRMoveOp(); + + // if framepointer enabled, restore the stack pointer. + if (hasFP(MF)) { + // Find the first instruction that restores a callee-saved register. + MachineBasicBlock::iterator I = MBBI; + + for (unsigned i = 0; i < MFI->getCalleeSavedInfo().size(); ++i) + --I; + + // Insert instruction "move $sp, $fp" at this location. + BuildMI(MBB, I, DL, TII.get(MOVE), SP).addReg(FP).addReg(ZERO); + } + + if (MipsFI->callsEhReturn()) { + const TargetRegisterClass *RC = + ABI.ArePtrs64bit() ? &Mips::GPR64RegClass : &Mips::GPR32RegClass; + + // Find first instruction that restores a callee-saved register. + MachineBasicBlock::iterator I = MBBI; + for (unsigned i = 0; i < MFI->getCalleeSavedInfo().size(); ++i) + --I; + + // Insert instructions that restore eh data registers. + for (int J = 0; J < 4; ++J) { + TII.loadRegFromStackSlot(MBB, I, ABI.GetEhDataReg(J), + MipsFI->getEhDataRegFI(J), RC, &RegInfo); + } + } + + if (MF.getFunction()->hasFnAttribute("interrupt")) + emitInterruptEpilogueStub(MF, MBB); + + // Get the number of bytes from FrameInfo + uint64_t StackSize = MFI->getStackSize(); + + if (!StackSize) + return; + + // Adjust stack. + TII.adjustStackPtr(SP, StackSize, MBB, MBBI); +} + +void MipsSEFrameLowering::emitInterruptEpilogueStub( + MachineFunction &MF, MachineBasicBlock &MBB) const { + + MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + + // Perform ISR handling like GCC + const TargetRegisterClass *PtrRC = &Mips::GPR32RegClass; + + // Disable Interrupts. + BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::DI), Mips::ZERO); + BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::EHB)); + + // Restore EPC + STI.getInstrInfo()->loadRegFromStackSlot(MBB, MBBI, Mips::K1, + MipsFI->getISRRegFI(0), PtrRC, + STI.getRegisterInfo()); + BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::MTC0), Mips::COP014) + .addReg(Mips::K1) + .addImm(0); + + // Restore Status + STI.getInstrInfo()->loadRegFromStackSlot(MBB, MBBI, Mips::K1, + MipsFI->getISRRegFI(1), PtrRC, + STI.getRegisterInfo()); + BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::MTC0), Mips::COP012) + .addReg(Mips::K1) + .addImm(0); +} + +int MipsSEFrameLowering::getFrameIndexReference(const MachineFunction &MF, + int FI, + unsigned &FrameReg) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsABIInfo ABI = STI.getABI(); + + if (MFI->isFixedObjectIndex(FI)) + FrameReg = hasFP(MF) ? ABI.GetFramePtr() : ABI.GetStackPtr(); + else + FrameReg = hasBP(MF) ? ABI.GetBasePtr() : ABI.GetStackPtr(); + + return MFI->getObjectOffset(FI) + MFI->getStackSize() - + getOffsetOfLocalArea() + MFI->getOffsetAdjustment(); +} + +bool MipsSEFrameLowering:: +spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const { + MachineFunction *MF = MBB.getParent(); + MachineBasicBlock *EntryBlock = &MF->front(); + const TargetInstrInfo &TII = *STI.getInstrInfo(); + + for (unsigned i = 0, e = CSI.size(); i != e; ++i) { + // Add the callee-saved register as live-in. Do not add if the register is + // RA and return address is taken, because it has already been added in + // method MipsTargetLowering::LowerRETURNADDR. + // It's killed at the spill, unless the register is RA and return address + // is taken. + unsigned Reg = CSI[i].getReg(); + bool IsRAAndRetAddrIsTaken = (Reg == Mips::RA || Reg == Mips::RA_64) + && MF->getFrameInfo()->isReturnAddressTaken(); + if (!IsRAAndRetAddrIsTaken) + EntryBlock->addLiveIn(Reg); + + // ISRs require HI/LO to be spilled into kernel registers to be then + // spilled to the stack frame. + bool IsLOHI = (Reg == Mips::LO0 || Reg == Mips::LO0_64 || + Reg == Mips::HI0 || Reg == Mips::HI0_64); + const Function *Func = MBB.getParent()->getFunction(); + if (IsLOHI && Func->hasFnAttribute("interrupt")) { + DebugLoc DL = MI->getDebugLoc(); + + unsigned Op = 0; + if (!STI.getABI().ArePtrs64bit()) { + Op = (Reg == Mips::HI0) ? Mips::MFHI : Mips::MFLO; + Reg = Mips::K0; + } else { + Op = (Reg == Mips::HI0) ? Mips::MFHI64 : Mips::MFLO64; + Reg = Mips::K0_64; + } + BuildMI(MBB, MI, DL, TII.get(Op), Mips::K0) + .setMIFlag(MachineInstr::FrameSetup); + } + + // Insert the spill to the stack frame. + bool IsKill = !IsRAAndRetAddrIsTaken; + const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); + TII.storeRegToStackSlot(*EntryBlock, MI, Reg, IsKill, + CSI[i].getFrameIdx(), RC, TRI); + } + + return true; +} + +bool +MipsSEFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + + // Reserve call frame if the size of the maximum call frame fits into 16-bit + // immediate field and there are no variable sized objects on the stack. + // Make sure the second register scavenger spill slot can be accessed with one + // instruction. + return isInt<16>(MFI->getMaxCallFrameSize() + getStackAlignment()) && + !MFI->hasVarSizedObjects(); +} + +/// Mark \p Reg and all registers aliasing it in the bitset. +static void setAliasRegs(MachineFunction &MF, BitVector &SavedRegs, + unsigned Reg) { + const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); + for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI) + SavedRegs.set(*AI); +} + +void MipsSEFrameLowering::determineCalleeSaves(MachineFunction &MF, + BitVector &SavedRegs, + RegScavenger *RS) const { + TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + MipsABIInfo ABI = STI.getABI(); + unsigned FP = ABI.GetFramePtr(); + unsigned BP = ABI.IsN64() ? Mips::S7_64 : Mips::S7; + + // Mark $fp as used if function has dedicated frame pointer. + if (hasFP(MF)) + setAliasRegs(MF, SavedRegs, FP); + // Mark $s7 as used if function has dedicated base pointer. + if (hasBP(MF)) + setAliasRegs(MF, SavedRegs, BP); + + // Create spill slots for eh data registers if function calls eh_return. + if (MipsFI->callsEhReturn()) + MipsFI->createEhDataRegsFI(); + + // Create spill slots for Coprocessor 0 registers if function is an ISR. + if (MipsFI->isISR()) + MipsFI->createISRRegFI(); + + // Expand pseudo instructions which load, store or copy accumulators. + // Add an emergency spill slot if a pseudo was expanded. + if (ExpandPseudo(MF).expand()) { + // The spill slot should be half the size of the accumulator. If target is + // mips64, it should be 64-bit, otherwise it should be 32-bt. + const TargetRegisterClass *RC = STI.hasMips64() ? + &Mips::GPR64RegClass : &Mips::GPR32RegClass; + int FI = MF.getFrameInfo()->CreateStackObject(RC->getSize(), + RC->getAlignment(), false); + RS->addScavengingFrameIndex(FI); + } + + // Set scavenging frame index if necessary. + uint64_t MaxSPOffset = MF.getInfo<MipsFunctionInfo>()->getIncomingArgSize() + + estimateStackSize(MF); + + if (isInt<16>(MaxSPOffset)) + return; + + const TargetRegisterClass *RC = + ABI.ArePtrs64bit() ? &Mips::GPR64RegClass : &Mips::GPR32RegClass; + int FI = MF.getFrameInfo()->CreateStackObject(RC->getSize(), + RC->getAlignment(), false); + RS->addScavengingFrameIndex(FI); +} + +const MipsFrameLowering * +llvm::createMipsSEFrameLowering(const MipsSubtarget &ST) { + return new MipsSEFrameLowering(ST); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsSEFrameLowering.h b/contrib/llvm/lib/Target/Mips/MipsSEFrameLowering.h new file mode 100644 index 0000000..63cd3ce --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSEFrameLowering.h @@ -0,0 +1,52 @@ +//===-- MipsSEFrameLowering.h - Mips32/64 frame lowering --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSSEFRAMELOWERING_H +#define LLVM_LIB_TARGET_MIPS_MIPSSEFRAMELOWERING_H + +#include "MipsFrameLowering.h" + +namespace llvm { + +class MipsSEFrameLowering : public MipsFrameLowering { +public: + explicit MipsSEFrameLowering(const MipsSubtarget &STI); + + /// emitProlog/emitEpilog - These methods insert prolog and epilog code into + /// the function. + void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + + int getFrameIndexReference(const MachineFunction &MF, int FI, + unsigned &FrameReg) const override; + + bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const override; + + bool hasReservedCallFrame(const MachineFunction &MF) const override; + + void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, + RegScavenger *RS) const override; + unsigned ehDataReg(unsigned I) const; + +private: + void emitInterruptEpilogueStub(MachineFunction &MF, + MachineBasicBlock &MBB) const; + void emitInterruptPrologueStub(MachineFunction &MF, + MachineBasicBlock &MBB) const; +}; +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp new file mode 100644 index 0000000..6f001ea --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp @@ -0,0 +1,1020 @@ +//===-- MipsSEISelDAGToDAG.cpp - A Dag to Dag Inst Selector for MipsSE ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Subclass of MipsDAGToDAGISel specialized for mips32/64. +// +//===----------------------------------------------------------------------===// + +#include "MipsSEISelDAGToDAG.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "Mips.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsMachineFunction.h" +#include "MipsRegisterInfo.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/IR/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/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +using namespace llvm; + +#define DEBUG_TYPE "mips-isel" + +bool MipsSEDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &static_cast<const MipsSubtarget &>(MF.getSubtarget()); + if (Subtarget->inMips16Mode()) + return false; + return MipsDAGToDAGISel::runOnMachineFunction(MF); +} + +void MipsSEDAGToDAGISel::addDSPCtrlRegOperands(bool IsDef, MachineInstr &MI, + MachineFunction &MF) { + MachineInstrBuilder MIB(MF, &MI); + unsigned Mask = MI.getOperand(1).getImm(); + unsigned Flag = IsDef ? RegState::ImplicitDefine : RegState::Implicit; + + if (Mask & 1) + MIB.addReg(Mips::DSPPos, Flag); + + if (Mask & 2) + MIB.addReg(Mips::DSPSCount, Flag); + + if (Mask & 4) + MIB.addReg(Mips::DSPCarry, Flag); + + if (Mask & 8) + MIB.addReg(Mips::DSPOutFlag, Flag); + + if (Mask & 16) + MIB.addReg(Mips::DSPCCond, Flag); + + if (Mask & 32) + MIB.addReg(Mips::DSPEFI, Flag); +} + +unsigned MipsSEDAGToDAGISel::getMSACtrlReg(const SDValue RegIdx) const { + switch (cast<ConstantSDNode>(RegIdx)->getZExtValue()) { + default: + llvm_unreachable("Could not map int to register"); + case 0: return Mips::MSAIR; + case 1: return Mips::MSACSR; + case 2: return Mips::MSAAccess; + case 3: return Mips::MSASave; + case 4: return Mips::MSAModify; + case 5: return Mips::MSARequest; + case 6: return Mips::MSAMap; + case 7: return Mips::MSAUnmap; + } +} + +bool MipsSEDAGToDAGISel::replaceUsesWithZeroReg(MachineRegisterInfo *MRI, + const MachineInstr& MI) { + unsigned DstReg = 0, ZeroReg = 0; + + // Check if MI is "addiu $dst, $zero, 0" or "daddiu $dst, $zero, 0". + if ((MI.getOpcode() == Mips::ADDiu) && + (MI.getOperand(1).getReg() == Mips::ZERO) && + (MI.getOperand(2).getImm() == 0)) { + DstReg = MI.getOperand(0).getReg(); + ZeroReg = Mips::ZERO; + } else if ((MI.getOpcode() == Mips::DADDiu) && + (MI.getOperand(1).getReg() == Mips::ZERO_64) && + (MI.getOperand(2).getImm() == 0)) { + DstReg = MI.getOperand(0).getReg(); + ZeroReg = Mips::ZERO_64; + } + + if (!DstReg) + return false; + + // Replace uses with ZeroReg. + for (MachineRegisterInfo::use_iterator U = MRI->use_begin(DstReg), + E = MRI->use_end(); U != E;) { + MachineOperand &MO = *U; + unsigned OpNo = U.getOperandNo(); + MachineInstr *MI = MO.getParent(); + ++U; + + // Do not replace if it is a phi's operand or is tied to def operand. + if (MI->isPHI() || MI->isRegTiedToDefOperand(OpNo) || MI->isPseudo()) + continue; + + // Also, we have to check that the register class of the operand + // contains the zero register. + if (!MRI->getRegClass(MO.getReg())->contains(ZeroReg)) + continue; + + MO.setReg(ZeroReg); + } + + return true; +} + +void MipsSEDAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) { + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + if (!MipsFI->globalBaseRegSet()) + return; + + MachineBasicBlock &MBB = MF.front(); + MachineBasicBlock::iterator I = MBB.begin(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); + DebugLoc DL; + unsigned V0, V1, GlobalBaseReg = MipsFI->getGlobalBaseReg(); + const TargetRegisterClass *RC; + const MipsABIInfo &ABI = static_cast<const MipsTargetMachine &>(TM).getABI(); + RC = (ABI.IsN64()) ? &Mips::GPR64RegClass : &Mips::GPR32RegClass; + + V0 = RegInfo.createVirtualRegister(RC); + V1 = RegInfo.createVirtualRegister(RC); + + if (ABI.IsN64()) { + MF.getRegInfo().addLiveIn(Mips::T9_64); + MBB.addLiveIn(Mips::T9_64); + + // lui $v0, %hi(%neg(%gp_rel(fname))) + // daddu $v1, $v0, $t9 + // daddiu $globalbasereg, $v1, %lo(%neg(%gp_rel(fname))) + const GlobalValue *FName = MF.getFunction(); + BuildMI(MBB, I, DL, TII.get(Mips::LUi64), V0) + .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI); + BuildMI(MBB, I, DL, TII.get(Mips::DADDu), V1).addReg(V0) + .addReg(Mips::T9_64); + BuildMI(MBB, I, DL, TII.get(Mips::DADDiu), GlobalBaseReg).addReg(V1) + .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO); + return; + } + + if (MF.getTarget().getRelocationModel() == Reloc::Static) { + // Set global register to __gnu_local_gp. + // + // lui $v0, %hi(__gnu_local_gp) + // addiu $globalbasereg, $v0, %lo(__gnu_local_gp) + BuildMI(MBB, I, DL, TII.get(Mips::LUi), V0) + .addExternalSymbol("__gnu_local_gp", MipsII::MO_ABS_HI); + BuildMI(MBB, I, DL, TII.get(Mips::ADDiu), GlobalBaseReg).addReg(V0) + .addExternalSymbol("__gnu_local_gp", MipsII::MO_ABS_LO); + return; + } + + MF.getRegInfo().addLiveIn(Mips::T9); + MBB.addLiveIn(Mips::T9); + + if (ABI.IsN32()) { + // lui $v0, %hi(%neg(%gp_rel(fname))) + // addu $v1, $v0, $t9 + // addiu $globalbasereg, $v1, %lo(%neg(%gp_rel(fname))) + const GlobalValue *FName = MF.getFunction(); + BuildMI(MBB, I, DL, TII.get(Mips::LUi), V0) + .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI); + BuildMI(MBB, I, DL, TII.get(Mips::ADDu), V1).addReg(V0).addReg(Mips::T9); + BuildMI(MBB, I, DL, TII.get(Mips::ADDiu), GlobalBaseReg).addReg(V1) + .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO); + return; + } + + assert(ABI.IsO32()); + + // For O32 ABI, the following instruction sequence is emitted to initialize + // the global base register: + // + // 0. lui $2, %hi(_gp_disp) + // 1. addiu $2, $2, %lo(_gp_disp) + // 2. addu $globalbasereg, $2, $t9 + // + // We emit only the last instruction here. + // + // GNU linker requires that the first two instructions appear at the beginning + // of a function and no instructions be inserted before or between them. + // The two instructions are emitted during lowering to MC layer in order to + // avoid any reordering. + // + // Register $2 (Mips::V0) is added to the list of live-in registers to ensure + // the value instruction 1 (addiu) defines is valid when instruction 2 (addu) + // reads it. + MF.getRegInfo().addLiveIn(Mips::V0); + MBB.addLiveIn(Mips::V0); + BuildMI(MBB, I, DL, TII.get(Mips::ADDu), GlobalBaseReg) + .addReg(Mips::V0).addReg(Mips::T9); +} + +void MipsSEDAGToDAGISel::processFunctionAfterISel(MachineFunction &MF) { + initGlobalBaseReg(MF); + + MachineRegisterInfo *MRI = &MF.getRegInfo(); + + for (MachineFunction::iterator MFI = MF.begin(), MFE = MF.end(); MFI != MFE; + ++MFI) + for (MachineBasicBlock::iterator I = MFI->begin(); I != MFI->end(); ++I) { + if (I->getOpcode() == Mips::RDDSP) + addDSPCtrlRegOperands(false, *I, MF); + else if (I->getOpcode() == Mips::WRDSP) + addDSPCtrlRegOperands(true, *I, MF); + else + replaceUsesWithZeroReg(MRI, *I); + } +} + +SDNode *MipsSEDAGToDAGISel::selectAddESubE(unsigned MOp, SDValue InFlag, + SDValue CmpLHS, SDLoc DL, + SDNode *Node) const { + unsigned Opc = InFlag.getOpcode(); (void)Opc; + + assert(((Opc == ISD::ADDC || Opc == ISD::ADDE) || + (Opc == ISD::SUBC || Opc == ISD::SUBE)) && + "(ADD|SUB)E flag operand must come from (ADD|SUB)C/E insn"); + + unsigned SLTuOp = Mips::SLTu, ADDuOp = Mips::ADDu; + if (Subtarget->isGP64bit()) { + SLTuOp = Mips::SLTu64; + ADDuOp = Mips::DADDu; + } + + SDValue Ops[] = { CmpLHS, InFlag.getOperand(1) }; + SDValue LHS = Node->getOperand(0), RHS = Node->getOperand(1); + EVT VT = LHS.getValueType(); + + SDNode *Carry = CurDAG->getMachineNode(SLTuOp, DL, VT, Ops); + + if (Subtarget->isGP64bit()) { + // On 64-bit targets, sltu produces an i64 but our backend currently says + // that SLTu64 produces an i32. We need to fix this in the long run but for + // now, just make the DAG type-correct by asserting the upper bits are zero. + Carry = CurDAG->getMachineNode(Mips::SUBREG_TO_REG, DL, VT, + CurDAG->getTargetConstant(0, DL, VT), + SDValue(Carry, 0), + CurDAG->getTargetConstant(Mips::sub_32, DL, + VT)); + } + + // Generate a second addition only if we know that RHS is not a + // constant-zero node. + SDNode *AddCarry = Carry; + ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS); + if (!C || C->getZExtValue()) + AddCarry = CurDAG->getMachineNode(ADDuOp, DL, VT, SDValue(Carry, 0), RHS); + + return CurDAG->SelectNodeTo(Node, MOp, VT, MVT::Glue, LHS, + 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, SDLoc(Addr), 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(), SDLoc(Addr), + 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 { + // if Address is FI, get the TargetFrameIndex. + if (selectAddrFrameIndex(Addr, Base, Offset)) + return true; + + // on PIC code Load GA + if (Addr.getOpcode() == MipsISD::Wrapper) { + Base = Addr.getOperand(0); + Offset = Addr.getOperand(1); + return true; + } + + if (TM.getRelocationModel() != Reloc::PIC_) { + if ((Addr.getOpcode() == ISD::TargetExternalSymbol || + Addr.getOpcode() == ISD::TargetGlobalAddress)) + return false; + } + + // Addresses of the form FI+const or FI|const + if (selectAddrFrameIndexOffset(Addr, Base, Offset, 16)) + return true; + + // Operand is a result from an ADD. + if (Addr.getOpcode() == ISD::ADD) { + // When loading from constant pools, load the lower address part in + // the instruction itself. Example, instead of: + // lui $2, %hi($CPI1_0) + // addiu $2, $2, %lo($CPI1_0) + // lwc1 $f0, 0($2) + // Generate: + // lui $2, %hi($CPI1_0) + // lwc1 $f0, %lo($CPI1_0)($2) + if (Addr.getOperand(1).getOpcode() == MipsISD::Lo || + Addr.getOperand(1).getOpcode() == MipsISD::GPRel) { + SDValue Opnd0 = Addr.getOperand(1).getOperand(0); + if (isa<ConstantPoolSDNode>(Opnd0) || isa<GlobalAddressSDNode>(Opnd0) || + isa<JumpTableSDNode>(Opnd0)) { + Base = Addr.getOperand(0); + Offset = Opnd0; + return true; + } + } + } + + return false; +} + +/// ComplexPattern used on MipsInstrInfo +/// Used on Mips Load/Store instructions +bool MipsSEDAGToDAGISel::selectAddrRegReg(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + // Operand is a result from an ADD. + if (Addr.getOpcode() == ISD::ADD) { + Base = Addr.getOperand(0); + Offset = Addr.getOperand(1); + return true; + } + + return false; +} + +bool MipsSEDAGToDAGISel::selectAddrDefault(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + Base = Addr; + Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), Addr.getValueType()); + return true; +} + +bool MipsSEDAGToDAGISel::selectIntAddr(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + return selectAddrRegImm(Addr, Base, Offset) || + selectAddrDefault(Addr, Base, Offset); +} + +bool MipsSEDAGToDAGISel::selectAddrRegImm9(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if (selectAddrFrameIndex(Addr, Base, Offset)) + return true; + + if (selectAddrFrameIndexOffset(Addr, Base, Offset, 9)) + return true; + + return false; +} + +bool MipsSEDAGToDAGISel::selectAddrRegImm10(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if (selectAddrFrameIndex(Addr, Base, Offset)) + return true; + + if (selectAddrFrameIndexOffset(Addr, Base, Offset, 10)) + return true; + + return false; +} + +/// 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; +} + +bool MipsSEDAGToDAGISel::selectAddrRegImm16(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if (selectAddrFrameIndex(Addr, Base, Offset)) + return true; + + if (selectAddrFrameIndexOffset(Addr, Base, Offset, 16)) + return true; + + return false; +} + +bool MipsSEDAGToDAGISel::selectIntAddrMM(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + return selectAddrRegImm12(Addr, Base, Offset) || + selectAddrDefault(Addr, Base, Offset); +} + +bool MipsSEDAGToDAGISel::selectIntAddrLSL2MM(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if (selectAddrFrameIndexOffset(Addr, Base, Offset, 7)) { + if (isa<FrameIndexSDNode>(Base)) + return false; + + if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Offset)) { + unsigned CnstOff = CN->getZExtValue(); + return (CnstOff == (CnstOff & 0x3c)); + } + + return false; + } + + // For all other cases where "lw" would be selected, don't select "lw16" + // because it would result in additional instructions to prepare operands. + if (selectAddrRegImm(Addr, Base, Offset)) + return false; + + return selectAddrDefault(Addr, Base, Offset); +} + +bool MipsSEDAGToDAGISel::selectIntAddrMSA(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if (selectAddrRegImm10(Addr, Base, Offset)) + return true; + + if (selectAddrDefault(Addr, Base, Offset)) + return true; + + return false; +} + +// Select constant vector splats. +// +// Returns true and sets Imm if: +// * MSA is enabled +// * N is a ISD::BUILD_VECTOR representing a constant splat +bool MipsSEDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm, + unsigned MinSizeInBits) const { + if (!Subtarget->hasMSA()) + return false; + + BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N); + + if (!Node) + return false; + + APInt SplatValue, SplatUndef; + unsigned SplatBitSize; + bool HasAnyUndefs; + + if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs, + MinSizeInBits, !Subtarget->isLittle())) + return false; + + Imm = SplatValue; + + return true; +} + +// Select constant vector splats. +// +// In addition to the requirements of selectVSplat(), this function returns +// true and sets Imm if: +// * The splat value is the same width as the elements of the vector +// * The splat value fits in an integer with the specified signed-ness and +// width. +// +// This function looks through ISD::BITCAST nodes. +// TODO: This might not be appropriate for big-endian MSA since BITCAST is +// sometimes a shuffle in big-endian mode. +// +// It's worth noting that this function is not used as part of the selection +// of ldi.[bhwd] since it does not permit using the wrong-typed ldi.[bhwd] +// instruction to achieve the desired bit pattern. ldi.[bhwd] is selected in +// MipsSEDAGToDAGISel::selectNode. +bool MipsSEDAGToDAGISel:: +selectVSplatCommon(SDValue N, SDValue &Imm, bool Signed, + unsigned ImmBitSize) const { + APInt ImmValue; + EVT EltTy = N->getValueType(0).getVectorElementType(); + + if (N->getOpcode() == ISD::BITCAST) + N = N->getOperand(0); + + if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) && + ImmValue.getBitWidth() == EltTy.getSizeInBits()) { + + if (( Signed && ImmValue.isSignedIntN(ImmBitSize)) || + (!Signed && ImmValue.isIntN(ImmBitSize))) { + Imm = CurDAG->getTargetConstant(ImmValue, SDLoc(N), EltTy); + return true; + } + } + + return false; +} + +// Select constant vector splats. +bool MipsSEDAGToDAGISel:: +selectVSplatUimm1(SDValue N, SDValue &Imm) const { + return selectVSplatCommon(N, Imm, false, 1); +} + +bool MipsSEDAGToDAGISel:: +selectVSplatUimm2(SDValue N, SDValue &Imm) const { + return selectVSplatCommon(N, Imm, false, 2); +} + +bool MipsSEDAGToDAGISel:: +selectVSplatUimm3(SDValue N, SDValue &Imm) const { + return selectVSplatCommon(N, Imm, false, 3); +} + +// Select constant vector splats. +bool MipsSEDAGToDAGISel:: +selectVSplatUimm4(SDValue N, SDValue &Imm) const { + return selectVSplatCommon(N, Imm, false, 4); +} + +// Select constant vector splats. +bool MipsSEDAGToDAGISel:: +selectVSplatUimm5(SDValue N, SDValue &Imm) const { + return selectVSplatCommon(N, Imm, false, 5); +} + +// Select constant vector splats. +bool MipsSEDAGToDAGISel:: +selectVSplatUimm6(SDValue N, SDValue &Imm) const { + return selectVSplatCommon(N, Imm, false, 6); +} + +// Select constant vector splats. +bool MipsSEDAGToDAGISel:: +selectVSplatUimm8(SDValue N, SDValue &Imm) const { + return selectVSplatCommon(N, Imm, false, 8); +} + +// Select constant vector splats. +bool MipsSEDAGToDAGISel:: +selectVSplatSimm5(SDValue N, SDValue &Imm) const { + return selectVSplatCommon(N, Imm, true, 5); +} + +// Select constant vector splats whose value is a power of 2. +// +// In addition to the requirements of selectVSplat(), this function returns +// true and sets Imm if: +// * The splat value is the same width as the elements of the vector +// * The splat value is a power of two. +// +// This function looks through ISD::BITCAST nodes. +// TODO: This might not be appropriate for big-endian MSA since BITCAST is +// sometimes a shuffle in big-endian mode. +bool MipsSEDAGToDAGISel::selectVSplatUimmPow2(SDValue N, SDValue &Imm) const { + APInt ImmValue; + EVT EltTy = N->getValueType(0).getVectorElementType(); + + if (N->getOpcode() == ISD::BITCAST) + N = N->getOperand(0); + + if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) && + ImmValue.getBitWidth() == EltTy.getSizeInBits()) { + int32_t Log2 = ImmValue.exactLogBase2(); + + if (Log2 != -1) { + Imm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy); + return true; + } + } + + return false; +} + +// Select constant vector splats whose value only has a consecutive sequence +// of left-most bits set (e.g. 0b11...1100...00). +// +// In addition to the requirements of selectVSplat(), this function returns +// true and sets Imm if: +// * The splat value is the same width as the elements of the vector +// * The splat value is a consecutive sequence of left-most bits. +// +// This function looks through ISD::BITCAST nodes. +// TODO: This might not be appropriate for big-endian MSA since BITCAST is +// sometimes a shuffle in big-endian mode. +bool MipsSEDAGToDAGISel::selectVSplatMaskL(SDValue N, SDValue &Imm) const { + APInt ImmValue; + EVT EltTy = N->getValueType(0).getVectorElementType(); + + if (N->getOpcode() == ISD::BITCAST) + N = N->getOperand(0); + + if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) && + ImmValue.getBitWidth() == EltTy.getSizeInBits()) { + // Extract the run of set bits starting with bit zero from the bitwise + // inverse of ImmValue, and test that the inverse of this is the same + // as the original value. + if (ImmValue == ~(~ImmValue & ~(~ImmValue + 1))) { + + Imm = CurDAG->getTargetConstant(ImmValue.countPopulation(), SDLoc(N), + EltTy); + return true; + } + } + + return false; +} + +// Select constant vector splats whose value only has a consecutive sequence +// of right-most bits set (e.g. 0b00...0011...11). +// +// In addition to the requirements of selectVSplat(), this function returns +// true and sets Imm if: +// * The splat value is the same width as the elements of the vector +// * The splat value is a consecutive sequence of right-most bits. +// +// This function looks through ISD::BITCAST nodes. +// TODO: This might not be appropriate for big-endian MSA since BITCAST is +// sometimes a shuffle in big-endian mode. +bool MipsSEDAGToDAGISel::selectVSplatMaskR(SDValue N, SDValue &Imm) const { + APInt ImmValue; + EVT EltTy = N->getValueType(0).getVectorElementType(); + + if (N->getOpcode() == ISD::BITCAST) + N = N->getOperand(0); + + if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) && + ImmValue.getBitWidth() == EltTy.getSizeInBits()) { + // Extract the run of set bits starting with bit zero, and test that the + // result is the same as the original value + if (ImmValue == (ImmValue & ~(ImmValue + 1))) { + Imm = CurDAG->getTargetConstant(ImmValue.countPopulation(), SDLoc(N), + EltTy); + return true; + } + } + + return false; +} + +bool MipsSEDAGToDAGISel::selectVSplatUimmInvPow2(SDValue N, + SDValue &Imm) const { + APInt ImmValue; + EVT EltTy = N->getValueType(0).getVectorElementType(); + + if (N->getOpcode() == ISD::BITCAST) + N = N->getOperand(0); + + if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) && + ImmValue.getBitWidth() == EltTy.getSizeInBits()) { + int32_t Log2 = (~ImmValue).exactLogBase2(); + + if (Log2 != -1) { + Imm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy); + return true; + } + } + + return false; +} + +std::pair<bool, SDNode*> MipsSEDAGToDAGISel::selectNode(SDNode *Node) { + unsigned Opcode = Node->getOpcode(); + SDLoc DL(Node); + + /// + // Instruction Selection not handled by the auto-generated + // tablegen selection should be handled here. + /// + SDNode *Result; + + switch(Opcode) { + default: break; + + case ISD::SUBE: { + SDValue InFlag = Node->getOperand(2); + unsigned Opc = Subtarget->isGP64bit() ? Mips::DSUBu : Mips::SUBu; + Result = selectAddESubE(Opc, InFlag, InFlag.getOperand(0), DL, Node); + return std::make_pair(true, Result); + } + + case ISD::ADDE: { + if (Subtarget->hasDSP()) // Select DSP instructions, ADDSC and ADDWC. + break; + SDValue InFlag = Node->getOperand(2); + unsigned Opc = Subtarget->isGP64bit() ? Mips::DADDu : Mips::ADDu; + Result = selectAddESubE(Opc, InFlag, InFlag.getValue(0), DL, Node); + return std::make_pair(true, Result); + } + + case ISD::ConstantFP: { + ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(Node); + if (Node->getValueType(0) == MVT::f64 && CN->isExactlyValue(+0.0)) { + if (Subtarget->isGP64bit()) { + SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, + Mips::ZERO_64, MVT::i64); + Result = CurDAG->getMachineNode(Mips::DMTC1, DL, MVT::f64, Zero); + } else if (Subtarget->isFP64bit()) { + SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, + Mips::ZERO, MVT::i32); + Result = CurDAG->getMachineNode(Mips::BuildPairF64_64, DL, MVT::f64, + Zero, Zero); + } else { + SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, + Mips::ZERO, MVT::i32); + Result = CurDAG->getMachineNode(Mips::BuildPairF64, DL, MVT::f64, Zero, + Zero); + } + + return std::make_pair(true, Result); + } + break; + } + + case ISD::Constant: { + const ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Node); + unsigned Size = CN->getValueSizeInBits(0); + + if (Size == 32) + break; + + MipsAnalyzeImmediate AnalyzeImm; + int64_t Imm = CN->getSExtValue(); + + const MipsAnalyzeImmediate::InstSeq &Seq = + AnalyzeImm.Analyze(Imm, Size, false); + + MipsAnalyzeImmediate::InstSeq::const_iterator Inst = Seq.begin(); + SDLoc DL(CN); + SDNode *RegOpnd; + SDValue ImmOpnd = CurDAG->getTargetConstant(SignExtend64<16>(Inst->ImmOpnd), + DL, MVT::i64); + + // The first instruction can be a LUi which is different from other + // instructions (ADDiu, ORI and SLL) in that it does not have a register + // operand. + if (Inst->Opc == Mips::LUi64) + RegOpnd = CurDAG->getMachineNode(Inst->Opc, DL, MVT::i64, ImmOpnd); + else + RegOpnd = + CurDAG->getMachineNode(Inst->Opc, DL, MVT::i64, + CurDAG->getRegister(Mips::ZERO_64, MVT::i64), + ImmOpnd); + + // The remaining instructions in the sequence are handled here. + for (++Inst; Inst != Seq.end(); ++Inst) { + ImmOpnd = CurDAG->getTargetConstant(SignExtend64<16>(Inst->ImmOpnd), DL, + MVT::i64); + RegOpnd = CurDAG->getMachineNode(Inst->Opc, DL, MVT::i64, + SDValue(RegOpnd, 0), ImmOpnd); + } + + return std::make_pair(true, RegOpnd); + } + + case ISD::INTRINSIC_W_CHAIN: { + switch (cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue()) { + default: + break; + + case Intrinsic::mips_cfcmsa: { + SDValue ChainIn = Node->getOperand(0); + SDValue RegIdx = Node->getOperand(2); + SDValue Reg = CurDAG->getCopyFromReg(ChainIn, DL, + getMSACtrlReg(RegIdx), MVT::i32); + return std::make_pair(true, Reg.getNode()); + } + } + break; + } + + case ISD::INTRINSIC_WO_CHAIN: { + switch (cast<ConstantSDNode>(Node->getOperand(0))->getZExtValue()) { + default: + break; + + case Intrinsic::mips_move_v: + // Like an assignment but will always produce a move.v even if + // unnecessary. + return std::make_pair(true, + CurDAG->getMachineNode(Mips::MOVE_V, DL, + Node->getValueType(0), + Node->getOperand(1))); + } + break; + } + + case ISD::INTRINSIC_VOID: { + switch (cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue()) { + default: + break; + + case Intrinsic::mips_ctcmsa: { + SDValue ChainIn = Node->getOperand(0); + SDValue RegIdx = Node->getOperand(2); + SDValue Value = Node->getOperand(3); + SDValue ChainOut = CurDAG->getCopyToReg(ChainIn, DL, + getMSACtrlReg(RegIdx), Value); + return std::make_pair(true, ChainOut.getNode()); + } + } + break; + } + + case MipsISD::ThreadPointer: { + EVT PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout()); + unsigned RdhwrOpc, DestReg; + + if (PtrVT == MVT::i32) { + RdhwrOpc = Mips::RDHWR; + DestReg = Mips::V1; + } else { + RdhwrOpc = Mips::RDHWR64; + DestReg = Mips::V1_64; + } + + SDNode *Rdhwr = + CurDAG->getMachineNode(RdhwrOpc, DL, + Node->getValueType(0), + CurDAG->getRegister(Mips::HWR29, MVT::i32)); + SDValue Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, DestReg, + SDValue(Rdhwr, 0)); + SDValue ResNode = CurDAG->getCopyFromReg(Chain, DL, DestReg, PtrVT); + ReplaceUses(SDValue(Node, 0), ResNode); + return std::make_pair(true, ResNode.getNode()); + } + + case ISD::BUILD_VECTOR: { + // Select appropriate ldi.[bhwd] instructions for constant splats of + // 128-bit when MSA is enabled. Fixup any register class mismatches that + // occur as a result. + // + // This allows the compiler to use a wider range of immediates than would + // otherwise be allowed. If, for example, v4i32 could only use ldi.h then + // it would not be possible to load { 0x01010101, 0x01010101, 0x01010101, + // 0x01010101 } without using a constant pool. This would be sub-optimal + // when // 'ldi.b wd, 1' is capable of producing that bit-pattern in the + // same set/ of registers. Similarly, ldi.h isn't capable of producing { + // 0x00000000, 0x00000001, 0x00000000, 0x00000001 } but 'ldi.d wd, 1' can. + + BuildVectorSDNode *BVN = cast<BuildVectorSDNode>(Node); + APInt SplatValue, SplatUndef; + unsigned SplatBitSize; + bool HasAnyUndefs; + unsigned LdiOp; + EVT ResVecTy = BVN->getValueType(0); + EVT ViaVecTy; + + if (!Subtarget->hasMSA() || !BVN->getValueType(0).is128BitVector()) + return std::make_pair(false, nullptr); + + if (!BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, + HasAnyUndefs, 8, + !Subtarget->isLittle())) + return std::make_pair(false, nullptr); + + switch (SplatBitSize) { + default: + return std::make_pair(false, nullptr); + case 8: + LdiOp = Mips::LDI_B; + ViaVecTy = MVT::v16i8; + break; + case 16: + LdiOp = Mips::LDI_H; + ViaVecTy = MVT::v8i16; + break; + case 32: + LdiOp = Mips::LDI_W; + ViaVecTy = MVT::v4i32; + break; + case 64: + LdiOp = Mips::LDI_D; + ViaVecTy = MVT::v2i64; + break; + } + + if (!SplatValue.isSignedIntN(10)) + return std::make_pair(false, nullptr); + + SDValue Imm = CurDAG->getTargetConstant(SplatValue, DL, + ViaVecTy.getVectorElementType()); + + SDNode *Res = CurDAG->getMachineNode(LdiOp, DL, ViaVecTy, Imm); + + if (ResVecTy != ViaVecTy) { + // If LdiOp is writing to a different register class to ResVecTy, then + // fix it up here. This COPY_TO_REGCLASS should never cause a move.v + // since the source and destination register sets contain the same + // registers. + const TargetLowering *TLI = getTargetLowering(); + MVT ResVecTySimple = ResVecTy.getSimpleVT(); + const TargetRegisterClass *RC = TLI->getRegClassFor(ResVecTySimple); + Res = CurDAG->getMachineNode(Mips::COPY_TO_REGCLASS, DL, + ResVecTy, SDValue(Res, 0), + CurDAG->getTargetConstant(RC->getID(), DL, + MVT::i32)); + } + + return std::make_pair(true, Res); + } + + } + + return std::make_pair(false, nullptr); +} + +bool MipsSEDAGToDAGISel:: +SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, + std::vector<SDValue> &OutOps) { + SDValue Base, Offset; + + switch(ConstraintID) { + default: + llvm_unreachable("Unexpected asm memory constraint"); + // All memory constraints can at least accept raw pointers. + case InlineAsm::Constraint_i: + OutOps.push_back(Op); + OutOps.push_back(CurDAG->getTargetConstant(0, SDLoc(Op), MVT::i32)); + return false; + case InlineAsm::Constraint_m: + if (selectAddrRegImm16(Op, Base, Offset)) { + OutOps.push_back(Base); + OutOps.push_back(Offset); + return false; + } + OutOps.push_back(Op); + OutOps.push_back(CurDAG->getTargetConstant(0, SDLoc(Op), MVT::i32)); + return false; + case InlineAsm::Constraint_R: + // The 'R' constraint is supposed to be much more complicated than this. + // However, it's becoming less useful due to architectural changes and + // ought to be replaced by other constraints such as 'ZC'. + // For now, support 9-bit signed offsets which is supportable by all + // subtargets for all instructions. + if (selectAddrRegImm9(Op, Base, Offset)) { + OutOps.push_back(Base); + OutOps.push_back(Offset); + return false; + } + OutOps.push_back(Op); + OutOps.push_back(CurDAG->getTargetConstant(0, SDLoc(Op), MVT::i32)); + return false; + case InlineAsm::Constraint_ZC: + // ZC matches whatever the pref, ll, and sc instructions can handle for the + // given subtarget. + if (Subtarget->inMicroMipsMode()) { + // On microMIPS, they can handle 12-bit offsets. + if (selectAddrRegImm12(Op, Base, Offset)) { + OutOps.push_back(Base); + OutOps.push_back(Offset); + return false; + } + } else if (Subtarget->hasMips32r6()) { + // On MIPS32r6/MIPS64r6, they can only handle 9-bit offsets. + if (selectAddrRegImm9(Op, Base, Offset)) { + OutOps.push_back(Base); + OutOps.push_back(Offset); + return false; + } + } else if (selectAddrRegImm16(Op, Base, Offset)) { + // Prior to MIPS32r6/MIPS64r6, they can handle 16-bit offsets. + OutOps.push_back(Base); + OutOps.push_back(Offset); + return false; + } + // In all cases, 0-bit offsets are acceptable. + OutOps.push_back(Op); + OutOps.push_back(CurDAG->getTargetConstant(0, SDLoc(Op), MVT::i32)); + return false; + } + return true; +} + +FunctionPass *llvm::createMipsSEISelDag(MipsTargetMachine &TM) { + return new MipsSEDAGToDAGISel(TM); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.h b/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.h new file mode 100644 index 0000000..a894034 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.h @@ -0,0 +1,131 @@ +//===-- MipsSEISelDAGToDAG.h - A Dag to Dag Inst Selector for MipsSE -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Subclass of MipsDAGToDAGISel specialized for mips32/64. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSSEISELDAGTODAG_H +#define LLVM_LIB_TARGET_MIPS_MIPSSEISELDAGTODAG_H + +#include "MipsISelDAGToDAG.h" + +namespace llvm { + +class MipsSEDAGToDAGISel : public MipsDAGToDAGISel { + +public: + explicit MipsSEDAGToDAGISel(MipsTargetMachine &TM) : MipsDAGToDAGISel(TM) {} + +private: + + bool runOnMachineFunction(MachineFunction &MF) override; + + void addDSPCtrlRegOperands(bool IsDef, MachineInstr &MI, + MachineFunction &MF); + + unsigned getMSACtrlReg(const SDValue RegIdx) const; + + bool replaceUsesWithZeroReg(MachineRegisterInfo *MRI, const MachineInstr&); + + std::pair<SDNode*, SDNode*> selectMULT(SDNode *N, unsigned Opc, SDLoc dl, + EVT Ty, bool HasLo, bool HasHi); + + SDNode *selectAddESubE(unsigned MOp, SDValue InFlag, SDValue CmpLHS, + SDLoc DL, SDNode *Node) const; + + bool selectAddrFrameIndex(SDValue Addr, SDValue &Base, SDValue &Offset) const; + bool selectAddrFrameIndexOffset(SDValue Addr, SDValue &Base, SDValue &Offset, + unsigned OffsetBits) const; + + bool selectAddrRegImm(SDValue Addr, SDValue &Base, + SDValue &Offset) const override; + + bool selectAddrRegReg(SDValue Addr, SDValue &Base, + SDValue &Offset) const override; + + bool selectAddrDefault(SDValue Addr, SDValue &Base, + SDValue &Offset) const override; + + bool selectIntAddr(SDValue Addr, SDValue &Base, + SDValue &Offset) const override; + + bool selectAddrRegImm9(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + bool selectAddrRegImm10(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + bool selectAddrRegImm12(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + bool selectAddrRegImm16(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + bool selectIntAddrMM(SDValue Addr, SDValue &Base, + SDValue &Offset) const override; + + bool selectIntAddrLSL2MM(SDValue Addr, SDValue &Base, + SDValue &Offset) const override; + + bool selectIntAddrMSA(SDValue Addr, SDValue &Base, + SDValue &Offset) const override; + + /// \brief Select constant vector splats. + bool selectVSplat(SDNode *N, APInt &Imm, + unsigned MinSizeInBits) const override; + /// \brief Select constant vector splats whose value fits in a given integer. + bool selectVSplatCommon(SDValue N, SDValue &Imm, bool Signed, + unsigned ImmBitSize) const; + /// \brief Select constant vector splats whose value fits in a uimm1. + bool selectVSplatUimm1(SDValue N, SDValue &Imm) const override; + /// \brief Select constant vector splats whose value fits in a uimm2. + bool selectVSplatUimm2(SDValue N, SDValue &Imm) const override; + /// \brief Select constant vector splats whose value fits in a uimm3. + bool selectVSplatUimm3(SDValue N, SDValue &Imm) const override; + /// \brief Select constant vector splats whose value fits in a uimm4. + bool selectVSplatUimm4(SDValue N, SDValue &Imm) const override; + /// \brief Select constant vector splats whose value fits in a uimm5. + bool selectVSplatUimm5(SDValue N, SDValue &Imm) const override; + /// \brief Select constant vector splats whose value fits in a uimm6. + bool selectVSplatUimm6(SDValue N, SDValue &Imm) const override; + /// \brief Select constant vector splats whose value fits in a uimm8. + bool selectVSplatUimm8(SDValue N, SDValue &Imm) const override; + /// \brief Select constant vector splats whose value fits in a simm5. + bool selectVSplatSimm5(SDValue N, SDValue &Imm) const override; + /// \brief Select constant vector splats whose value is a power of 2. + bool selectVSplatUimmPow2(SDValue N, SDValue &Imm) const override; + /// \brief Select constant vector splats whose value is the inverse of a + /// power of 2. + bool selectVSplatUimmInvPow2(SDValue N, SDValue &Imm) const override; + /// \brief Select constant vector splats whose value is a run of set bits + /// ending at the most significant bit + bool selectVSplatMaskL(SDValue N, SDValue &Imm) const override; + /// \brief Select constant vector splats whose value is a run of set bits + /// starting at bit zero. + bool selectVSplatMaskR(SDValue N, SDValue &Imm) const override; + + std::pair<bool, SDNode*> selectNode(SDNode *Node) override; + + void processFunctionAfterISel(MachineFunction &MF) override; + + // Insert instructions to initialize the global base register in the + // first MBB of the function. + void initGlobalBaseReg(MachineFunction &MF); + + bool SelectInlineAsmMemoryOperand(const SDValue &Op, + unsigned ConstraintID, + std::vector<SDValue> &OutOps) override; +}; + +FunctionPass *createMipsSEISelDag(MipsTargetMachine &TM); + +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.cpp b/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.cpp new file mode 100644 index 0000000..efe22fb --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.cpp @@ -0,0 +1,3427 @@ +//===-- MipsSEISelLowering.cpp - MipsSE DAG Lowering Interface --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Subclass of MipsTargetLowering specialized for mips32/64. +// +//===----------------------------------------------------------------------===// +#include "MipsSEISelLowering.h" +#include "MipsMachineFunction.h" +#include "MipsRegisterInfo.h" +#include "MipsTargetMachine.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetInstrInfo.h" + +using namespace llvm; + +#define DEBUG_TYPE "mips-isel" + +static cl::opt<bool> +EnableMipsTailCalls("enable-mips-tail-calls", cl::Hidden, + cl::desc("MIPS: Enable tail calls."), cl::init(false)); + +static cl::opt<bool> NoDPLoadStore("mno-ldc1-sdc1", cl::init(false), + cl::desc("Expand double precision loads and " + "stores to their single precision " + "counterparts")); + +MipsSETargetLowering::MipsSETargetLowering(const MipsTargetMachine &TM, + const MipsSubtarget &STI) + : MipsTargetLowering(TM, STI) { + // Set up the register classes + addRegisterClass(MVT::i32, &Mips::GPR32RegClass); + + if (Subtarget.isGP64bit()) + addRegisterClass(MVT::i64, &Mips::GPR64RegClass); + + if (Subtarget.hasDSP() || Subtarget.hasMSA()) { + // Expand all truncating stores and extending loads. + for (MVT VT0 : MVT::vector_valuetypes()) { + for (MVT VT1 : MVT::vector_valuetypes()) { + setTruncStoreAction(VT0, VT1, Expand); + setLoadExtAction(ISD::SEXTLOAD, VT0, VT1, Expand); + setLoadExtAction(ISD::ZEXTLOAD, VT0, VT1, Expand); + setLoadExtAction(ISD::EXTLOAD, VT0, VT1, Expand); + } + } + } + + if (Subtarget.hasDSP()) { + MVT::SimpleValueType VecTys[2] = {MVT::v2i16, MVT::v4i8}; + + for (unsigned i = 0; i < array_lengthof(VecTys); ++i) { + addRegisterClass(VecTys[i], &Mips::DSPRRegClass); + + // Expand all builtin opcodes. + for (unsigned Opc = 0; Opc < ISD::BUILTIN_OP_END; ++Opc) + setOperationAction(Opc, VecTys[i], Expand); + + setOperationAction(ISD::ADD, VecTys[i], Legal); + setOperationAction(ISD::SUB, VecTys[i], Legal); + setOperationAction(ISD::LOAD, VecTys[i], Legal); + setOperationAction(ISD::STORE, VecTys[i], Legal); + setOperationAction(ISD::BITCAST, VecTys[i], Legal); + } + + setTargetDAGCombine(ISD::SHL); + setTargetDAGCombine(ISD::SRA); + setTargetDAGCombine(ISD::SRL); + setTargetDAGCombine(ISD::SETCC); + setTargetDAGCombine(ISD::VSELECT); + } + + if (Subtarget.hasDSPR2()) + setOperationAction(ISD::MUL, MVT::v2i16, Legal); + + if (Subtarget.hasMSA()) { + addMSAIntType(MVT::v16i8, &Mips::MSA128BRegClass); + addMSAIntType(MVT::v8i16, &Mips::MSA128HRegClass); + addMSAIntType(MVT::v4i32, &Mips::MSA128WRegClass); + addMSAIntType(MVT::v2i64, &Mips::MSA128DRegClass); + addMSAFloatType(MVT::v8f16, &Mips::MSA128HRegClass); + addMSAFloatType(MVT::v4f32, &Mips::MSA128WRegClass); + addMSAFloatType(MVT::v2f64, &Mips::MSA128DRegClass); + + setTargetDAGCombine(ISD::AND); + setTargetDAGCombine(ISD::OR); + setTargetDAGCombine(ISD::SRA); + setTargetDAGCombine(ISD::VSELECT); + setTargetDAGCombine(ISD::XOR); + } + + if (!Subtarget.useSoftFloat()) { + addRegisterClass(MVT::f32, &Mips::FGR32RegClass); + + // When dealing with single precision only, use libcalls + if (!Subtarget.isSingleFloat()) { + if (Subtarget.isFP64bit()) + addRegisterClass(MVT::f64, &Mips::FGR64RegClass); + else + addRegisterClass(MVT::f64, &Mips::AFGR64RegClass); + } + } + + setOperationAction(ISD::SMUL_LOHI, MVT::i32, Custom); + setOperationAction(ISD::UMUL_LOHI, MVT::i32, Custom); + setOperationAction(ISD::MULHS, MVT::i32, Custom); + setOperationAction(ISD::MULHU, MVT::i32, Custom); + + if (Subtarget.hasCnMips()) + setOperationAction(ISD::MUL, MVT::i64, Legal); + else if (Subtarget.isGP64bit()) + setOperationAction(ISD::MUL, MVT::i64, Custom); + + if (Subtarget.isGP64bit()) { + setOperationAction(ISD::SMUL_LOHI, MVT::i64, Custom); + setOperationAction(ISD::UMUL_LOHI, MVT::i64, Custom); + setOperationAction(ISD::MULHS, MVT::i64, Custom); + setOperationAction(ISD::MULHU, MVT::i64, Custom); + setOperationAction(ISD::SDIVREM, MVT::i64, Custom); + setOperationAction(ISD::UDIVREM, MVT::i64, Custom); + } + + setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::i64, Custom); + setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i64, Custom); + + setOperationAction(ISD::SDIVREM, MVT::i32, Custom); + setOperationAction(ISD::UDIVREM, MVT::i32, Custom); + setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom); + setOperationAction(ISD::LOAD, MVT::i32, Custom); + setOperationAction(ISD::STORE, MVT::i32, Custom); + + setTargetDAGCombine(ISD::ADDE); + setTargetDAGCombine(ISD::SUBE); + setTargetDAGCombine(ISD::MUL); + + setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); + setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom); + setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom); + + if (NoDPLoadStore) { + setOperationAction(ISD::LOAD, MVT::f64, Custom); + setOperationAction(ISD::STORE, MVT::f64, Custom); + } + + if (Subtarget.hasMips32r6()) { + // MIPS32r6 replaces the accumulator-based multiplies with a three register + // instruction + setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::MUL, MVT::i32, Legal); + setOperationAction(ISD::MULHS, MVT::i32, Legal); + setOperationAction(ISD::MULHU, MVT::i32, Legal); + + // MIPS32r6 replaces the accumulator-based division/remainder with separate + // three register division and remainder instructions. + setOperationAction(ISD::SDIVREM, MVT::i32, Expand); + setOperationAction(ISD::UDIVREM, MVT::i32, Expand); + setOperationAction(ISD::SDIV, MVT::i32, Legal); + setOperationAction(ISD::UDIV, MVT::i32, Legal); + setOperationAction(ISD::SREM, MVT::i32, Legal); + setOperationAction(ISD::UREM, MVT::i32, Legal); + + // MIPS32r6 replaces conditional moves with an equivalent that removes the + // need for three GPR read ports. + setOperationAction(ISD::SETCC, MVT::i32, Legal); + setOperationAction(ISD::SELECT, MVT::i32, Legal); + setOperationAction(ISD::SELECT_CC, MVT::i32, Expand); + + setOperationAction(ISD::SETCC, MVT::f32, Legal); + setOperationAction(ISD::SELECT, MVT::f32, Legal); + setOperationAction(ISD::SELECT_CC, MVT::f32, Expand); + + assert(Subtarget.isFP64bit() && "FR=1 is required for MIPS32r6"); + setOperationAction(ISD::SETCC, MVT::f64, Legal); + setOperationAction(ISD::SELECT, MVT::f64, Legal); + setOperationAction(ISD::SELECT_CC, MVT::f64, Expand); + + setOperationAction(ISD::BRCOND, MVT::Other, Legal); + + // Floating point > and >= are supported via < and <= + setCondCodeAction(ISD::SETOGE, MVT::f32, Expand); + setCondCodeAction(ISD::SETOGT, MVT::f32, Expand); + setCondCodeAction(ISD::SETUGE, MVT::f32, Expand); + setCondCodeAction(ISD::SETUGT, MVT::f32, Expand); + + setCondCodeAction(ISD::SETOGE, MVT::f64, Expand); + setCondCodeAction(ISD::SETOGT, MVT::f64, Expand); + setCondCodeAction(ISD::SETUGE, MVT::f64, Expand); + setCondCodeAction(ISD::SETUGT, MVT::f64, Expand); + } + + if (Subtarget.hasMips64r6()) { + // MIPS64r6 replaces the accumulator-based multiplies with a three register + // instruction + setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i64, Expand); + setOperationAction(ISD::MUL, MVT::i64, Legal); + setOperationAction(ISD::MULHS, MVT::i64, Legal); + setOperationAction(ISD::MULHU, MVT::i64, Legal); + + // MIPS32r6 replaces the accumulator-based division/remainder with separate + // three register division and remainder instructions. + setOperationAction(ISD::SDIVREM, MVT::i64, Expand); + setOperationAction(ISD::UDIVREM, MVT::i64, Expand); + setOperationAction(ISD::SDIV, MVT::i64, Legal); + setOperationAction(ISD::UDIV, MVT::i64, Legal); + setOperationAction(ISD::SREM, MVT::i64, Legal); + setOperationAction(ISD::UREM, MVT::i64, Legal); + + // MIPS64r6 replaces conditional moves with an equivalent that removes the + // need for three GPR read ports. + setOperationAction(ISD::SETCC, MVT::i64, Legal); + setOperationAction(ISD::SELECT, MVT::i64, Legal); + setOperationAction(ISD::SELECT_CC, MVT::i64, Expand); + } + + computeRegisterProperties(Subtarget.getRegisterInfo()); +} + +const MipsTargetLowering * +llvm::createMipsSETargetLowering(const MipsTargetMachine &TM, + const MipsSubtarget &STI) { + return new MipsSETargetLowering(TM, STI); +} + +const TargetRegisterClass * +MipsSETargetLowering::getRepRegClassFor(MVT VT) const { + if (VT == MVT::Untyped) + return Subtarget.hasDSP() ? &Mips::ACC64DSPRegClass : &Mips::ACC64RegClass; + + return TargetLowering::getRepRegClassFor(VT); +} + +// Enable MSA support for the given integer type and Register class. +void MipsSETargetLowering:: +addMSAIntType(MVT::SimpleValueType Ty, const TargetRegisterClass *RC) { + addRegisterClass(Ty, RC); + + // Expand all builtin opcodes. + for (unsigned Opc = 0; Opc < ISD::BUILTIN_OP_END; ++Opc) + setOperationAction(Opc, Ty, Expand); + + setOperationAction(ISD::BITCAST, Ty, Legal); + setOperationAction(ISD::LOAD, Ty, Legal); + setOperationAction(ISD::STORE, Ty, Legal); + setOperationAction(ISD::EXTRACT_VECTOR_ELT, Ty, Custom); + setOperationAction(ISD::INSERT_VECTOR_ELT, Ty, Legal); + setOperationAction(ISD::BUILD_VECTOR, Ty, Custom); + + setOperationAction(ISD::ADD, Ty, Legal); + setOperationAction(ISD::AND, Ty, Legal); + setOperationAction(ISD::CTLZ, Ty, Legal); + setOperationAction(ISD::CTPOP, Ty, Legal); + setOperationAction(ISD::MUL, Ty, Legal); + setOperationAction(ISD::OR, Ty, Legal); + setOperationAction(ISD::SDIV, Ty, Legal); + setOperationAction(ISD::SREM, Ty, Legal); + setOperationAction(ISD::SHL, Ty, Legal); + setOperationAction(ISD::SRA, Ty, Legal); + setOperationAction(ISD::SRL, Ty, Legal); + setOperationAction(ISD::SUB, Ty, Legal); + setOperationAction(ISD::UDIV, Ty, Legal); + setOperationAction(ISD::UREM, Ty, Legal); + setOperationAction(ISD::VECTOR_SHUFFLE, Ty, Custom); + setOperationAction(ISD::VSELECT, Ty, Legal); + setOperationAction(ISD::XOR, Ty, Legal); + + if (Ty == MVT::v4i32 || Ty == MVT::v2i64) { + setOperationAction(ISD::FP_TO_SINT, Ty, Legal); + setOperationAction(ISD::FP_TO_UINT, Ty, Legal); + setOperationAction(ISD::SINT_TO_FP, Ty, Legal); + setOperationAction(ISD::UINT_TO_FP, Ty, Legal); + } + + setOperationAction(ISD::SETCC, Ty, Legal); + setCondCodeAction(ISD::SETNE, Ty, Expand); + setCondCodeAction(ISD::SETGE, Ty, Expand); + setCondCodeAction(ISD::SETGT, Ty, Expand); + setCondCodeAction(ISD::SETUGE, Ty, Expand); + setCondCodeAction(ISD::SETUGT, Ty, Expand); +} + +// Enable MSA support for the given floating-point type and Register class. +void MipsSETargetLowering:: +addMSAFloatType(MVT::SimpleValueType Ty, const TargetRegisterClass *RC) { + addRegisterClass(Ty, RC); + + // Expand all builtin opcodes. + for (unsigned Opc = 0; Opc < ISD::BUILTIN_OP_END; ++Opc) + setOperationAction(Opc, Ty, Expand); + + setOperationAction(ISD::LOAD, Ty, Legal); + setOperationAction(ISD::STORE, Ty, Legal); + setOperationAction(ISD::BITCAST, Ty, Legal); + setOperationAction(ISD::EXTRACT_VECTOR_ELT, Ty, Legal); + setOperationAction(ISD::INSERT_VECTOR_ELT, Ty, Legal); + setOperationAction(ISD::BUILD_VECTOR, Ty, Custom); + + if (Ty != MVT::v8f16) { + setOperationAction(ISD::FABS, Ty, Legal); + setOperationAction(ISD::FADD, Ty, Legal); + setOperationAction(ISD::FDIV, Ty, Legal); + setOperationAction(ISD::FEXP2, Ty, Legal); + setOperationAction(ISD::FLOG2, Ty, Legal); + setOperationAction(ISD::FMA, Ty, Legal); + setOperationAction(ISD::FMUL, Ty, Legal); + setOperationAction(ISD::FRINT, Ty, Legal); + setOperationAction(ISD::FSQRT, Ty, Legal); + setOperationAction(ISD::FSUB, Ty, Legal); + setOperationAction(ISD::VSELECT, Ty, Legal); + + setOperationAction(ISD::SETCC, Ty, Legal); + setCondCodeAction(ISD::SETOGE, Ty, Expand); + setCondCodeAction(ISD::SETOGT, Ty, Expand); + setCondCodeAction(ISD::SETUGE, Ty, Expand); + setCondCodeAction(ISD::SETUGT, Ty, Expand); + setCondCodeAction(ISD::SETGE, Ty, Expand); + setCondCodeAction(ISD::SETGT, Ty, Expand); + } +} + +bool +MipsSETargetLowering::allowsMisalignedMemoryAccesses(EVT VT, + unsigned, + unsigned, + bool *Fast) const { + MVT::SimpleValueType SVT = VT.getSimpleVT().SimpleTy; + + if (Subtarget.systemSupportsUnalignedAccess()) { + // MIPS32r6/MIPS64r6 is required to support unaligned access. It's + // implementation defined whether this is handled by hardware, software, or + // a hybrid of the two but it's expected that most implementations will + // handle the majority of cases in hardware. + if (Fast) + *Fast = true; + return true; + } + + switch (SVT) { + case MVT::i64: + case MVT::i32: + if (Fast) + *Fast = true; + return true; + default: + return false; + } +} + +SDValue MipsSETargetLowering::LowerOperation(SDValue Op, + SelectionDAG &DAG) const { + switch(Op.getOpcode()) { + case ISD::LOAD: return lowerLOAD(Op, DAG); + case ISD::STORE: return lowerSTORE(Op, DAG); + case ISD::SMUL_LOHI: return lowerMulDiv(Op, MipsISD::Mult, true, true, DAG); + case ISD::UMUL_LOHI: return lowerMulDiv(Op, MipsISD::Multu, true, true, DAG); + case ISD::MULHS: return lowerMulDiv(Op, MipsISD::Mult, false, true, DAG); + case ISD::MULHU: return lowerMulDiv(Op, MipsISD::Multu, false, true, DAG); + case ISD::MUL: return lowerMulDiv(Op, MipsISD::Mult, true, false, DAG); + case ISD::SDIVREM: return lowerMulDiv(Op, MipsISD::DivRem, true, true, DAG); + case ISD::UDIVREM: return lowerMulDiv(Op, MipsISD::DivRemU, true, true, + DAG); + case ISD::INTRINSIC_WO_CHAIN: return lowerINTRINSIC_WO_CHAIN(Op, DAG); + case ISD::INTRINSIC_W_CHAIN: return lowerINTRINSIC_W_CHAIN(Op, DAG); + case ISD::INTRINSIC_VOID: return lowerINTRINSIC_VOID(Op, DAG); + case ISD::EXTRACT_VECTOR_ELT: return lowerEXTRACT_VECTOR_ELT(Op, DAG); + case ISD::BUILD_VECTOR: return lowerBUILD_VECTOR(Op, DAG); + case ISD::VECTOR_SHUFFLE: return lowerVECTOR_SHUFFLE(Op, DAG); + } + + return MipsTargetLowering::LowerOperation(Op, DAG); +} + +// selectMADD - +// Transforms a subgraph in CurDAG if the following pattern is found: +// (addc multLo, Lo0), (adde multHi, Hi0), +// where, +// multHi/Lo: product of multiplication +// Lo0: initial value of Lo register +// Hi0: initial value of Hi register +// Return true if pattern matching was successful. +static bool selectMADD(SDNode *ADDENode, SelectionDAG *CurDAG) { + // ADDENode's second operand must be a flag output of an ADDC node in order + // for the matching to be successful. + SDNode *ADDCNode = ADDENode->getOperand(2).getNode(); + + if (ADDCNode->getOpcode() != ISD::ADDC) + return false; + + SDValue MultHi = ADDENode->getOperand(0); + SDValue MultLo = ADDCNode->getOperand(0); + SDNode *MultNode = MultHi.getNode(); + unsigned MultOpc = MultHi.getOpcode(); + + // MultHi and MultLo must be generated by the same node, + if (MultLo.getNode() != MultNode) + return false; + + // and it must be a multiplication. + if (MultOpc != ISD::SMUL_LOHI && MultOpc != ISD::UMUL_LOHI) + return false; + + // MultLo amd MultHi must be the first and second output of MultNode + // respectively. + if (MultHi.getResNo() != 1 || MultLo.getResNo() != 0) + return false; + + // Transform this to a MADD only if ADDENode and ADDCNode are the only users + // of the values of MultNode, in which case MultNode will be removed in later + // phases. + // If there exist users other than ADDENode or ADDCNode, this function returns + // here, which will result in MultNode being mapped to a single MULT + // instruction node rather than a pair of MULT and MADD instructions being + // produced. + if (!MultHi.hasOneUse() || !MultLo.hasOneUse()) + return false; + + SDLoc DL(ADDENode); + + // Initialize accumulator. + SDValue ACCIn = CurDAG->getNode(MipsISD::MTLOHI, DL, MVT::Untyped, + ADDCNode->getOperand(1), + ADDENode->getOperand(1)); + + // create MipsMAdd(u) node + MultOpc = MultOpc == ISD::UMUL_LOHI ? MipsISD::MAddu : MipsISD::MAdd; + + SDValue MAdd = CurDAG->getNode(MultOpc, DL, MVT::Untyped, + MultNode->getOperand(0),// Factor 0 + MultNode->getOperand(1),// Factor 1 + ACCIn); + + // replace uses of adde and addc here + if (!SDValue(ADDCNode, 0).use_empty()) { + SDValue LoOut = CurDAG->getNode(MipsISD::MFLO, DL, MVT::i32, MAdd); + CurDAG->ReplaceAllUsesOfValueWith(SDValue(ADDCNode, 0), LoOut); + } + if (!SDValue(ADDENode, 0).use_empty()) { + SDValue HiOut = CurDAG->getNode(MipsISD::MFHI, DL, MVT::i32, MAdd); + CurDAG->ReplaceAllUsesOfValueWith(SDValue(ADDENode, 0), HiOut); + } + + return true; +} + +// selectMSUB - +// Transforms a subgraph in CurDAG if the following pattern is found: +// (addc Lo0, multLo), (sube Hi0, multHi), +// where, +// multHi/Lo: product of multiplication +// Lo0: initial value of Lo register +// Hi0: initial value of Hi register +// Return true if pattern matching was successful. +static bool selectMSUB(SDNode *SUBENode, SelectionDAG *CurDAG) { + // SUBENode's second operand must be a flag output of an SUBC node in order + // for the matching to be successful. + SDNode *SUBCNode = SUBENode->getOperand(2).getNode(); + + if (SUBCNode->getOpcode() != ISD::SUBC) + return false; + + SDValue MultHi = SUBENode->getOperand(1); + SDValue MultLo = SUBCNode->getOperand(1); + SDNode *MultNode = MultHi.getNode(); + unsigned MultOpc = MultHi.getOpcode(); + + // MultHi and MultLo must be generated by the same node, + if (MultLo.getNode() != MultNode) + return false; + + // and it must be a multiplication. + if (MultOpc != ISD::SMUL_LOHI && MultOpc != ISD::UMUL_LOHI) + return false; + + // MultLo amd MultHi must be the first and second output of MultNode + // respectively. + if (MultHi.getResNo() != 1 || MultLo.getResNo() != 0) + return false; + + // Transform this to a MSUB only if SUBENode and SUBCNode are the only users + // of the values of MultNode, in which case MultNode will be removed in later + // phases. + // If there exist users other than SUBENode or SUBCNode, this function returns + // here, which will result in MultNode being mapped to a single MULT + // instruction node rather than a pair of MULT and MSUB instructions being + // produced. + if (!MultHi.hasOneUse() || !MultLo.hasOneUse()) + return false; + + SDLoc DL(SUBENode); + + // Initialize accumulator. + SDValue ACCIn = CurDAG->getNode(MipsISD::MTLOHI, DL, MVT::Untyped, + SUBCNode->getOperand(0), + SUBENode->getOperand(0)); + + // create MipsSub(u) node + MultOpc = MultOpc == ISD::UMUL_LOHI ? MipsISD::MSubu : MipsISD::MSub; + + SDValue MSub = CurDAG->getNode(MultOpc, DL, MVT::Glue, + MultNode->getOperand(0),// Factor 0 + MultNode->getOperand(1),// Factor 1 + ACCIn); + + // replace uses of sube and subc here + if (!SDValue(SUBCNode, 0).use_empty()) { + SDValue LoOut = CurDAG->getNode(MipsISD::MFLO, DL, MVT::i32, MSub); + CurDAG->ReplaceAllUsesOfValueWith(SDValue(SUBCNode, 0), LoOut); + } + if (!SDValue(SUBENode, 0).use_empty()) { + SDValue HiOut = CurDAG->getNode(MipsISD::MFHI, DL, MVT::i32, MSub); + CurDAG->ReplaceAllUsesOfValueWith(SDValue(SUBENode, 0), HiOut); + } + + return true; +} + +static SDValue performADDECombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget &Subtarget) { + if (DCI.isBeforeLegalize()) + return SDValue(); + + if (Subtarget.hasMips32() && !Subtarget.hasMips32r6() && + N->getValueType(0) == MVT::i32 && selectMADD(N, &DAG)) + return SDValue(N, 0); + + return SDValue(); +} + +// Fold zero extensions into MipsISD::VEXTRACT_[SZ]EXT_ELT +// +// Performs the following transformations: +// - Changes MipsISD::VEXTRACT_[SZ]EXT_ELT to zero extension if its +// sign/zero-extension is completely overwritten by the new one performed by +// the ISD::AND. +// - Removes redundant zero extensions performed by an ISD::AND. +static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget &Subtarget) { + if (!Subtarget.hasMSA()) + return SDValue(); + + SDValue Op0 = N->getOperand(0); + SDValue Op1 = N->getOperand(1); + unsigned Op0Opcode = Op0->getOpcode(); + + // (and (MipsVExtract[SZ]Ext $a, $b, $c), imm:$d) + // where $d + 1 == 2^n and n == 32 + // or $d + 1 == 2^n and n <= 32 and ZExt + // -> (MipsVExtractZExt $a, $b, $c) + if (Op0Opcode == MipsISD::VEXTRACT_SEXT_ELT || + Op0Opcode == MipsISD::VEXTRACT_ZEXT_ELT) { + ConstantSDNode *Mask = dyn_cast<ConstantSDNode>(Op1); + + if (!Mask) + return SDValue(); + + int32_t Log2IfPositive = (Mask->getAPIntValue() + 1).exactLogBase2(); + + if (Log2IfPositive <= 0) + return SDValue(); // Mask+1 is not a power of 2 + + SDValue Op0Op2 = Op0->getOperand(2); + EVT ExtendTy = cast<VTSDNode>(Op0Op2)->getVT(); + unsigned ExtendTySize = ExtendTy.getSizeInBits(); + unsigned Log2 = Log2IfPositive; + + if ((Op0Opcode == MipsISD::VEXTRACT_ZEXT_ELT && Log2 >= ExtendTySize) || + Log2 == ExtendTySize) { + SDValue Ops[] = { Op0->getOperand(0), Op0->getOperand(1), Op0Op2 }; + return DAG.getNode(MipsISD::VEXTRACT_ZEXT_ELT, SDLoc(Op0), + Op0->getVTList(), + makeArrayRef(Ops, Op0->getNumOperands())); + } + } + + return SDValue(); +} + +// Determine if the specified node is a constant vector splat. +// +// Returns true and sets Imm if: +// * N is a ISD::BUILD_VECTOR representing a constant splat +// +// This function is quite similar to MipsSEDAGToDAGISel::selectVSplat. The +// differences are that it assumes the MSA has already been checked and the +// arbitrary requirement for a maximum of 32-bit integers isn't applied (and +// must not be in order for binsri.d to be selectable). +static bool isVSplat(SDValue N, APInt &Imm, bool IsLittleEndian) { + BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N.getNode()); + + if (!Node) + return false; + + APInt SplatValue, SplatUndef; + unsigned SplatBitSize; + bool HasAnyUndefs; + + if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs, + 8, !IsLittleEndian)) + return false; + + Imm = SplatValue; + + return true; +} + +// Test whether the given node is an all-ones build_vector. +static bool isVectorAllOnes(SDValue N) { + // Look through bitcasts. Endianness doesn't matter because we are looking + // for an all-ones value. + if (N->getOpcode() == ISD::BITCAST) + N = N->getOperand(0); + + BuildVectorSDNode *BVN = dyn_cast<BuildVectorSDNode>(N); + + if (!BVN) + return false; + + APInt SplatValue, SplatUndef; + unsigned SplatBitSize; + bool HasAnyUndefs; + + // Endianness doesn't matter in this context because we are looking for + // an all-ones value. + if (BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs)) + return SplatValue.isAllOnesValue(); + + return false; +} + +// Test whether N is the bitwise inverse of OfNode. +static bool isBitwiseInverse(SDValue N, SDValue OfNode) { + if (N->getOpcode() != ISD::XOR) + return false; + + if (isVectorAllOnes(N->getOperand(0))) + return N->getOperand(1) == OfNode; + + if (isVectorAllOnes(N->getOperand(1))) + return N->getOperand(0) == OfNode; + + return false; +} + +// Perform combines where ISD::OR is the root node. +// +// Performs the following transformations: +// - (or (and $a, $mask), (and $b, $inv_mask)) => (vselect $mask, $a, $b) +// where $inv_mask is the bitwise inverse of $mask and the 'or' has a 128-bit +// vector type. +static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget &Subtarget) { + if (!Subtarget.hasMSA()) + return SDValue(); + + EVT Ty = N->getValueType(0); + + if (!Ty.is128BitVector()) + return SDValue(); + + SDValue Op0 = N->getOperand(0); + SDValue Op1 = N->getOperand(1); + + if (Op0->getOpcode() == ISD::AND && Op1->getOpcode() == ISD::AND) { + SDValue Op0Op0 = Op0->getOperand(0); + SDValue Op0Op1 = Op0->getOperand(1); + SDValue Op1Op0 = Op1->getOperand(0); + SDValue Op1Op1 = Op1->getOperand(1); + bool IsLittleEndian = !Subtarget.isLittle(); + + SDValue IfSet, IfClr, Cond; + bool IsConstantMask = false; + APInt Mask, InvMask; + + // If Op0Op0 is an appropriate mask, try to find it's inverse in either + // Op1Op0, or Op1Op1. Keep track of the Cond, IfSet, and IfClr nodes, while + // looking. + // IfClr will be set if we find a valid match. + if (isVSplat(Op0Op0, Mask, IsLittleEndian)) { + Cond = Op0Op0; + IfSet = Op0Op1; + + if (isVSplat(Op1Op0, InvMask, IsLittleEndian) && + Mask.getBitWidth() == InvMask.getBitWidth() && Mask == ~InvMask) + IfClr = Op1Op1; + else if (isVSplat(Op1Op1, InvMask, IsLittleEndian) && + Mask.getBitWidth() == InvMask.getBitWidth() && Mask == ~InvMask) + IfClr = Op1Op0; + + IsConstantMask = true; + } + + // If IfClr is not yet set, and Op0Op1 is an appropriate mask, try the same + // thing again using this mask. + // IfClr will be set if we find a valid match. + if (!IfClr.getNode() && isVSplat(Op0Op1, Mask, IsLittleEndian)) { + Cond = Op0Op1; + IfSet = Op0Op0; + + if (isVSplat(Op1Op0, InvMask, IsLittleEndian) && + Mask.getBitWidth() == InvMask.getBitWidth() && Mask == ~InvMask) + IfClr = Op1Op1; + else if (isVSplat(Op1Op1, InvMask, IsLittleEndian) && + Mask.getBitWidth() == InvMask.getBitWidth() && Mask == ~InvMask) + IfClr = Op1Op0; + + IsConstantMask = true; + } + + // If IfClr is not yet set, try looking for a non-constant match. + // IfClr will be set if we find a valid match amongst the eight + // possibilities. + if (!IfClr.getNode()) { + if (isBitwiseInverse(Op0Op0, Op1Op0)) { + Cond = Op1Op0; + IfSet = Op1Op1; + IfClr = Op0Op1; + } else if (isBitwiseInverse(Op0Op1, Op1Op0)) { + Cond = Op1Op0; + IfSet = Op1Op1; + IfClr = Op0Op0; + } else if (isBitwiseInverse(Op0Op0, Op1Op1)) { + Cond = Op1Op1; + IfSet = Op1Op0; + IfClr = Op0Op1; + } else if (isBitwiseInverse(Op0Op1, Op1Op1)) { + Cond = Op1Op1; + IfSet = Op1Op0; + IfClr = Op0Op0; + } else if (isBitwiseInverse(Op1Op0, Op0Op0)) { + Cond = Op0Op0; + IfSet = Op0Op1; + IfClr = Op1Op1; + } else if (isBitwiseInverse(Op1Op1, Op0Op0)) { + Cond = Op0Op0; + IfSet = Op0Op1; + IfClr = Op1Op0; + } else if (isBitwiseInverse(Op1Op0, Op0Op1)) { + Cond = Op0Op1; + IfSet = Op0Op0; + IfClr = Op1Op1; + } else if (isBitwiseInverse(Op1Op1, Op0Op1)) { + Cond = Op0Op1; + IfSet = Op0Op0; + IfClr = Op1Op0; + } + } + + // At this point, IfClr will be set if we have a valid match. + if (!IfClr.getNode()) + return SDValue(); + + assert(Cond.getNode() && IfSet.getNode()); + + // Fold degenerate cases. + if (IsConstantMask) { + if (Mask.isAllOnesValue()) + return IfSet; + else if (Mask == 0) + return IfClr; + } + + // Transform the DAG into an equivalent VSELECT. + return DAG.getNode(ISD::VSELECT, SDLoc(N), Ty, Cond, IfSet, IfClr); + } + + return SDValue(); +} + +static SDValue performSUBECombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget &Subtarget) { + if (DCI.isBeforeLegalize()) + return SDValue(); + + if (Subtarget.hasMips32() && N->getValueType(0) == MVT::i32 && + selectMSUB(N, &DAG)) + return SDValue(N, 0); + + return SDValue(); +} + +static SDValue genConstMult(SDValue X, uint64_t C, SDLoc DL, EVT VT, + EVT ShiftTy, SelectionDAG &DAG) { + // Clear the upper (64 - VT.sizeInBits) bits. + C &= ((uint64_t)-1) >> (64 - VT.getSizeInBits()); + + // Return 0. + if (C == 0) + return DAG.getConstant(0, DL, VT); + + // Return x. + if (C == 1) + return X; + + // If c is power of 2, return (shl x, log2(c)). + if (isPowerOf2_64(C)) + return DAG.getNode(ISD::SHL, DL, VT, X, + DAG.getConstant(Log2_64(C), DL, ShiftTy)); + + unsigned Log2Ceil = Log2_64_Ceil(C); + uint64_t Floor = 1LL << Log2_64(C); + uint64_t Ceil = Log2Ceil == 64 ? 0LL : 1LL << Log2Ceil; + + // If |c - floor_c| <= |c - ceil_c|, + // where floor_c = pow(2, floor(log2(c))) and ceil_c = pow(2, ceil(log2(c))), + // return (add constMult(x, floor_c), constMult(x, c - floor_c)). + if (C - Floor <= Ceil - C) { + SDValue Op0 = genConstMult(X, Floor, DL, VT, ShiftTy, DAG); + SDValue Op1 = genConstMult(X, C - Floor, DL, VT, ShiftTy, DAG); + return DAG.getNode(ISD::ADD, DL, VT, Op0, Op1); + } + + // If |c - floor_c| > |c - ceil_c|, + // return (sub constMult(x, ceil_c), constMult(x, ceil_c - c)). + SDValue Op0 = genConstMult(X, Ceil, DL, VT, ShiftTy, DAG); + SDValue Op1 = genConstMult(X, Ceil - C, DL, VT, ShiftTy, DAG); + return DAG.getNode(ISD::SUB, DL, VT, Op0, Op1); +} + +static SDValue performMULCombine(SDNode *N, SelectionDAG &DAG, + const TargetLowering::DAGCombinerInfo &DCI, + const MipsSETargetLowering *TL) { + EVT VT = N->getValueType(0); + + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1))) + if (!VT.isVector()) + return genConstMult(N->getOperand(0), C->getZExtValue(), SDLoc(N), VT, + TL->getScalarShiftAmountTy(DAG.getDataLayout(), VT), + DAG); + + return SDValue(N, 0); +} + +static SDValue performDSPShiftCombine(unsigned Opc, SDNode *N, EVT Ty, + SelectionDAG &DAG, + const MipsSubtarget &Subtarget) { + // See if this is a vector splat immediate node. + APInt SplatValue, SplatUndef; + unsigned SplatBitSize; + bool HasAnyUndefs; + unsigned EltSize = Ty.getVectorElementType().getSizeInBits(); + BuildVectorSDNode *BV = dyn_cast<BuildVectorSDNode>(N->getOperand(1)); + + if (!Subtarget.hasDSP()) + return SDValue(); + + if (!BV || + !BV->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs, + EltSize, !Subtarget.isLittle()) || + (SplatBitSize != EltSize) || + (SplatValue.getZExtValue() >= EltSize)) + return SDValue(); + + SDLoc DL(N); + return DAG.getNode(Opc, DL, Ty, N->getOperand(0), + DAG.getConstant(SplatValue.getZExtValue(), DL, MVT::i32)); +} + +static SDValue performSHLCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget &Subtarget) { + EVT Ty = N->getValueType(0); + + if ((Ty != MVT::v2i16) && (Ty != MVT::v4i8)) + return SDValue(); + + return performDSPShiftCombine(MipsISD::SHLL_DSP, N, Ty, DAG, Subtarget); +} + +// Fold sign-extensions into MipsISD::VEXTRACT_[SZ]EXT_ELT for MSA and fold +// constant splats into MipsISD::SHRA_DSP for DSPr2. +// +// Performs the following transformations: +// - Changes MipsISD::VEXTRACT_[SZ]EXT_ELT to sign extension if its +// sign/zero-extension is completely overwritten by the new one performed by +// the ISD::SRA and ISD::SHL nodes. +// - Removes redundant sign extensions performed by an ISD::SRA and ISD::SHL +// sequence. +// +// See performDSPShiftCombine for more information about the transformation +// used for DSPr2. +static SDValue performSRACombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget &Subtarget) { + EVT Ty = N->getValueType(0); + + if (Subtarget.hasMSA()) { + SDValue Op0 = N->getOperand(0); + SDValue Op1 = N->getOperand(1); + + // (sra (shl (MipsVExtract[SZ]Ext $a, $b, $c), imm:$d), imm:$d) + // where $d + sizeof($c) == 32 + // or $d + sizeof($c) <= 32 and SExt + // -> (MipsVExtractSExt $a, $b, $c) + if (Op0->getOpcode() == ISD::SHL && Op1 == Op0->getOperand(1)) { + SDValue Op0Op0 = Op0->getOperand(0); + ConstantSDNode *ShAmount = dyn_cast<ConstantSDNode>(Op1); + + if (!ShAmount) + return SDValue(); + + if (Op0Op0->getOpcode() != MipsISD::VEXTRACT_SEXT_ELT && + Op0Op0->getOpcode() != MipsISD::VEXTRACT_ZEXT_ELT) + return SDValue(); + + EVT ExtendTy = cast<VTSDNode>(Op0Op0->getOperand(2))->getVT(); + unsigned TotalBits = ShAmount->getZExtValue() + ExtendTy.getSizeInBits(); + + if (TotalBits == 32 || + (Op0Op0->getOpcode() == MipsISD::VEXTRACT_SEXT_ELT && + TotalBits <= 32)) { + SDValue Ops[] = { Op0Op0->getOperand(0), Op0Op0->getOperand(1), + Op0Op0->getOperand(2) }; + return DAG.getNode(MipsISD::VEXTRACT_SEXT_ELT, SDLoc(Op0Op0), + Op0Op0->getVTList(), + makeArrayRef(Ops, Op0Op0->getNumOperands())); + } + } + } + + if ((Ty != MVT::v2i16) && ((Ty != MVT::v4i8) || !Subtarget.hasDSPR2())) + return SDValue(); + + return performDSPShiftCombine(MipsISD::SHRA_DSP, N, Ty, DAG, Subtarget); +} + + +static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget &Subtarget) { + EVT Ty = N->getValueType(0); + + if (((Ty != MVT::v2i16) || !Subtarget.hasDSPR2()) && (Ty != MVT::v4i8)) + return SDValue(); + + return performDSPShiftCombine(MipsISD::SHRL_DSP, N, Ty, DAG, Subtarget); +} + +static bool isLegalDSPCondCode(EVT Ty, ISD::CondCode CC) { + bool IsV216 = (Ty == MVT::v2i16); + + switch (CC) { + case ISD::SETEQ: + case ISD::SETNE: return true; + case ISD::SETLT: + case ISD::SETLE: + case ISD::SETGT: + case ISD::SETGE: return IsV216; + case ISD::SETULT: + case ISD::SETULE: + case ISD::SETUGT: + case ISD::SETUGE: return !IsV216; + default: return false; + } +} + +static SDValue performSETCCCombine(SDNode *N, SelectionDAG &DAG) { + EVT Ty = N->getValueType(0); + + if ((Ty != MVT::v2i16) && (Ty != MVT::v4i8)) + return SDValue(); + + if (!isLegalDSPCondCode(Ty, cast<CondCodeSDNode>(N->getOperand(2))->get())) + return SDValue(); + + return DAG.getNode(MipsISD::SETCC_DSP, SDLoc(N), Ty, N->getOperand(0), + N->getOperand(1), N->getOperand(2)); +} + +static SDValue performVSELECTCombine(SDNode *N, SelectionDAG &DAG) { + EVT Ty = N->getValueType(0); + + if (Ty.is128BitVector() && Ty.isInteger()) { + // Try the following combines: + // (vselect (setcc $a, $b, SETLT), $b, $a)) -> (vsmax $a, $b) + // (vselect (setcc $a, $b, SETLE), $b, $a)) -> (vsmax $a, $b) + // (vselect (setcc $a, $b, SETLT), $a, $b)) -> (vsmin $a, $b) + // (vselect (setcc $a, $b, SETLE), $a, $b)) -> (vsmin $a, $b) + // (vselect (setcc $a, $b, SETULT), $b, $a)) -> (vumax $a, $b) + // (vselect (setcc $a, $b, SETULE), $b, $a)) -> (vumax $a, $b) + // (vselect (setcc $a, $b, SETULT), $a, $b)) -> (vumin $a, $b) + // (vselect (setcc $a, $b, SETULE), $a, $b)) -> (vumin $a, $b) + // SETGT/SETGE/SETUGT/SETUGE variants of these will show up initially but + // will be expanded to equivalent SETLT/SETLE/SETULT/SETULE versions by the + // legalizer. + SDValue Op0 = N->getOperand(0); + + if (Op0->getOpcode() != ISD::SETCC) + return SDValue(); + + ISD::CondCode CondCode = cast<CondCodeSDNode>(Op0->getOperand(2))->get(); + bool Signed; + + if (CondCode == ISD::SETLT || CondCode == ISD::SETLE) + Signed = true; + else if (CondCode == ISD::SETULT || CondCode == ISD::SETULE) + Signed = false; + else + return SDValue(); + + SDValue Op1 = N->getOperand(1); + SDValue Op2 = N->getOperand(2); + SDValue Op0Op0 = Op0->getOperand(0); + SDValue Op0Op1 = Op0->getOperand(1); + + if (Op1 == Op0Op0 && Op2 == Op0Op1) + return DAG.getNode(Signed ? MipsISD::VSMIN : MipsISD::VUMIN, SDLoc(N), + Ty, Op1, Op2); + else if (Op1 == Op0Op1 && Op2 == Op0Op0) + return DAG.getNode(Signed ? MipsISD::VSMAX : MipsISD::VUMAX, SDLoc(N), + Ty, Op1, Op2); + } else if ((Ty == MVT::v2i16) || (Ty == MVT::v4i8)) { + SDValue SetCC = N->getOperand(0); + + if (SetCC.getOpcode() != MipsISD::SETCC_DSP) + return SDValue(); + + return DAG.getNode(MipsISD::SELECT_CC_DSP, SDLoc(N), Ty, + SetCC.getOperand(0), SetCC.getOperand(1), + N->getOperand(1), N->getOperand(2), SetCC.getOperand(2)); + } + + return SDValue(); +} + +static SDValue performXORCombine(SDNode *N, SelectionDAG &DAG, + const MipsSubtarget &Subtarget) { + EVT Ty = N->getValueType(0); + + if (Subtarget.hasMSA() && Ty.is128BitVector() && Ty.isInteger()) { + // Try the following combines: + // (xor (or $a, $b), (build_vector allones)) + // (xor (or $a, $b), (bitcast (build_vector allones))) + SDValue Op0 = N->getOperand(0); + SDValue Op1 = N->getOperand(1); + SDValue NotOp; + + if (ISD::isBuildVectorAllOnes(Op0.getNode())) + NotOp = Op1; + else if (ISD::isBuildVectorAllOnes(Op1.getNode())) + NotOp = Op0; + else + return SDValue(); + + if (NotOp->getOpcode() == ISD::OR) + return DAG.getNode(MipsISD::VNOR, SDLoc(N), Ty, NotOp->getOperand(0), + NotOp->getOperand(1)); + } + + return SDValue(); +} + +SDValue +MipsSETargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const { + SelectionDAG &DAG = DCI.DAG; + SDValue Val; + + switch (N->getOpcode()) { + case ISD::ADDE: + return performADDECombine(N, DAG, DCI, Subtarget); + case ISD::AND: + Val = performANDCombine(N, DAG, DCI, Subtarget); + break; + case ISD::OR: + Val = performORCombine(N, DAG, DCI, Subtarget); + break; + case ISD::SUBE: + return performSUBECombine(N, DAG, DCI, Subtarget); + case ISD::MUL: + return performMULCombine(N, DAG, DCI, this); + case ISD::SHL: + return performSHLCombine(N, DAG, DCI, Subtarget); + case ISD::SRA: + return performSRACombine(N, DAG, DCI, Subtarget); + case ISD::SRL: + return performSRLCombine(N, DAG, DCI, Subtarget); + case ISD::VSELECT: + return performVSELECTCombine(N, DAG); + case ISD::XOR: + Val = performXORCombine(N, DAG, Subtarget); + break; + case ISD::SETCC: + Val = performSETCCCombine(N, DAG); + break; + } + + if (Val.getNode()) { + DEBUG(dbgs() << "\nMipsSE DAG Combine:\n"; + N->printrWithDepth(dbgs(), &DAG); + dbgs() << "\n=> \n"; + Val.getNode()->printrWithDepth(dbgs(), &DAG); + dbgs() << "\n"); + return Val; + } + + return MipsTargetLowering::PerformDAGCombine(N, DCI); +} + +MachineBasicBlock * +MipsSETargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const { + switch (MI->getOpcode()) { + default: + return MipsTargetLowering::EmitInstrWithCustomInserter(MI, BB); + case Mips::BPOSGE32_PSEUDO: + return emitBPOSGE32(MI, BB); + case Mips::SNZ_B_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BNZ_B); + case Mips::SNZ_H_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BNZ_H); + case Mips::SNZ_W_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BNZ_W); + case Mips::SNZ_D_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BNZ_D); + case Mips::SNZ_V_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BNZ_V); + case Mips::SZ_B_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BZ_B); + case Mips::SZ_H_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BZ_H); + case Mips::SZ_W_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BZ_W); + case Mips::SZ_D_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BZ_D); + case Mips::SZ_V_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BZ_V); + case Mips::COPY_FW_PSEUDO: + return emitCOPY_FW(MI, BB); + case Mips::COPY_FD_PSEUDO: + return emitCOPY_FD(MI, BB); + case Mips::INSERT_FW_PSEUDO: + return emitINSERT_FW(MI, BB); + case Mips::INSERT_FD_PSEUDO: + return emitINSERT_FD(MI, BB); + case Mips::INSERT_B_VIDX_PSEUDO: + case Mips::INSERT_B_VIDX64_PSEUDO: + return emitINSERT_DF_VIDX(MI, BB, 1, false); + case Mips::INSERT_H_VIDX_PSEUDO: + case Mips::INSERT_H_VIDX64_PSEUDO: + return emitINSERT_DF_VIDX(MI, BB, 2, false); + case Mips::INSERT_W_VIDX_PSEUDO: + case Mips::INSERT_W_VIDX64_PSEUDO: + return emitINSERT_DF_VIDX(MI, BB, 4, false); + case Mips::INSERT_D_VIDX_PSEUDO: + case Mips::INSERT_D_VIDX64_PSEUDO: + return emitINSERT_DF_VIDX(MI, BB, 8, false); + case Mips::INSERT_FW_VIDX_PSEUDO: + case Mips::INSERT_FW_VIDX64_PSEUDO: + return emitINSERT_DF_VIDX(MI, BB, 4, true); + case Mips::INSERT_FD_VIDX_PSEUDO: + case Mips::INSERT_FD_VIDX64_PSEUDO: + return emitINSERT_DF_VIDX(MI, BB, 8, true); + case Mips::FILL_FW_PSEUDO: + return emitFILL_FW(MI, BB); + case Mips::FILL_FD_PSEUDO: + return emitFILL_FD(MI, BB); + case Mips::FEXP2_W_1_PSEUDO: + return emitFEXP2_W_1(MI, BB); + case Mips::FEXP2_D_1_PSEUDO: + return emitFEXP2_D_1(MI, BB); + } +} + +bool MipsSETargetLowering::isEligibleForTailCallOptimization( + const CCState &CCInfo, unsigned NextStackOffset, + const MipsFunctionInfo &FI) const { + if (!EnableMipsTailCalls) + return false; + + // Exception has to be cleared with eret. + if (FI.isISR()) + return false; + + // Return false if either the callee or caller has a byval argument. + if (CCInfo.getInRegsParamsCount() > 0 || FI.hasByvalArg()) + return false; + + // Return true if the callee's argument area is no larger than the + // caller's. + return NextStackOffset <= FI.getIncomingArgSize(); +} + +void MipsSETargetLowering:: +getOpndList(SmallVectorImpl<SDValue> &Ops, + std::deque< std::pair<unsigned, SDValue> > &RegsToPass, + bool IsPICCall, bool GlobalOrExternal, bool InternalLinkage, + bool IsCallReloc, CallLoweringInfo &CLI, SDValue Callee, + SDValue Chain) const { + Ops.push_back(Callee); + MipsTargetLowering::getOpndList(Ops, RegsToPass, IsPICCall, GlobalOrExternal, + InternalLinkage, IsCallReloc, CLI, Callee, + Chain); +} + +SDValue MipsSETargetLowering::lowerLOAD(SDValue Op, SelectionDAG &DAG) const { + LoadSDNode &Nd = *cast<LoadSDNode>(Op); + + if (Nd.getMemoryVT() != MVT::f64 || !NoDPLoadStore) + return MipsTargetLowering::lowerLOAD(Op, DAG); + + // Replace a double precision load with two i32 loads and a buildpair64. + SDLoc DL(Op); + SDValue Ptr = Nd.getBasePtr(), Chain = Nd.getChain(); + EVT PtrVT = Ptr.getValueType(); + + // i32 load from lower address. + SDValue Lo = DAG.getLoad(MVT::i32, DL, Chain, Ptr, + MachinePointerInfo(), Nd.isVolatile(), + Nd.isNonTemporal(), Nd.isInvariant(), + Nd.getAlignment()); + + // i32 load from higher address. + Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, Ptr, DAG.getConstant(4, DL, PtrVT)); + SDValue Hi = DAG.getLoad(MVT::i32, DL, Lo.getValue(1), Ptr, + MachinePointerInfo(), Nd.isVolatile(), + Nd.isNonTemporal(), Nd.isInvariant(), + std::min(Nd.getAlignment(), 4U)); + + if (!Subtarget.isLittle()) + std::swap(Lo, Hi); + + SDValue BP = DAG.getNode(MipsISD::BuildPairF64, DL, MVT::f64, Lo, Hi); + SDValue Ops[2] = {BP, Hi.getValue(1)}; + return DAG.getMergeValues(Ops, DL); +} + +SDValue MipsSETargetLowering::lowerSTORE(SDValue Op, SelectionDAG &DAG) const { + StoreSDNode &Nd = *cast<StoreSDNode>(Op); + + if (Nd.getMemoryVT() != MVT::f64 || !NoDPLoadStore) + return MipsTargetLowering::lowerSTORE(Op, DAG); + + // Replace a double precision store with two extractelement64s and i32 stores. + SDLoc DL(Op); + SDValue Val = Nd.getValue(), Ptr = Nd.getBasePtr(), Chain = Nd.getChain(); + EVT PtrVT = Ptr.getValueType(); + SDValue Lo = DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, + Val, DAG.getConstant(0, DL, MVT::i32)); + SDValue Hi = DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, + Val, DAG.getConstant(1, DL, MVT::i32)); + + if (!Subtarget.isLittle()) + std::swap(Lo, Hi); + + // i32 store to lower address. + Chain = DAG.getStore(Chain, DL, Lo, Ptr, MachinePointerInfo(), + Nd.isVolatile(), Nd.isNonTemporal(), Nd.getAlignment(), + Nd.getAAInfo()); + + // i32 store to higher address. + Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, Ptr, DAG.getConstant(4, DL, PtrVT)); + return DAG.getStore(Chain, DL, Hi, Ptr, MachinePointerInfo(), + Nd.isVolatile(), Nd.isNonTemporal(), + std::min(Nd.getAlignment(), 4U), Nd.getAAInfo()); +} + +SDValue MipsSETargetLowering::lowerMulDiv(SDValue Op, unsigned NewOpc, + bool HasLo, bool HasHi, + SelectionDAG &DAG) const { + // MIPS32r6/MIPS64r6 removed accumulator based multiplies. + assert(!Subtarget.hasMips32r6()); + + EVT Ty = Op.getOperand(0).getValueType(); + SDLoc DL(Op); + SDValue Mult = DAG.getNode(NewOpc, DL, MVT::Untyped, + Op.getOperand(0), Op.getOperand(1)); + SDValue Lo, Hi; + + if (HasLo) + Lo = DAG.getNode(MipsISD::MFLO, DL, Ty, Mult); + if (HasHi) + Hi = DAG.getNode(MipsISD::MFHI, DL, Ty, Mult); + + if (!HasLo || !HasHi) + return HasLo ? Lo : Hi; + + SDValue Vals[] = { Lo, Hi }; + return DAG.getMergeValues(Vals, DL); +} + + +static SDValue initAccumulator(SDValue In, SDLoc DL, SelectionDAG &DAG) { + SDValue InLo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, In, + DAG.getConstant(0, DL, MVT::i32)); + SDValue InHi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, In, + DAG.getConstant(1, DL, MVT::i32)); + return DAG.getNode(MipsISD::MTLOHI, DL, MVT::Untyped, InLo, InHi); +} + +static SDValue extractLOHI(SDValue Op, SDLoc DL, SelectionDAG &DAG) { + SDValue Lo = DAG.getNode(MipsISD::MFLO, DL, MVT::i32, Op); + SDValue Hi = DAG.getNode(MipsISD::MFHI, DL, MVT::i32, Op); + return DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, Lo, Hi); +} + +// This function expands mips intrinsic nodes which have 64-bit input operands +// or output values. +// +// out64 = intrinsic-node in64 +// => +// lo = copy (extract-element (in64, 0)) +// hi = copy (extract-element (in64, 1)) +// mips-specific-node +// v0 = copy lo +// v1 = copy hi +// out64 = merge-values (v0, v1) +// +static SDValue lowerDSPIntr(SDValue Op, SelectionDAG &DAG, unsigned Opc) { + SDLoc DL(Op); + bool HasChainIn = Op->getOperand(0).getValueType() == MVT::Other; + SmallVector<SDValue, 3> Ops; + unsigned OpNo = 0; + + // See if Op has a chain input. + if (HasChainIn) + Ops.push_back(Op->getOperand(OpNo++)); + + // The next operand is the intrinsic opcode. + assert(Op->getOperand(OpNo).getOpcode() == ISD::TargetConstant); + + // See if the next operand has type i64. + SDValue Opnd = Op->getOperand(++OpNo), In64; + + if (Opnd.getValueType() == MVT::i64) + In64 = initAccumulator(Opnd, DL, DAG); + else + Ops.push_back(Opnd); + + // Push the remaining operands. + for (++OpNo ; OpNo < Op->getNumOperands(); ++OpNo) + Ops.push_back(Op->getOperand(OpNo)); + + // Add In64 to the end of the list. + if (In64.getNode()) + Ops.push_back(In64); + + // Scan output. + SmallVector<EVT, 2> ResTys; + + for (SDNode::value_iterator I = Op->value_begin(), E = Op->value_end(); + I != E; ++I) + ResTys.push_back((*I == MVT::i64) ? MVT::Untyped : *I); + + // Create node. + SDValue Val = DAG.getNode(Opc, DL, ResTys, Ops); + SDValue Out = (ResTys[0] == MVT::Untyped) ? extractLOHI(Val, DL, DAG) : Val; + + if (!HasChainIn) + return Out; + + assert(Val->getValueType(1) == MVT::Other); + SDValue Vals[] = { Out, SDValue(Val.getNode(), 1) }; + return DAG.getMergeValues(Vals, DL); +} + +// Lower an MSA copy intrinsic into the specified SelectionDAG node +static SDValue lowerMSACopyIntr(SDValue Op, SelectionDAG &DAG, unsigned Opc) { + SDLoc DL(Op); + SDValue Vec = Op->getOperand(1); + SDValue Idx = Op->getOperand(2); + EVT ResTy = Op->getValueType(0); + EVT EltTy = Vec->getValueType(0).getVectorElementType(); + + SDValue Result = DAG.getNode(Opc, DL, ResTy, Vec, Idx, + DAG.getValueType(EltTy)); + + return Result; +} + +static SDValue lowerMSASplatZExt(SDValue Op, unsigned OpNr, SelectionDAG &DAG) { + EVT ResVecTy = Op->getValueType(0); + EVT ViaVecTy = ResVecTy; + SDLoc DL(Op); + + // When ResVecTy == MVT::v2i64, LaneA is the upper 32 bits of the lane and + // LaneB is the lower 32-bits. Otherwise LaneA and LaneB are alternating + // lanes. + SDValue LaneA; + SDValue LaneB = Op->getOperand(2); + + if (ResVecTy == MVT::v2i64) { + LaneA = DAG.getConstant(0, DL, MVT::i32); + ViaVecTy = MVT::v4i32; + } else + LaneA = LaneB; + + SDValue Ops[16] = { LaneA, LaneB, LaneA, LaneB, LaneA, LaneB, LaneA, LaneB, + LaneA, LaneB, LaneA, LaneB, LaneA, LaneB, LaneA, LaneB }; + + SDValue Result = DAG.getNode(ISD::BUILD_VECTOR, DL, ViaVecTy, + makeArrayRef(Ops, ViaVecTy.getVectorNumElements())); + + if (ViaVecTy != ResVecTy) + Result = DAG.getNode(ISD::BITCAST, DL, ResVecTy, Result); + + return Result; +} + +static SDValue lowerMSASplatImm(SDValue Op, unsigned ImmOp, SelectionDAG &DAG) { + return DAG.getConstant(Op->getConstantOperandVal(ImmOp), SDLoc(Op), + Op->getValueType(0)); +} + +static SDValue getBuildVectorSplat(EVT VecTy, SDValue SplatValue, + bool BigEndian, SelectionDAG &DAG) { + EVT ViaVecTy = VecTy; + SDValue SplatValueA = SplatValue; + SDValue SplatValueB = SplatValue; + SDLoc DL(SplatValue); + + if (VecTy == MVT::v2i64) { + // v2i64 BUILD_VECTOR must be performed via v4i32 so split into i32's. + ViaVecTy = MVT::v4i32; + + SplatValueA = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, SplatValue); + SplatValueB = DAG.getNode(ISD::SRL, DL, MVT::i64, SplatValue, + DAG.getConstant(32, DL, MVT::i32)); + SplatValueB = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, SplatValueB); + } + + // We currently hold the parts in little endian order. Swap them if + // necessary. + if (BigEndian) + std::swap(SplatValueA, SplatValueB); + + SDValue Ops[16] = { SplatValueA, SplatValueB, SplatValueA, SplatValueB, + SplatValueA, SplatValueB, SplatValueA, SplatValueB, + SplatValueA, SplatValueB, SplatValueA, SplatValueB, + SplatValueA, SplatValueB, SplatValueA, SplatValueB }; + + SDValue Result = DAG.getNode(ISD::BUILD_VECTOR, DL, ViaVecTy, + makeArrayRef(Ops, ViaVecTy.getVectorNumElements())); + + if (VecTy != ViaVecTy) + Result = DAG.getNode(ISD::BITCAST, DL, VecTy, Result); + + return Result; +} + +static SDValue lowerMSABinaryBitImmIntr(SDValue Op, SelectionDAG &DAG, + unsigned Opc, SDValue Imm, + bool BigEndian) { + EVT VecTy = Op->getValueType(0); + SDValue Exp2Imm; + SDLoc DL(Op); + + // The DAG Combiner can't constant fold bitcasted vectors yet so we must do it + // here for now. + if (VecTy == MVT::v2i64) { + if (ConstantSDNode *CImm = dyn_cast<ConstantSDNode>(Imm)) { + APInt BitImm = APInt(64, 1) << CImm->getAPIntValue(); + + SDValue BitImmHiOp = DAG.getConstant(BitImm.lshr(32).trunc(32), DL, + MVT::i32); + SDValue BitImmLoOp = DAG.getConstant(BitImm.trunc(32), DL, MVT::i32); + + if (BigEndian) + std::swap(BitImmLoOp, BitImmHiOp); + + Exp2Imm = + DAG.getNode(ISD::BITCAST, DL, MVT::v2i64, + DAG.getNode(ISD::BUILD_VECTOR, DL, MVT::v4i32, BitImmLoOp, + BitImmHiOp, BitImmLoOp, BitImmHiOp)); + } + } + + if (!Exp2Imm.getNode()) { + // We couldnt constant fold, do a vector shift instead + + // Extend i32 to i64 if necessary. Sign or zero extend doesn't matter since + // only values 0-63 are valid. + if (VecTy == MVT::v2i64) + Imm = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, Imm); + + Exp2Imm = getBuildVectorSplat(VecTy, Imm, BigEndian, DAG); + + Exp2Imm = DAG.getNode(ISD::SHL, DL, VecTy, DAG.getConstant(1, DL, VecTy), + Exp2Imm); + } + + return DAG.getNode(Opc, DL, VecTy, Op->getOperand(1), Exp2Imm); +} + +static SDValue lowerMSABitClear(SDValue Op, SelectionDAG &DAG) { + EVT ResTy = Op->getValueType(0); + SDLoc DL(Op); + SDValue One = DAG.getConstant(1, DL, ResTy); + SDValue Bit = DAG.getNode(ISD::SHL, DL, ResTy, One, Op->getOperand(2)); + + return DAG.getNode(ISD::AND, DL, ResTy, Op->getOperand(1), + DAG.getNOT(DL, Bit, ResTy)); +} + +static SDValue lowerMSABitClearImm(SDValue Op, SelectionDAG &DAG) { + SDLoc DL(Op); + EVT ResTy = Op->getValueType(0); + APInt BitImm = APInt(ResTy.getVectorElementType().getSizeInBits(), 1) + << cast<ConstantSDNode>(Op->getOperand(2))->getAPIntValue(); + SDValue BitMask = DAG.getConstant(~BitImm, DL, ResTy); + + return DAG.getNode(ISD::AND, DL, ResTy, Op->getOperand(1), BitMask); +} + +SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + + switch (cast<ConstantSDNode>(Op->getOperand(0))->getZExtValue()) { + default: + return SDValue(); + case Intrinsic::mips_shilo: + return lowerDSPIntr(Op, DAG, MipsISD::SHILO); + case Intrinsic::mips_dpau_h_qbl: + return lowerDSPIntr(Op, DAG, MipsISD::DPAU_H_QBL); + case Intrinsic::mips_dpau_h_qbr: + return lowerDSPIntr(Op, DAG, MipsISD::DPAU_H_QBR); + case Intrinsic::mips_dpsu_h_qbl: + return lowerDSPIntr(Op, DAG, MipsISD::DPSU_H_QBL); + case Intrinsic::mips_dpsu_h_qbr: + return lowerDSPIntr(Op, DAG, MipsISD::DPSU_H_QBR); + case Intrinsic::mips_dpa_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPA_W_PH); + case Intrinsic::mips_dps_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPS_W_PH); + case Intrinsic::mips_dpax_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPAX_W_PH); + case Intrinsic::mips_dpsx_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPSX_W_PH); + case Intrinsic::mips_mulsa_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::MULSA_W_PH); + case Intrinsic::mips_mult: + return lowerDSPIntr(Op, DAG, MipsISD::Mult); + case Intrinsic::mips_multu: + return lowerDSPIntr(Op, DAG, MipsISD::Multu); + case Intrinsic::mips_madd: + return lowerDSPIntr(Op, DAG, MipsISD::MAdd); + case Intrinsic::mips_maddu: + return lowerDSPIntr(Op, DAG, MipsISD::MAddu); + case Intrinsic::mips_msub: + return lowerDSPIntr(Op, DAG, MipsISD::MSub); + case Intrinsic::mips_msubu: + return lowerDSPIntr(Op, DAG, MipsISD::MSubu); + case Intrinsic::mips_addv_b: + case Intrinsic::mips_addv_h: + case Intrinsic::mips_addv_w: + case Intrinsic::mips_addv_d: + return DAG.getNode(ISD::ADD, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_addvi_b: + case Intrinsic::mips_addvi_h: + case Intrinsic::mips_addvi_w: + case Intrinsic::mips_addvi_d: + return DAG.getNode(ISD::ADD, DL, Op->getValueType(0), Op->getOperand(1), + lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_and_v: + return DAG.getNode(ISD::AND, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_andi_b: + return DAG.getNode(ISD::AND, DL, Op->getValueType(0), Op->getOperand(1), + lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_bclr_b: + case Intrinsic::mips_bclr_h: + case Intrinsic::mips_bclr_w: + case Intrinsic::mips_bclr_d: + return lowerMSABitClear(Op, DAG); + case Intrinsic::mips_bclri_b: + case Intrinsic::mips_bclri_h: + case Intrinsic::mips_bclri_w: + case Intrinsic::mips_bclri_d: + return lowerMSABitClearImm(Op, DAG); + case Intrinsic::mips_binsli_b: + case Intrinsic::mips_binsli_h: + case Intrinsic::mips_binsli_w: + case Intrinsic::mips_binsli_d: { + // 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, DL, 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, DL, 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), + Op->getOperand(2), Op->getOperand(1)); + case Intrinsic::mips_bmnzi_b: + return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0), + lowerMSASplatImm(Op, 3, DAG), Op->getOperand(2), + Op->getOperand(1)); + case Intrinsic::mips_bmz_v: + return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0), Op->getOperand(3), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_bmzi_b: + return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0), + lowerMSASplatImm(Op, 3, DAG), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_bneg_b: + case Intrinsic::mips_bneg_h: + case Intrinsic::mips_bneg_w: + case Intrinsic::mips_bneg_d: { + EVT VecTy = Op->getValueType(0); + SDValue One = DAG.getConstant(1, DL, VecTy); + + return DAG.getNode(ISD::XOR, DL, VecTy, Op->getOperand(1), + DAG.getNode(ISD::SHL, DL, VecTy, One, + Op->getOperand(2))); + } + case Intrinsic::mips_bnegi_b: + case Intrinsic::mips_bnegi_h: + case Intrinsic::mips_bnegi_w: + case Intrinsic::mips_bnegi_d: + return lowerMSABinaryBitImmIntr(Op, DAG, ISD::XOR, Op->getOperand(2), + !Subtarget.isLittle()); + case Intrinsic::mips_bnz_b: + case Intrinsic::mips_bnz_h: + case Intrinsic::mips_bnz_w: + case Intrinsic::mips_bnz_d: + return DAG.getNode(MipsISD::VALL_NONZERO, DL, Op->getValueType(0), + Op->getOperand(1)); + case Intrinsic::mips_bnz_v: + return DAG.getNode(MipsISD::VANY_NONZERO, DL, Op->getValueType(0), + Op->getOperand(1)); + case Intrinsic::mips_bsel_v: + // bsel_v(Mask, IfClear, IfSet) -> (vselect Mask, IfSet, IfClear) + return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0), + 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), lowerMSASplatImm(Op, 3, DAG), + Op->getOperand(2)); + case Intrinsic::mips_bset_b: + case Intrinsic::mips_bset_h: + case Intrinsic::mips_bset_w: + case Intrinsic::mips_bset_d: { + EVT VecTy = Op->getValueType(0); + SDValue One = DAG.getConstant(1, DL, VecTy); + + return DAG.getNode(ISD::OR, DL, VecTy, Op->getOperand(1), + DAG.getNode(ISD::SHL, DL, VecTy, One, + Op->getOperand(2))); + } + case Intrinsic::mips_bseti_b: + case Intrinsic::mips_bseti_h: + case Intrinsic::mips_bseti_w: + case Intrinsic::mips_bseti_d: + return lowerMSABinaryBitImmIntr(Op, DAG, ISD::OR, Op->getOperand(2), + !Subtarget.isLittle()); + case Intrinsic::mips_bz_b: + case Intrinsic::mips_bz_h: + case Intrinsic::mips_bz_w: + case Intrinsic::mips_bz_d: + return DAG.getNode(MipsISD::VALL_ZERO, DL, Op->getValueType(0), + Op->getOperand(1)); + case Intrinsic::mips_bz_v: + return DAG.getNode(MipsISD::VANY_ZERO, DL, Op->getValueType(0), + Op->getOperand(1)); + case Intrinsic::mips_ceq_b: + case Intrinsic::mips_ceq_h: + case Intrinsic::mips_ceq_w: + case Intrinsic::mips_ceq_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETEQ); + case Intrinsic::mips_ceqi_b: + case Intrinsic::mips_ceqi_h: + case Intrinsic::mips_ceqi_w: + case Intrinsic::mips_ceqi_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + lowerMSASplatImm(Op, 2, DAG), ISD::SETEQ); + case Intrinsic::mips_cle_s_b: + case Intrinsic::mips_cle_s_h: + case Intrinsic::mips_cle_s_w: + case Intrinsic::mips_cle_s_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETLE); + case Intrinsic::mips_clei_s_b: + case Intrinsic::mips_clei_s_h: + case Intrinsic::mips_clei_s_w: + case Intrinsic::mips_clei_s_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + lowerMSASplatImm(Op, 2, DAG), ISD::SETLE); + case Intrinsic::mips_cle_u_b: + case Intrinsic::mips_cle_u_h: + case Intrinsic::mips_cle_u_w: + case Intrinsic::mips_cle_u_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETULE); + case Intrinsic::mips_clei_u_b: + case Intrinsic::mips_clei_u_h: + case Intrinsic::mips_clei_u_w: + case Intrinsic::mips_clei_u_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + lowerMSASplatImm(Op, 2, DAG), ISD::SETULE); + case Intrinsic::mips_clt_s_b: + case Intrinsic::mips_clt_s_h: + case Intrinsic::mips_clt_s_w: + case Intrinsic::mips_clt_s_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETLT); + case Intrinsic::mips_clti_s_b: + case Intrinsic::mips_clti_s_h: + case Intrinsic::mips_clti_s_w: + case Intrinsic::mips_clti_s_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + lowerMSASplatImm(Op, 2, DAG), ISD::SETLT); + case Intrinsic::mips_clt_u_b: + case Intrinsic::mips_clt_u_h: + case Intrinsic::mips_clt_u_w: + case Intrinsic::mips_clt_u_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETULT); + case Intrinsic::mips_clti_u_b: + case Intrinsic::mips_clti_u_h: + case Intrinsic::mips_clti_u_w: + case Intrinsic::mips_clti_u_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + lowerMSASplatImm(Op, 2, DAG), ISD::SETULT); + case Intrinsic::mips_copy_s_b: + case Intrinsic::mips_copy_s_h: + case Intrinsic::mips_copy_s_w: + return lowerMSACopyIntr(Op, DAG, MipsISD::VEXTRACT_SEXT_ELT); + case Intrinsic::mips_copy_s_d: + if (Subtarget.hasMips64()) + // Lower directly into VEXTRACT_SEXT_ELT since i64 is legal on Mips64. + return lowerMSACopyIntr(Op, DAG, MipsISD::VEXTRACT_SEXT_ELT); + else { + // Lower into the generic EXTRACT_VECTOR_ELT node and let the type + // legalizer and EXTRACT_VECTOR_ELT lowering sort it out. + return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SDLoc(Op), + Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + } + case Intrinsic::mips_copy_u_b: + case Intrinsic::mips_copy_u_h: + case Intrinsic::mips_copy_u_w: + return lowerMSACopyIntr(Op, DAG, MipsISD::VEXTRACT_ZEXT_ELT); + case Intrinsic::mips_copy_u_d: + if (Subtarget.hasMips64()) + // Lower directly into VEXTRACT_ZEXT_ELT since i64 is legal on Mips64. + return lowerMSACopyIntr(Op, DAG, MipsISD::VEXTRACT_ZEXT_ELT); + else { + // Lower into the generic EXTRACT_VECTOR_ELT node and let the type + // legalizer and EXTRACT_VECTOR_ELT lowering sort it out. + // Note: When i64 is illegal, this results in copy_s.w instructions + // instead of copy_u.w instructions. This makes no difference to the + // behaviour since i64 is only illegal when the register file is 32-bit. + return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SDLoc(Op), + Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + } + case Intrinsic::mips_div_s_b: + case Intrinsic::mips_div_s_h: + case Intrinsic::mips_div_s_w: + case Intrinsic::mips_div_s_d: + return DAG.getNode(ISD::SDIV, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_div_u_b: + case Intrinsic::mips_div_u_h: + case Intrinsic::mips_div_u_w: + case Intrinsic::mips_div_u_d: + return DAG.getNode(ISD::UDIV, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_fadd_w: + case Intrinsic::mips_fadd_d: { + // TODO: If intrinsics have fast-math-flags, propagate them. + return DAG.getNode(ISD::FADD, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + } + // Don't lower mips_fcaf_[wd] since LLVM folds SETFALSE condcodes away + case Intrinsic::mips_fceq_w: + case Intrinsic::mips_fceq_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETOEQ); + case Intrinsic::mips_fcle_w: + case Intrinsic::mips_fcle_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETOLE); + case Intrinsic::mips_fclt_w: + case Intrinsic::mips_fclt_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETOLT); + case Intrinsic::mips_fcne_w: + case Intrinsic::mips_fcne_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETONE); + case Intrinsic::mips_fcor_w: + case Intrinsic::mips_fcor_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETO); + case Intrinsic::mips_fcueq_w: + case Intrinsic::mips_fcueq_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETUEQ); + case Intrinsic::mips_fcule_w: + case Intrinsic::mips_fcule_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETULE); + case Intrinsic::mips_fcult_w: + case Intrinsic::mips_fcult_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETULT); + case Intrinsic::mips_fcun_w: + case Intrinsic::mips_fcun_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETUO); + case Intrinsic::mips_fcune_w: + case Intrinsic::mips_fcune_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETUNE); + case Intrinsic::mips_fdiv_w: + case Intrinsic::mips_fdiv_d: { + // TODO: If intrinsics have fast-math-flags, propagate them. + return DAG.getNode(ISD::FDIV, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + } + case Intrinsic::mips_ffint_u_w: + case Intrinsic::mips_ffint_u_d: + return DAG.getNode(ISD::UINT_TO_FP, DL, Op->getValueType(0), + Op->getOperand(1)); + case Intrinsic::mips_ffint_s_w: + case Intrinsic::mips_ffint_s_d: + return DAG.getNode(ISD::SINT_TO_FP, DL, Op->getValueType(0), + Op->getOperand(1)); + case Intrinsic::mips_fill_b: + case Intrinsic::mips_fill_h: + case Intrinsic::mips_fill_w: + case Intrinsic::mips_fill_d: { + EVT ResTy = Op->getValueType(0); + SmallVector<SDValue, 16> Ops(ResTy.getVectorNumElements(), + Op->getOperand(1)); + + // If ResTy is v2i64 then the type legalizer will break this node down into + // an equivalent v4i32. + return DAG.getNode(ISD::BUILD_VECTOR, DL, ResTy, Ops); + } + case Intrinsic::mips_fexp2_w: + case Intrinsic::mips_fexp2_d: { + // TODO: If intrinsics have fast-math-flags, propagate them. + EVT ResTy = Op->getValueType(0); + return DAG.getNode( + ISD::FMUL, SDLoc(Op), ResTy, Op->getOperand(1), + DAG.getNode(ISD::FEXP2, SDLoc(Op), ResTy, Op->getOperand(2))); + } + case Intrinsic::mips_flog2_w: + case Intrinsic::mips_flog2_d: + return DAG.getNode(ISD::FLOG2, DL, Op->getValueType(0), Op->getOperand(1)); + case Intrinsic::mips_fmadd_w: + case Intrinsic::mips_fmadd_d: + return DAG.getNode(ISD::FMA, SDLoc(Op), Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2), Op->getOperand(3)); + case Intrinsic::mips_fmul_w: + case Intrinsic::mips_fmul_d: { + // TODO: If intrinsics have fast-math-flags, propagate them. + return DAG.getNode(ISD::FMUL, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + } + case Intrinsic::mips_fmsub_w: + case Intrinsic::mips_fmsub_d: { + // TODO: If intrinsics have fast-math-flags, propagate them. + EVT ResTy = Op->getValueType(0); + return DAG.getNode(ISD::FSUB, SDLoc(Op), ResTy, Op->getOperand(1), + DAG.getNode(ISD::FMUL, SDLoc(Op), ResTy, + Op->getOperand(2), Op->getOperand(3))); + } + case Intrinsic::mips_frint_w: + case Intrinsic::mips_frint_d: + return DAG.getNode(ISD::FRINT, DL, Op->getValueType(0), Op->getOperand(1)); + case Intrinsic::mips_fsqrt_w: + case Intrinsic::mips_fsqrt_d: + return DAG.getNode(ISD::FSQRT, DL, Op->getValueType(0), Op->getOperand(1)); + case Intrinsic::mips_fsub_w: + case Intrinsic::mips_fsub_d: { + // TODO: If intrinsics have fast-math-flags, propagate them. + return DAG.getNode(ISD::FSUB, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + } + case Intrinsic::mips_ftrunc_u_w: + case Intrinsic::mips_ftrunc_u_d: + return DAG.getNode(ISD::FP_TO_UINT, DL, Op->getValueType(0), + Op->getOperand(1)); + case Intrinsic::mips_ftrunc_s_w: + case Intrinsic::mips_ftrunc_s_d: + return DAG.getNode(ISD::FP_TO_SINT, DL, Op->getValueType(0), + Op->getOperand(1)); + case Intrinsic::mips_ilvev_b: + case Intrinsic::mips_ilvev_h: + case Intrinsic::mips_ilvev_w: + case Intrinsic::mips_ilvev_d: + return DAG.getNode(MipsISD::ILVEV, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_ilvl_b: + case Intrinsic::mips_ilvl_h: + case Intrinsic::mips_ilvl_w: + case Intrinsic::mips_ilvl_d: + return DAG.getNode(MipsISD::ILVL, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_ilvod_b: + case Intrinsic::mips_ilvod_h: + case Intrinsic::mips_ilvod_w: + case Intrinsic::mips_ilvod_d: + return DAG.getNode(MipsISD::ILVOD, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_ilvr_b: + case Intrinsic::mips_ilvr_h: + case Intrinsic::mips_ilvr_w: + case Intrinsic::mips_ilvr_d: + return DAG.getNode(MipsISD::ILVR, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_insert_b: + case Intrinsic::mips_insert_h: + case Intrinsic::mips_insert_w: + case Intrinsic::mips_insert_d: + return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(Op), Op->getValueType(0), + Op->getOperand(1), Op->getOperand(3), Op->getOperand(2)); + case Intrinsic::mips_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, DL, 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_dlsa: { + EVT ResTy = Op->getValueType(0); + return DAG.getNode(ISD::ADD, SDLoc(Op), ResTy, Op->getOperand(1), + DAG.getNode(ISD::SHL, SDLoc(Op), ResTy, + Op->getOperand(2), Op->getOperand(3))); + } + case Intrinsic::mips_maddv_b: + case Intrinsic::mips_maddv_h: + case Intrinsic::mips_maddv_w: + case Intrinsic::mips_maddv_d: { + EVT ResTy = Op->getValueType(0); + return DAG.getNode(ISD::ADD, SDLoc(Op), ResTy, Op->getOperand(1), + DAG.getNode(ISD::MUL, SDLoc(Op), ResTy, + Op->getOperand(2), Op->getOperand(3))); + } + case Intrinsic::mips_max_s_b: + case Intrinsic::mips_max_s_h: + case Intrinsic::mips_max_s_w: + case Intrinsic::mips_max_s_d: + return DAG.getNode(MipsISD::VSMAX, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_max_u_b: + case Intrinsic::mips_max_u_h: + case Intrinsic::mips_max_u_w: + case Intrinsic::mips_max_u_d: + return DAG.getNode(MipsISD::VUMAX, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_maxi_s_b: + case Intrinsic::mips_maxi_s_h: + case Intrinsic::mips_maxi_s_w: + case Intrinsic::mips_maxi_s_d: + return DAG.getNode(MipsISD::VSMAX, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_maxi_u_b: + case Intrinsic::mips_maxi_u_h: + case Intrinsic::mips_maxi_u_w: + case Intrinsic::mips_maxi_u_d: + return DAG.getNode(MipsISD::VUMAX, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_min_s_b: + case Intrinsic::mips_min_s_h: + case Intrinsic::mips_min_s_w: + case Intrinsic::mips_min_s_d: + return DAG.getNode(MipsISD::VSMIN, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_min_u_b: + case Intrinsic::mips_min_u_h: + case Intrinsic::mips_min_u_w: + case Intrinsic::mips_min_u_d: + return DAG.getNode(MipsISD::VUMIN, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_mini_s_b: + case Intrinsic::mips_mini_s_h: + case Intrinsic::mips_mini_s_w: + case Intrinsic::mips_mini_s_d: + return DAG.getNode(MipsISD::VSMIN, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_mini_u_b: + case Intrinsic::mips_mini_u_h: + case Intrinsic::mips_mini_u_w: + case Intrinsic::mips_mini_u_d: + return DAG.getNode(MipsISD::VUMIN, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_mod_s_b: + case Intrinsic::mips_mod_s_h: + case Intrinsic::mips_mod_s_w: + case Intrinsic::mips_mod_s_d: + return DAG.getNode(ISD::SREM, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_mod_u_b: + case Intrinsic::mips_mod_u_h: + case Intrinsic::mips_mod_u_w: + case Intrinsic::mips_mod_u_d: + return DAG.getNode(ISD::UREM, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_mulv_b: + case Intrinsic::mips_mulv_h: + case Intrinsic::mips_mulv_w: + case Intrinsic::mips_mulv_d: + return DAG.getNode(ISD::MUL, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_msubv_b: + case Intrinsic::mips_msubv_h: + case Intrinsic::mips_msubv_w: + case Intrinsic::mips_msubv_d: { + EVT ResTy = Op->getValueType(0); + return DAG.getNode(ISD::SUB, SDLoc(Op), ResTy, Op->getOperand(1), + DAG.getNode(ISD::MUL, SDLoc(Op), ResTy, + Op->getOperand(2), Op->getOperand(3))); + } + case Intrinsic::mips_nlzc_b: + case Intrinsic::mips_nlzc_h: + case Intrinsic::mips_nlzc_w: + case Intrinsic::mips_nlzc_d: + return DAG.getNode(ISD::CTLZ, DL, Op->getValueType(0), Op->getOperand(1)); + case Intrinsic::mips_nor_v: { + SDValue Res = DAG.getNode(ISD::OR, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + return DAG.getNOT(DL, Res, Res->getValueType(0)); + } + case Intrinsic::mips_nori_b: { + SDValue Res = DAG.getNode(ISD::OR, DL, Op->getValueType(0), + Op->getOperand(1), + lowerMSASplatImm(Op, 2, DAG)); + return DAG.getNOT(DL, Res, Res->getValueType(0)); + } + case Intrinsic::mips_or_v: + return DAG.getNode(ISD::OR, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_ori_b: + return DAG.getNode(ISD::OR, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_pckev_b: + case Intrinsic::mips_pckev_h: + case Intrinsic::mips_pckev_w: + case Intrinsic::mips_pckev_d: + return DAG.getNode(MipsISD::PCKEV, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_pckod_b: + case Intrinsic::mips_pckod_h: + case Intrinsic::mips_pckod_w: + case Intrinsic::mips_pckod_d: + return DAG.getNode(MipsISD::PCKOD, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_pcnt_b: + case Intrinsic::mips_pcnt_h: + case Intrinsic::mips_pcnt_w: + case Intrinsic::mips_pcnt_d: + return DAG.getNode(ISD::CTPOP, DL, Op->getValueType(0), Op->getOperand(1)); + case Intrinsic::mips_shf_b: + case Intrinsic::mips_shf_h: + case Intrinsic::mips_shf_w: + return DAG.getNode(MipsISD::SHF, DL, Op->getValueType(0), + Op->getOperand(2), Op->getOperand(1)); + case Intrinsic::mips_sll_b: + case Intrinsic::mips_sll_h: + case Intrinsic::mips_sll_w: + case Intrinsic::mips_sll_d: + return DAG.getNode(ISD::SHL, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_slli_b: + case Intrinsic::mips_slli_h: + case Intrinsic::mips_slli_w: + case Intrinsic::mips_slli_d: + return DAG.getNode(ISD::SHL, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_splat_b: + case Intrinsic::mips_splat_h: + case Intrinsic::mips_splat_w: + case Intrinsic::mips_splat_d: + // We can't lower via VECTOR_SHUFFLE because it requires constant shuffle + // masks, nor can we lower via BUILD_VECTOR & EXTRACT_VECTOR_ELT because + // EXTRACT_VECTOR_ELT can't extract i64's on MIPS32. + // Instead we lower to MipsISD::VSHF and match from there. + return DAG.getNode(MipsISD::VSHF, DL, Op->getValueType(0), + lowerMSASplatZExt(Op, 2, DAG), Op->getOperand(1), + Op->getOperand(1)); + case Intrinsic::mips_splati_b: + case Intrinsic::mips_splati_h: + case Intrinsic::mips_splati_w: + case Intrinsic::mips_splati_d: + return DAG.getNode(MipsISD::VSHF, DL, Op->getValueType(0), + lowerMSASplatImm(Op, 2, DAG), Op->getOperand(1), + Op->getOperand(1)); + case Intrinsic::mips_sra_b: + case Intrinsic::mips_sra_h: + case Intrinsic::mips_sra_w: + case Intrinsic::mips_sra_d: + return DAG.getNode(ISD::SRA, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_srai_b: + case Intrinsic::mips_srai_h: + case Intrinsic::mips_srai_w: + case Intrinsic::mips_srai_d: + return DAG.getNode(ISD::SRA, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_srl_b: + case Intrinsic::mips_srl_h: + case Intrinsic::mips_srl_w: + case Intrinsic::mips_srl_d: + return DAG.getNode(ISD::SRL, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_srli_b: + case Intrinsic::mips_srli_h: + case Intrinsic::mips_srli_w: + case Intrinsic::mips_srli_d: + return DAG.getNode(ISD::SRL, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_subv_b: + case Intrinsic::mips_subv_h: + case Intrinsic::mips_subv_w: + case Intrinsic::mips_subv_d: + return DAG.getNode(ISD::SUB, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_subvi_b: + case Intrinsic::mips_subvi_h: + case Intrinsic::mips_subvi_w: + case Intrinsic::mips_subvi_d: + return DAG.getNode(ISD::SUB, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_vshf_b: + case Intrinsic::mips_vshf_h: + case Intrinsic::mips_vshf_w: + case Intrinsic::mips_vshf_d: + return DAG.getNode(MipsISD::VSHF, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2), Op->getOperand(3)); + case Intrinsic::mips_xor_v: + return DAG.getNode(ISD::XOR, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_xori_b: + return DAG.getNode(ISD::XOR, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + } +} + +static SDValue lowerMSALoadIntr(SDValue Op, SelectionDAG &DAG, unsigned Intr) { + SDLoc DL(Op); + SDValue ChainIn = Op->getOperand(0); + SDValue Address = Op->getOperand(2); + SDValue Offset = Op->getOperand(3); + EVT ResTy = Op->getValueType(0); + EVT PtrTy = Address->getValueType(0); + + Address = DAG.getNode(ISD::ADD, DL, PtrTy, Address, Offset); + + return DAG.getLoad(ResTy, DL, ChainIn, Address, MachinePointerInfo(), false, + false, false, 16); +} + +SDValue MipsSETargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op, + SelectionDAG &DAG) const { + unsigned Intr = cast<ConstantSDNode>(Op->getOperand(1))->getZExtValue(); + switch (Intr) { + default: + return SDValue(); + case Intrinsic::mips_extp: + return lowerDSPIntr(Op, DAG, MipsISD::EXTP); + case Intrinsic::mips_extpdp: + return lowerDSPIntr(Op, DAG, MipsISD::EXTPDP); + case Intrinsic::mips_extr_w: + return lowerDSPIntr(Op, DAG, MipsISD::EXTR_W); + case Intrinsic::mips_extr_r_w: + return lowerDSPIntr(Op, DAG, MipsISD::EXTR_R_W); + case Intrinsic::mips_extr_rs_w: + return lowerDSPIntr(Op, DAG, MipsISD::EXTR_RS_W); + case Intrinsic::mips_extr_s_h: + return lowerDSPIntr(Op, DAG, MipsISD::EXTR_S_H); + case Intrinsic::mips_mthlip: + return lowerDSPIntr(Op, DAG, MipsISD::MTHLIP); + case Intrinsic::mips_mulsaq_s_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::MULSAQ_S_W_PH); + case Intrinsic::mips_maq_s_w_phl: + return lowerDSPIntr(Op, DAG, MipsISD::MAQ_S_W_PHL); + case Intrinsic::mips_maq_s_w_phr: + return lowerDSPIntr(Op, DAG, MipsISD::MAQ_S_W_PHR); + case Intrinsic::mips_maq_sa_w_phl: + return lowerDSPIntr(Op, DAG, MipsISD::MAQ_SA_W_PHL); + case Intrinsic::mips_maq_sa_w_phr: + return lowerDSPIntr(Op, DAG, MipsISD::MAQ_SA_W_PHR); + case Intrinsic::mips_dpaq_s_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPAQ_S_W_PH); + case Intrinsic::mips_dpsq_s_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPSQ_S_W_PH); + case Intrinsic::mips_dpaq_sa_l_w: + return lowerDSPIntr(Op, DAG, MipsISD::DPAQ_SA_L_W); + case Intrinsic::mips_dpsq_sa_l_w: + return lowerDSPIntr(Op, DAG, MipsISD::DPSQ_SA_L_W); + case Intrinsic::mips_dpaqx_s_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPAQX_S_W_PH); + case Intrinsic::mips_dpaqx_sa_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPAQX_SA_W_PH); + case Intrinsic::mips_dpsqx_s_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPSQX_S_W_PH); + case Intrinsic::mips_dpsqx_sa_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPSQX_SA_W_PH); + case Intrinsic::mips_ld_b: + case Intrinsic::mips_ld_h: + case Intrinsic::mips_ld_w: + case Intrinsic::mips_ld_d: + return lowerMSALoadIntr(Op, DAG, Intr); + } +} + +static SDValue lowerMSAStoreIntr(SDValue Op, SelectionDAG &DAG, unsigned Intr) { + SDLoc DL(Op); + SDValue ChainIn = Op->getOperand(0); + SDValue Value = Op->getOperand(2); + SDValue Address = Op->getOperand(3); + SDValue Offset = Op->getOperand(4); + EVT PtrTy = Address->getValueType(0); + + Address = DAG.getNode(ISD::ADD, DL, PtrTy, Address, Offset); + + return DAG.getStore(ChainIn, DL, Value, Address, MachinePointerInfo(), false, + false, 16); +} + +SDValue MipsSETargetLowering::lowerINTRINSIC_VOID(SDValue Op, + SelectionDAG &DAG) const { + unsigned Intr = cast<ConstantSDNode>(Op->getOperand(1))->getZExtValue(); + switch (Intr) { + default: + return SDValue(); + case Intrinsic::mips_st_b: + case Intrinsic::mips_st_h: + case Intrinsic::mips_st_w: + case Intrinsic::mips_st_d: + return lowerMSAStoreIntr(Op, DAG, Intr); + } +} + +/// \brief Check if the given BuildVectorSDNode is a splat. +/// This method currently relies on DAG nodes being reused when equivalent, +/// so it's possible for this to return false even when isConstantSplat returns +/// true. +static bool isSplatVector(const BuildVectorSDNode *N) { + unsigned int nOps = N->getNumOperands(); + assert(nOps > 1 && "isSplatVector has 0 or 1 sized build vector"); + + SDValue Operand0 = N->getOperand(0); + + for (unsigned int i = 1; i < nOps; ++i) { + if (N->getOperand(i) != Operand0) + return false; + } + + return true; +} + +// Lower ISD::EXTRACT_VECTOR_ELT into MipsISD::VEXTRACT_SEXT_ELT. +// +// The non-value bits resulting from ISD::EXTRACT_VECTOR_ELT are undefined. We +// choose to sign-extend but we could have equally chosen zero-extend. The +// DAGCombiner will fold any sign/zero extension of the ISD::EXTRACT_VECTOR_ELT +// result into this node later (possibly changing it to a zero-extend in the +// process). +SDValue MipsSETargetLowering:: +lowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const { + SDLoc DL(Op); + EVT ResTy = Op->getValueType(0); + SDValue Op0 = Op->getOperand(0); + EVT VecTy = Op0->getValueType(0); + + if (!VecTy.is128BitVector()) + return SDValue(); + + if (ResTy.isInteger()) { + SDValue Op1 = Op->getOperand(1); + EVT EltTy = VecTy.getVectorElementType(); + return DAG.getNode(MipsISD::VEXTRACT_SEXT_ELT, DL, ResTy, Op0, Op1, + DAG.getValueType(EltTy)); + } + + return Op; +} + +static bool isConstantOrUndef(const SDValue Op) { + if (Op->getOpcode() == ISD::UNDEF) + return true; + if (isa<ConstantSDNode>(Op)) + return true; + if (isa<ConstantFPSDNode>(Op)) + return true; + return false; +} + +static bool isConstantOrUndefBUILD_VECTOR(const BuildVectorSDNode *Op) { + for (unsigned i = 0; i < Op->getNumOperands(); ++i) + if (isConstantOrUndef(Op->getOperand(i))) + return true; + return false; +} + +// Lowers ISD::BUILD_VECTOR into appropriate SelectionDAG nodes for the +// backend. +// +// Lowers according to the following rules: +// - Constant splats are legal as-is as long as the SplatBitSize is a power of +// 2 less than or equal to 64 and the value fits into a signed 10-bit +// immediate +// - Constant splats are lowered to bitconverted BUILD_VECTORs if SplatBitSize +// is a power of 2 less than or equal to 64 and the value does not fit into a +// signed 10-bit immediate +// - Non-constant splats are legal as-is. +// - Non-constant non-splats are lowered to sequences of INSERT_VECTOR_ELT. +// - All others are illegal and must be expanded. +SDValue MipsSETargetLowering::lowerBUILD_VECTOR(SDValue Op, + SelectionDAG &DAG) const { + BuildVectorSDNode *Node = cast<BuildVectorSDNode>(Op); + EVT ResTy = Op->getValueType(0); + SDLoc DL(Op); + APInt SplatValue, SplatUndef; + unsigned SplatBitSize; + bool HasAnyUndefs; + + if (!Subtarget.hasMSA() || !ResTy.is128BitVector()) + return SDValue(); + + if (Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, + HasAnyUndefs, 8, + !Subtarget.isLittle()) && SplatBitSize <= 64) { + // We can only cope with 8, 16, 32, or 64-bit elements + if (SplatBitSize != 8 && SplatBitSize != 16 && SplatBitSize != 32 && + SplatBitSize != 64) + return SDValue(); + + // If the value fits into a simm10 then we can use ldi.[bhwd] + // However, if it isn't an integer type we will have to bitcast from an + // integer type first. Also, if there are any undefs, we must lower them + // to defined values first. + if (ResTy.isInteger() && !HasAnyUndefs && SplatValue.isSignedIntN(10)) + return Op; + + EVT ViaVecTy; + + switch (SplatBitSize) { + default: + return SDValue(); + case 8: + ViaVecTy = MVT::v16i8; + break; + case 16: + ViaVecTy = MVT::v8i16; + break; + case 32: + ViaVecTy = MVT::v4i32; + break; + case 64: + // There's no fill.d to fall back on for 64-bit values + return SDValue(); + } + + // SelectionDAG::getConstant will promote SplatValue appropriately. + SDValue Result = DAG.getConstant(SplatValue, DL, ViaVecTy); + + // Bitcast to the type we originally wanted + if (ViaVecTy != ResTy) + Result = DAG.getNode(ISD::BITCAST, SDLoc(Node), ResTy, Result); + + return Result; + } else if (isSplatVector(Node)) + return Op; + else if (!isConstantOrUndefBUILD_VECTOR(Node)) { + // Use INSERT_VECTOR_ELT operations rather than expand to stores. + // The resulting code is the same length as the expansion, but it doesn't + // use memory operations + EVT ResTy = Node->getValueType(0); + + assert(ResTy.isVector()); + + unsigned NumElts = ResTy.getVectorNumElements(); + SDValue Vector = DAG.getUNDEF(ResTy); + for (unsigned i = 0; i < NumElts; ++i) { + Vector = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Vector, + Node->getOperand(i), + DAG.getConstant(i, DL, MVT::i32)); + } + return Vector; + } + + return SDValue(); +} + +// Lower VECTOR_SHUFFLE into SHF (if possible). +// +// SHF splits the vector into blocks of four elements, then shuffles these +// elements according to a <4 x i2> constant (encoded as an integer immediate). +// +// It is therefore possible to lower into SHF when the mask takes the form: +// <a, b, c, d, a+4, b+4, c+4, d+4, a+8, b+8, c+8, d+8, ...> +// When undef's appear they are treated as if they were whatever value is +// necessary in order to fit the above forms. +// +// For example: +// %2 = shufflevector <8 x i16> %0, <8 x i16> undef, +// <8 x i32> <i32 3, i32 2, i32 1, i32 0, +// i32 7, i32 6, i32 5, i32 4> +// is lowered to: +// (SHF_H $w0, $w1, 27) +// where the 27 comes from: +// 3 + (2 << 2) + (1 << 4) + (0 << 6) +static SDValue lowerVECTOR_SHUFFLE_SHF(SDValue Op, EVT ResTy, + SmallVector<int, 16> Indices, + SelectionDAG &DAG) { + int SHFIndices[4] = { -1, -1, -1, -1 }; + + if (Indices.size() < 4) + return SDValue(); + + for (unsigned i = 0; i < 4; ++i) { + for (unsigned j = i; j < Indices.size(); j += 4) { + int Idx = Indices[j]; + + // Convert from vector index to 4-element subvector index + // If an index refers to an element outside of the subvector then give up + if (Idx != -1) { + Idx -= 4 * (j / 4); + if (Idx < 0 || Idx >= 4) + return SDValue(); + } + + // If the mask has an undef, replace it with the current index. + // Note that it might still be undef if the current index is also undef + if (SHFIndices[i] == -1) + SHFIndices[i] = Idx; + + // Check that non-undef values are the same as in the mask. If they + // aren't then give up + if (!(Idx == -1 || Idx == SHFIndices[i])) + return SDValue(); + } + } + + // Calculate the immediate. Replace any remaining undefs with zero + APInt Imm(32, 0); + for (int i = 3; i >= 0; --i) { + int Idx = SHFIndices[i]; + + if (Idx == -1) + Idx = 0; + + Imm <<= 2; + Imm |= Idx & 0x3; + } + + SDLoc DL(Op); + return DAG.getNode(MipsISD::SHF, DL, ResTy, + DAG.getConstant(Imm, DL, MVT::i32), Op->getOperand(0)); +} + +/// Determine whether a range fits a regular pattern of values. +/// This function accounts for the possibility of jumping over the End iterator. +template <typename ValType> +static bool +fitsRegularPattern(typename SmallVectorImpl<ValType>::const_iterator Begin, + unsigned CheckStride, + typename SmallVectorImpl<ValType>::const_iterator End, + ValType ExpectedIndex, unsigned ExpectedIndexStride) { + auto &I = Begin; + + while (I != End) { + if (*I != -1 && *I != ExpectedIndex) + return false; + ExpectedIndex += ExpectedIndexStride; + + // Incrementing past End is undefined behaviour so we must increment one + // step at a time and check for End at each step. + for (unsigned n = 0; n < CheckStride && I != End; ++n, ++I) + ; // Empty loop body. + } + return true; +} + +// Determine whether VECTOR_SHUFFLE is a SPLATI. +// +// It is a SPLATI when the mask is: +// <x, x, x, ...> +// where x is any valid index. +// +// When undef's appear in the mask they are treated as if they were whatever +// value is necessary in order to fit the above form. +static bool isVECTOR_SHUFFLE_SPLATI(SDValue Op, EVT ResTy, + SmallVector<int, 16> Indices, + SelectionDAG &DAG) { + assert((Indices.size() % 2) == 0); + + int SplatIndex = -1; + for (const auto &V : Indices) { + if (V != -1) { + SplatIndex = V; + break; + } + } + + return fitsRegularPattern<int>(Indices.begin(), 1, Indices.end(), SplatIndex, + 0); +} + +// Lower VECTOR_SHUFFLE into ILVEV (if possible). +// +// ILVEV interleaves the even elements from each vector. +// +// It is possible to lower into ILVEV when the mask consists of two of the +// following forms interleaved: +// <0, 2, 4, ...> +// <n, n+2, n+4, ...> +// where n is the number of elements in the vector. +// For example: +// <0, 0, 2, 2, 4, 4, ...> +// <0, n, 2, n+2, 4, n+4, ...> +// +// When undef's appear in the mask they are treated as if they were whatever +// value is necessary in order to fit the above forms. +static SDValue lowerVECTOR_SHUFFLE_ILVEV(SDValue Op, EVT ResTy, + SmallVector<int, 16> Indices, + SelectionDAG &DAG) { + assert((Indices.size() % 2) == 0); + + SDValue Wt; + SDValue Ws; + const auto &Begin = Indices.begin(); + const auto &End = Indices.end(); + + // Check even elements are taken from the even elements of one half or the + // other and pick an operand accordingly. + if (fitsRegularPattern<int>(Begin, 2, End, 0, 2)) + Wt = Op->getOperand(0); + else if (fitsRegularPattern<int>(Begin, 2, End, Indices.size(), 2)) + Wt = Op->getOperand(1); + else + return SDValue(); + + // Check odd elements are taken from the even elements of one half or the + // other and pick an operand accordingly. + if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 2)) + Ws = Op->getOperand(0); + else if (fitsRegularPattern<int>(Begin + 1, 2, End, Indices.size(), 2)) + Ws = Op->getOperand(1); + else + return SDValue(); + + return DAG.getNode(MipsISD::ILVEV, SDLoc(Op), ResTy, Ws, Wt); +} + +// Lower VECTOR_SHUFFLE into ILVOD (if possible). +// +// ILVOD interleaves the odd elements from each vector. +// +// It is possible to lower into ILVOD when the mask consists of two of the +// following forms interleaved: +// <1, 3, 5, ...> +// <n+1, n+3, n+5, ...> +// where n is the number of elements in the vector. +// For example: +// <1, 1, 3, 3, 5, 5, ...> +// <1, n+1, 3, n+3, 5, n+5, ...> +// +// When undef's appear in the mask they are treated as if they were whatever +// value is necessary in order to fit the above forms. +static SDValue lowerVECTOR_SHUFFLE_ILVOD(SDValue Op, EVT ResTy, + SmallVector<int, 16> Indices, + SelectionDAG &DAG) { + assert((Indices.size() % 2) == 0); + + SDValue Wt; + SDValue Ws; + const auto &Begin = Indices.begin(); + const auto &End = Indices.end(); + + // Check even elements are taken from the odd elements of one half or the + // other and pick an operand accordingly. + if (fitsRegularPattern<int>(Begin, 2, End, 1, 2)) + Wt = Op->getOperand(0); + else if (fitsRegularPattern<int>(Begin, 2, End, Indices.size() + 1, 2)) + Wt = Op->getOperand(1); + else + return SDValue(); + + // Check odd elements are taken from the odd elements of one half or the + // other and pick an operand accordingly. + if (fitsRegularPattern<int>(Begin + 1, 2, End, 1, 2)) + Ws = Op->getOperand(0); + else if (fitsRegularPattern<int>(Begin + 1, 2, End, Indices.size() + 1, 2)) + Ws = Op->getOperand(1); + else + return SDValue(); + + return DAG.getNode(MipsISD::ILVOD, SDLoc(Op), ResTy, Wt, Ws); +} + +// Lower VECTOR_SHUFFLE into ILVR (if possible). +// +// ILVR interleaves consecutive elements from the right (lowest-indexed) half of +// each vector. +// +// It is possible to lower into ILVR when the mask consists of two of the +// following forms interleaved: +// <0, 1, 2, ...> +// <n, n+1, n+2, ...> +// where n is the number of elements in the vector. +// For example: +// <0, 0, 1, 1, 2, 2, ...> +// <0, n, 1, n+1, 2, n+2, ...> +// +// When undef's appear in the mask they are treated as if they were whatever +// value is necessary in order to fit the above forms. +static SDValue lowerVECTOR_SHUFFLE_ILVR(SDValue Op, EVT ResTy, + SmallVector<int, 16> Indices, + SelectionDAG &DAG) { + assert((Indices.size() % 2) == 0); + + SDValue Wt; + SDValue Ws; + const auto &Begin = Indices.begin(); + const auto &End = Indices.end(); + + // Check even elements are taken from the right (lowest-indexed) elements of + // one half or the other and pick an operand accordingly. + if (fitsRegularPattern<int>(Begin, 2, End, 0, 1)) + Wt = Op->getOperand(0); + else if (fitsRegularPattern<int>(Begin, 2, End, Indices.size(), 1)) + Wt = Op->getOperand(1); + else + return SDValue(); + + // Check odd elements are taken from the right (lowest-indexed) elements of + // one half or the other and pick an operand accordingly. + if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 1)) + Ws = Op->getOperand(0); + else if (fitsRegularPattern<int>(Begin + 1, 2, End, Indices.size(), 1)) + Ws = Op->getOperand(1); + else + return SDValue(); + + return DAG.getNode(MipsISD::ILVR, SDLoc(Op), ResTy, Ws, Wt); +} + +// Lower VECTOR_SHUFFLE into ILVL (if possible). +// +// ILVL interleaves consecutive elements from the left (highest-indexed) half +// of each vector. +// +// It is possible to lower into ILVL when the mask consists of two of the +// following forms interleaved: +// <x, x+1, x+2, ...> +// <n+x, n+x+1, n+x+2, ...> +// where n is the number of elements in the vector and x is half n. +// For example: +// <x, x, x+1, x+1, x+2, x+2, ...> +// <x, n+x, x+1, n+x+1, x+2, n+x+2, ...> +// +// When undef's appear in the mask they are treated as if they were whatever +// value is necessary in order to fit the above forms. +static SDValue lowerVECTOR_SHUFFLE_ILVL(SDValue Op, EVT ResTy, + SmallVector<int, 16> Indices, + SelectionDAG &DAG) { + assert((Indices.size() % 2) == 0); + + unsigned HalfSize = Indices.size() / 2; + SDValue Wt; + SDValue Ws; + const auto &Begin = Indices.begin(); + const auto &End = Indices.end(); + + // Check even elements are taken from the left (highest-indexed) elements of + // one half or the other and pick an operand accordingly. + if (fitsRegularPattern<int>(Begin, 2, End, HalfSize, 1)) + Wt = Op->getOperand(0); + else if (fitsRegularPattern<int>(Begin, 2, End, Indices.size() + HalfSize, 1)) + Wt = Op->getOperand(1); + else + return SDValue(); + + // Check odd elements are taken from the left (highest-indexed) elements of + // one half or the other and pick an operand accordingly. + if (fitsRegularPattern<int>(Begin + 1, 2, End, HalfSize, 1)) + Ws = Op->getOperand(0); + else if (fitsRegularPattern<int>(Begin + 1, 2, End, Indices.size() + HalfSize, + 1)) + Ws = Op->getOperand(1); + else + return SDValue(); + + return DAG.getNode(MipsISD::ILVL, SDLoc(Op), ResTy, Ws, Wt); +} + +// Lower VECTOR_SHUFFLE into PCKEV (if possible). +// +// PCKEV copies the even elements of each vector into the result vector. +// +// It is possible to lower into PCKEV when the mask consists of two of the +// following forms concatenated: +// <0, 2, 4, ...> +// <n, n+2, n+4, ...> +// where n is the number of elements in the vector. +// For example: +// <0, 2, 4, ..., 0, 2, 4, ...> +// <0, 2, 4, ..., n, n+2, n+4, ...> +// +// When undef's appear in the mask they are treated as if they were whatever +// value is necessary in order to fit the above forms. +static SDValue lowerVECTOR_SHUFFLE_PCKEV(SDValue Op, EVT ResTy, + SmallVector<int, 16> Indices, + SelectionDAG &DAG) { + assert((Indices.size() % 2) == 0); + + SDValue Wt; + SDValue Ws; + const auto &Begin = Indices.begin(); + const auto &Mid = Indices.begin() + Indices.size() / 2; + const auto &End = Indices.end(); + + if (fitsRegularPattern<int>(Begin, 1, Mid, 0, 2)) + Wt = Op->getOperand(0); + else if (fitsRegularPattern<int>(Begin, 1, Mid, Indices.size(), 2)) + Wt = Op->getOperand(1); + else + return SDValue(); + + if (fitsRegularPattern<int>(Mid, 1, End, 0, 2)) + Ws = Op->getOperand(0); + else if (fitsRegularPattern<int>(Mid, 1, End, Indices.size(), 2)) + Ws = Op->getOperand(1); + else + return SDValue(); + + return DAG.getNode(MipsISD::PCKEV, SDLoc(Op), ResTy, Ws, Wt); +} + +// Lower VECTOR_SHUFFLE into PCKOD (if possible). +// +// PCKOD copies the odd elements of each vector into the result vector. +// +// It is possible to lower into PCKOD when the mask consists of two of the +// following forms concatenated: +// <1, 3, 5, ...> +// <n+1, n+3, n+5, ...> +// where n is the number of elements in the vector. +// For example: +// <1, 3, 5, ..., 1, 3, 5, ...> +// <1, 3, 5, ..., n+1, n+3, n+5, ...> +// +// When undef's appear in the mask they are treated as if they were whatever +// value is necessary in order to fit the above forms. +static SDValue lowerVECTOR_SHUFFLE_PCKOD(SDValue Op, EVT ResTy, + SmallVector<int, 16> Indices, + SelectionDAG &DAG) { + assert((Indices.size() % 2) == 0); + + SDValue Wt; + SDValue Ws; + const auto &Begin = Indices.begin(); + const auto &Mid = Indices.begin() + Indices.size() / 2; + const auto &End = Indices.end(); + + if (fitsRegularPattern<int>(Begin, 1, Mid, 1, 2)) + Wt = Op->getOperand(0); + else if (fitsRegularPattern<int>(Begin, 1, Mid, Indices.size() + 1, 2)) + Wt = Op->getOperand(1); + else + return SDValue(); + + if (fitsRegularPattern<int>(Mid, 1, End, 1, 2)) + Ws = Op->getOperand(0); + else if (fitsRegularPattern<int>(Mid, 1, End, Indices.size() + 1, 2)) + Ws = Op->getOperand(1); + else + return SDValue(); + + return DAG.getNode(MipsISD::PCKOD, SDLoc(Op), ResTy, Ws, Wt); +} + +// Lower VECTOR_SHUFFLE into VSHF. +// +// This mostly consists of converting the shuffle indices in Indices into a +// BUILD_VECTOR and adding it as an operand to the resulting VSHF. There is +// also code to eliminate unused operands of the VECTOR_SHUFFLE. For example, +// if the type is v8i16 and all the indices are less than 8 then the second +// operand is unused and can be replaced with anything. We choose to replace it +// with the used operand since this reduces the number of instructions overall. +static SDValue lowerVECTOR_SHUFFLE_VSHF(SDValue Op, EVT ResTy, + SmallVector<int, 16> Indices, + SelectionDAG &DAG) { + SmallVector<SDValue, 16> Ops; + SDValue Op0; + SDValue Op1; + EVT MaskVecTy = ResTy.changeVectorElementTypeToInteger(); + EVT MaskEltTy = MaskVecTy.getVectorElementType(); + bool Using1stVec = false; + bool Using2ndVec = false; + SDLoc DL(Op); + int ResTyNumElts = ResTy.getVectorNumElements(); + + for (int i = 0; i < ResTyNumElts; ++i) { + // Idx == -1 means UNDEF + int Idx = Indices[i]; + + if (0 <= Idx && Idx < ResTyNumElts) + Using1stVec = true; + if (ResTyNumElts <= Idx && Idx < ResTyNumElts * 2) + Using2ndVec = true; + } + + for (SmallVector<int, 16>::iterator I = Indices.begin(); I != Indices.end(); + ++I) + Ops.push_back(DAG.getTargetConstant(*I, DL, MaskEltTy)); + + SDValue MaskVec = DAG.getNode(ISD::BUILD_VECTOR, DL, MaskVecTy, Ops); + + if (Using1stVec && Using2ndVec) { + Op0 = Op->getOperand(0); + Op1 = Op->getOperand(1); + } else if (Using1stVec) + Op0 = Op1 = Op->getOperand(0); + else if (Using2ndVec) + Op0 = Op1 = Op->getOperand(1); + else + llvm_unreachable("shuffle vector mask references neither vector operand?"); + + // 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 +// indices in the shuffle. +SDValue MipsSETargetLowering::lowerVECTOR_SHUFFLE(SDValue Op, + SelectionDAG &DAG) const { + ShuffleVectorSDNode *Node = cast<ShuffleVectorSDNode>(Op); + EVT ResTy = Op->getValueType(0); + + if (!ResTy.is128BitVector()) + return SDValue(); + + int ResTyNumElts = ResTy.getVectorNumElements(); + SmallVector<int, 16> Indices; + + for (int i = 0; i < ResTyNumElts; ++i) + Indices.push_back(Node->getMaskElt(i)); + + // splati.[bhwd] is preferable to the others but is matched from + // MipsISD::VSHF. + if (isVECTOR_SHUFFLE_SPLATI(Op, ResTy, Indices, DAG)) + return lowerVECTOR_SHUFFLE_VSHF(Op, ResTy, Indices, DAG); + SDValue Result = lowerVECTOR_SHUFFLE_ILVEV(Op, ResTy, Indices, DAG); + if (Result.getNode()) + return Result; + Result = lowerVECTOR_SHUFFLE_ILVOD(Op, ResTy, Indices, DAG); + if (Result.getNode()) + return Result; + Result = lowerVECTOR_SHUFFLE_ILVL(Op, ResTy, Indices, DAG); + if (Result.getNode()) + return Result; + Result = lowerVECTOR_SHUFFLE_ILVR(Op, ResTy, Indices, DAG); + if (Result.getNode()) + return Result; + Result = lowerVECTOR_SHUFFLE_PCKEV(Op, ResTy, Indices, DAG); + if (Result.getNode()) + return Result; + Result = lowerVECTOR_SHUFFLE_PCKOD(Op, ResTy, Indices, DAG); + if (Result.getNode()) + return Result; + Result = lowerVECTOR_SHUFFLE_SHF(Op, ResTy, Indices, DAG); + if (Result.getNode()) + return Result; + return lowerVECTOR_SHUFFLE_VSHF(Op, ResTy, Indices, DAG); +} + +MachineBasicBlock * MipsSETargetLowering:: +emitBPOSGE32(MachineInstr *MI, MachineBasicBlock *BB) const{ + // $bb: + // bposge32_pseudo $vr0 + // => + // $bb: + // bposge32 $tbb + // $fbb: + // li $vr2, 0 + // b $sink + // $tbb: + // li $vr1, 1 + // $sink: + // $vr0 = phi($vr2, $fbb, $vr1, $tbb) + + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + DebugLoc DL = MI->getDebugLoc(); + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = std::next(MachineFunction::iterator(BB)); + MachineFunction *F = BB->getParent(); + MachineBasicBlock *FBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *TBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *Sink = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, FBB); + F->insert(It, TBB); + F->insert(It, Sink); + + // Transfer the remainder of BB and its successor edges to Sink. + Sink->splice(Sink->begin(), BB, std::next(MachineBasicBlock::iterator(MI)), + BB->end()); + Sink->transferSuccessorsAndUpdatePHIs(BB); + + // Add successors. + BB->addSuccessor(FBB); + BB->addSuccessor(TBB); + FBB->addSuccessor(Sink); + TBB->addSuccessor(Sink); + + // Insert the real bposge32 instruction to $BB. + BuildMI(BB, DL, TII->get(Mips::BPOSGE32)).addMBB(TBB); + + // Fill $FBB. + unsigned VR2 = RegInfo.createVirtualRegister(RC); + BuildMI(*FBB, FBB->end(), DL, TII->get(Mips::ADDiu), VR2) + .addReg(Mips::ZERO).addImm(0); + BuildMI(*FBB, FBB->end(), DL, TII->get(Mips::B)).addMBB(Sink); + + // Fill $TBB. + unsigned VR1 = RegInfo.createVirtualRegister(RC); + BuildMI(*TBB, TBB->end(), DL, TII->get(Mips::ADDiu), VR1) + .addReg(Mips::ZERO).addImm(1); + + // Insert phi function to $Sink. + BuildMI(*Sink, Sink->begin(), DL, TII->get(Mips::PHI), + MI->getOperand(0).getReg()) + .addReg(VR2).addMBB(FBB).addReg(VR1).addMBB(TBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return Sink; +} + +MachineBasicBlock * MipsSETargetLowering:: +emitMSACBranchPseudo(MachineInstr *MI, MachineBasicBlock *BB, + unsigned BranchOp) const{ + // $bb: + // vany_nonzero $rd, $ws + // => + // $bb: + // bnz.b $ws, $tbb + // b $fbb + // $fbb: + // li $rd1, 0 + // b $sink + // $tbb: + // li $rd2, 1 + // $sink: + // $rd = phi($rd1, $fbb, $rd2, $tbb) + + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + DebugLoc DL = MI->getDebugLoc(); + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = std::next(MachineFunction::iterator(BB)); + MachineFunction *F = BB->getParent(); + MachineBasicBlock *FBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *TBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *Sink = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, FBB); + F->insert(It, TBB); + F->insert(It, Sink); + + // Transfer the remainder of BB and its successor edges to Sink. + Sink->splice(Sink->begin(), BB, std::next(MachineBasicBlock::iterator(MI)), + BB->end()); + Sink->transferSuccessorsAndUpdatePHIs(BB); + + // Add successors. + BB->addSuccessor(FBB); + BB->addSuccessor(TBB); + FBB->addSuccessor(Sink); + TBB->addSuccessor(Sink); + + // Insert the real bnz.b instruction to $BB. + BuildMI(BB, DL, TII->get(BranchOp)) + .addReg(MI->getOperand(1).getReg()) + .addMBB(TBB); + + // Fill $FBB. + unsigned RD1 = RegInfo.createVirtualRegister(RC); + BuildMI(*FBB, FBB->end(), DL, TII->get(Mips::ADDiu), RD1) + .addReg(Mips::ZERO).addImm(0); + BuildMI(*FBB, FBB->end(), DL, TII->get(Mips::B)).addMBB(Sink); + + // Fill $TBB. + unsigned RD2 = RegInfo.createVirtualRegister(RC); + BuildMI(*TBB, TBB->end(), DL, TII->get(Mips::ADDiu), RD2) + .addReg(Mips::ZERO).addImm(1); + + // Insert phi function to $Sink. + BuildMI(*Sink, Sink->begin(), DL, TII->get(Mips::PHI), + MI->getOperand(0).getReg()) + .addReg(RD1).addMBB(FBB).addReg(RD2).addMBB(TBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return Sink; +} + +// Emit the COPY_FW pseudo instruction. +// +// copy_fw_pseudo $fd, $ws, n +// => +// copy_u_w $rt, $ws, $n +// mtc1 $rt, $fd +// +// When n is zero, the equivalent operation can be performed with (potentially) +// zero instructions due to register overlaps. This optimization is never valid +// for lane 1 because it would require FR=0 mode which isn't supported by MSA. +MachineBasicBlock * MipsSETargetLowering:: +emitCOPY_FW(MachineInstr *MI, MachineBasicBlock *BB) const{ + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + DebugLoc DL = MI->getDebugLoc(); + unsigned Fd = MI->getOperand(0).getReg(); + unsigned Ws = MI->getOperand(1).getReg(); + unsigned Lane = MI->getOperand(2).getImm(); + + if (Lane == 0) { + unsigned Wt = Ws; + if (!Subtarget.useOddSPReg()) { + // We must copy to an even-numbered MSA register so that the + // single-precision sub-register is also guaranteed to be even-numbered. + Wt = RegInfo.createVirtualRegister(&Mips::MSA128WEvensRegClass); + + BuildMI(*BB, MI, DL, TII->get(Mips::COPY), Wt).addReg(Ws); + } + + BuildMI(*BB, MI, DL, TII->get(Mips::COPY), Fd).addReg(Wt, 0, Mips::sub_lo); + } else { + unsigned Wt = RegInfo.createVirtualRegister( + Subtarget.useOddSPReg() ? &Mips::MSA128WRegClass : + &Mips::MSA128WEvensRegClass); + + 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); + } + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +// Emit the COPY_FD pseudo instruction. +// +// copy_fd_pseudo $fd, $ws, n +// => +// splati.d $wt, $ws, $n +// copy $fd, $wt:sub_64 +// +// When n is zero, the equivalent operation can be performed with (potentially) +// zero instructions due to register overlaps. This optimization is always +// valid because FR=1 mode which is the only supported mode in MSA. +MachineBasicBlock * MipsSETargetLowering:: +emitCOPY_FD(MachineInstr *MI, MachineBasicBlock *BB) const{ + assert(Subtarget.isFP64bit()); + + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + unsigned Fd = MI->getOperand(0).getReg(); + unsigned Ws = MI->getOperand(1).getReg(); + unsigned Lane = MI->getOperand(2).getImm() * 2; + DebugLoc DL = MI->getDebugLoc(); + + if (Lane == 0) + BuildMI(*BB, MI, DL, TII->get(Mips::COPY), Fd).addReg(Ws, 0, Mips::sub_64); + else { + unsigned Wt = RegInfo.createVirtualRegister(&Mips::MSA128DRegClass); + + BuildMI(*BB, MI, DL, TII->get(Mips::SPLATI_D), Wt).addReg(Ws).addImm(1); + BuildMI(*BB, MI, DL, TII->get(Mips::COPY), Fd).addReg(Wt, 0, Mips::sub_64); + } + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +// Emit the INSERT_FW pseudo instruction. +// +// insert_fw_pseudo $wd, $wd_in, $n, $fs +// => +// subreg_to_reg $wt:sub_lo, $fs +// insve_w $wd[$n], $wd_in, $wt[0] +MachineBasicBlock * +MipsSETargetLowering::emitINSERT_FW(MachineInstr *MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + DebugLoc DL = MI->getDebugLoc(); + unsigned Wd = MI->getOperand(0).getReg(); + unsigned Wd_in = MI->getOperand(1).getReg(); + unsigned Lane = MI->getOperand(2).getImm(); + unsigned Fs = MI->getOperand(3).getReg(); + unsigned Wt = RegInfo.createVirtualRegister( + Subtarget.useOddSPReg() ? &Mips::MSA128WRegClass : + &Mips::MSA128WEvensRegClass); + + BuildMI(*BB, MI, DL, TII->get(Mips::SUBREG_TO_REG), Wt) + .addImm(0) + .addReg(Fs) + .addImm(Mips::sub_lo); + BuildMI(*BB, MI, DL, TII->get(Mips::INSVE_W), Wd) + .addReg(Wd_in) + .addImm(Lane) + .addReg(Wt) + .addImm(0); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +// Emit the INSERT_FD pseudo instruction. +// +// insert_fd_pseudo $wd, $fs, n +// => +// subreg_to_reg $wt:sub_64, $fs +// insve_d $wd[$n], $wd_in, $wt[0] +MachineBasicBlock * +MipsSETargetLowering::emitINSERT_FD(MachineInstr *MI, + MachineBasicBlock *BB) const { + assert(Subtarget.isFP64bit()); + + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + DebugLoc DL = MI->getDebugLoc(); + unsigned Wd = MI->getOperand(0).getReg(); + unsigned Wd_in = MI->getOperand(1).getReg(); + unsigned Lane = MI->getOperand(2).getImm(); + unsigned Fs = MI->getOperand(3).getReg(); + unsigned Wt = RegInfo.createVirtualRegister(&Mips::MSA128DRegClass); + + BuildMI(*BB, MI, DL, TII->get(Mips::SUBREG_TO_REG), Wt) + .addImm(0) + .addReg(Fs) + .addImm(Mips::sub_64); + BuildMI(*BB, MI, DL, TII->get(Mips::INSVE_D), Wd) + .addReg(Wd_in) + .addImm(Lane) + .addReg(Wt) + .addImm(0); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +// Emit the INSERT_([BHWD]|F[WD])_VIDX pseudo instruction. +// +// For integer: +// (INSERT_([BHWD]|F[WD])_PSEUDO $wd, $wd_in, $n, $rs) +// => +// (SLL $lanetmp1, $lane, <log2size) +// (SLD_B $wdtmp1, $wd_in, $wd_in, $lanetmp1) +// (INSERT_[BHWD], $wdtmp2, $wdtmp1, 0, $rs) +// (NEG $lanetmp2, $lanetmp1) +// (SLD_B $wd, $wdtmp2, $wdtmp2, $lanetmp2) +// +// For floating point: +// (INSERT_([BHWD]|F[WD])_PSEUDO $wd, $wd_in, $n, $fs) +// => +// (SUBREG_TO_REG $wt, $fs, <subreg>) +// (SLL $lanetmp1, $lane, <log2size) +// (SLD_B $wdtmp1, $wd_in, $wd_in, $lanetmp1) +// (INSVE_[WD], $wdtmp2, 0, $wdtmp1, 0) +// (NEG $lanetmp2, $lanetmp1) +// (SLD_B $wd, $wdtmp2, $wdtmp2, $lanetmp2) +MachineBasicBlock * +MipsSETargetLowering::emitINSERT_DF_VIDX(MachineInstr *MI, + MachineBasicBlock *BB, + unsigned EltSizeInBytes, + bool IsFP) const { + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + DebugLoc DL = MI->getDebugLoc(); + unsigned Wd = MI->getOperand(0).getReg(); + unsigned SrcVecReg = MI->getOperand(1).getReg(); + unsigned LaneReg = MI->getOperand(2).getReg(); + unsigned SrcValReg = MI->getOperand(3).getReg(); + + const TargetRegisterClass *VecRC = nullptr; + const TargetRegisterClass *GPRRC = + Subtarget.isABI_N64() ? &Mips::GPR64RegClass : &Mips::GPR32RegClass; + unsigned EltLog2Size; + unsigned InsertOp = 0; + unsigned InsveOp = 0; + switch (EltSizeInBytes) { + default: + llvm_unreachable("Unexpected size"); + case 1: + EltLog2Size = 0; + InsertOp = Mips::INSERT_B; + InsveOp = Mips::INSVE_B; + VecRC = &Mips::MSA128BRegClass; + break; + case 2: + EltLog2Size = 1; + InsertOp = Mips::INSERT_H; + InsveOp = Mips::INSVE_H; + VecRC = &Mips::MSA128HRegClass; + break; + case 4: + EltLog2Size = 2; + InsertOp = Mips::INSERT_W; + InsveOp = Mips::INSVE_W; + VecRC = &Mips::MSA128WRegClass; + break; + case 8: + EltLog2Size = 3; + InsertOp = Mips::INSERT_D; + InsveOp = Mips::INSVE_D; + VecRC = &Mips::MSA128DRegClass; + break; + } + + if (IsFP) { + unsigned Wt = RegInfo.createVirtualRegister(VecRC); + BuildMI(*BB, MI, DL, TII->get(Mips::SUBREG_TO_REG), Wt) + .addImm(0) + .addReg(SrcValReg) + .addImm(EltSizeInBytes == 8 ? Mips::sub_64 : Mips::sub_lo); + SrcValReg = Wt; + } + + // Convert the lane index into a byte index + if (EltSizeInBytes != 1) { + unsigned LaneTmp1 = RegInfo.createVirtualRegister(GPRRC); + BuildMI(*BB, MI, DL, TII->get(Mips::SLL), LaneTmp1) + .addReg(LaneReg) + .addImm(EltLog2Size); + LaneReg = LaneTmp1; + } + + // Rotate bytes around so that the desired lane is element zero + unsigned WdTmp1 = RegInfo.createVirtualRegister(VecRC); + BuildMI(*BB, MI, DL, TII->get(Mips::SLD_B), WdTmp1) + .addReg(SrcVecReg) + .addReg(SrcVecReg) + .addReg(LaneReg); + + unsigned WdTmp2 = RegInfo.createVirtualRegister(VecRC); + if (IsFP) { + // Use insve.df to insert to element zero + BuildMI(*BB, MI, DL, TII->get(InsveOp), WdTmp2) + .addReg(WdTmp1) + .addImm(0) + .addReg(SrcValReg) + .addImm(0); + } else { + // Use insert.df to insert to element zero + BuildMI(*BB, MI, DL, TII->get(InsertOp), WdTmp2) + .addReg(WdTmp1) + .addReg(SrcValReg) + .addImm(0); + } + + // Rotate elements the rest of the way for a full rotation. + // sld.df inteprets $rt modulo the number of columns so we only need to negate + // the lane index to do this. + unsigned LaneTmp2 = RegInfo.createVirtualRegister(GPRRC); + BuildMI(*BB, MI, DL, TII->get(Subtarget.isABI_N64() ? Mips::DSUB : Mips::SUB), + LaneTmp2) + .addReg(Subtarget.isABI_N64() ? Mips::ZERO_64 : Mips::ZERO) + .addReg(LaneReg); + BuildMI(*BB, MI, DL, TII->get(Mips::SLD_B), Wd) + .addReg(WdTmp2) + .addReg(WdTmp2) + .addReg(LaneTmp2); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +// Emit the FILL_FW pseudo instruction. +// +// fill_fw_pseudo $wd, $fs +// => +// implicit_def $wt1 +// insert_subreg $wt2:subreg_lo, $wt1, $fs +// splati.w $wd, $wt2[0] +MachineBasicBlock * +MipsSETargetLowering::emitFILL_FW(MachineInstr *MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + DebugLoc DL = MI->getDebugLoc(); + unsigned Wd = MI->getOperand(0).getReg(); + unsigned Fs = MI->getOperand(1).getReg(); + unsigned Wt1 = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass); + unsigned Wt2 = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass); + + BuildMI(*BB, MI, DL, TII->get(Mips::IMPLICIT_DEF), Wt1); + BuildMI(*BB, MI, DL, TII->get(Mips::INSERT_SUBREG), Wt2) + .addReg(Wt1) + .addReg(Fs) + .addImm(Mips::sub_lo); + BuildMI(*BB, MI, DL, TII->get(Mips::SPLATI_W), Wd).addReg(Wt2).addImm(0); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +// Emit the FILL_FD pseudo instruction. +// +// fill_fd_pseudo $wd, $fs +// => +// implicit_def $wt1 +// insert_subreg $wt2:subreg_64, $wt1, $fs +// splati.d $wd, $wt2[0] +MachineBasicBlock * +MipsSETargetLowering::emitFILL_FD(MachineInstr *MI, + MachineBasicBlock *BB) const { + assert(Subtarget.isFP64bit()); + + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + DebugLoc DL = MI->getDebugLoc(); + unsigned Wd = MI->getOperand(0).getReg(); + unsigned Fs = MI->getOperand(1).getReg(); + unsigned Wt1 = RegInfo.createVirtualRegister(&Mips::MSA128DRegClass); + unsigned Wt2 = RegInfo.createVirtualRegister(&Mips::MSA128DRegClass); + + BuildMI(*BB, MI, DL, TII->get(Mips::IMPLICIT_DEF), Wt1); + BuildMI(*BB, MI, DL, TII->get(Mips::INSERT_SUBREG), Wt2) + .addReg(Wt1) + .addReg(Fs) + .addImm(Mips::sub_64); + BuildMI(*BB, MI, DL, TII->get(Mips::SPLATI_D), Wd).addReg(Wt2).addImm(0); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +// Emit the FEXP2_W_1 pseudo instructions. +// +// fexp2_w_1_pseudo $wd, $wt +// => +// ldi.w $ws, 1 +// fexp2.w $wd, $ws, $wt +MachineBasicBlock * +MipsSETargetLowering::emitFEXP2_W_1(MachineInstr *MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + const TargetRegisterClass *RC = &Mips::MSA128WRegClass; + unsigned Ws1 = RegInfo.createVirtualRegister(RC); + unsigned Ws2 = RegInfo.createVirtualRegister(RC); + DebugLoc DL = MI->getDebugLoc(); + + // Splat 1.0 into a vector + BuildMI(*BB, MI, DL, TII->get(Mips::LDI_W), Ws1).addImm(1); + BuildMI(*BB, MI, DL, TII->get(Mips::FFINT_U_W), Ws2).addReg(Ws1); + + // Emit 1.0 * fexp2(Wt) + BuildMI(*BB, MI, DL, TII->get(Mips::FEXP2_W), MI->getOperand(0).getReg()) + .addReg(Ws2) + .addReg(MI->getOperand(1).getReg()); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +// Emit the FEXP2_D_1 pseudo instructions. +// +// fexp2_d_1_pseudo $wd, $wt +// => +// ldi.d $ws, 1 +// fexp2.d $wd, $ws, $wt +MachineBasicBlock * +MipsSETargetLowering::emitFEXP2_D_1(MachineInstr *MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + const TargetRegisterClass *RC = &Mips::MSA128DRegClass; + unsigned Ws1 = RegInfo.createVirtualRegister(RC); + unsigned Ws2 = RegInfo.createVirtualRegister(RC); + DebugLoc DL = MI->getDebugLoc(); + + // Splat 1.0 into a vector + BuildMI(*BB, MI, DL, TII->get(Mips::LDI_D), Ws1).addImm(1); + BuildMI(*BB, MI, DL, TII->get(Mips::FFINT_U_D), Ws2).addReg(Ws1); + + // Emit 1.0 * fexp2(Wt) + BuildMI(*BB, MI, DL, TII->get(Mips::FEXP2_D), MI->getOperand(0).getReg()) + .addReg(Ws2) + .addReg(MI->getOperand(1).getReg()); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.h b/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.h new file mode 100644 index 0000000..d44f8d8 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.h @@ -0,0 +1,117 @@ +//===-- MipsSEISelLowering.h - MipsSE DAG Lowering Interface ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Subclass of MipsTargetLowering specialized for mips32/64. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSSEISELLOWERING_H +#define LLVM_LIB_TARGET_MIPS_MIPSSEISELLOWERING_H + +#include "MipsISelLowering.h" +#include "MipsRegisterInfo.h" + +namespace llvm { + class MipsSETargetLowering : public MipsTargetLowering { + public: + explicit MipsSETargetLowering(const MipsTargetMachine &TM, + const MipsSubtarget &STI); + + /// \brief Enable MSA support for the given integer type and Register + /// class. + void addMSAIntType(MVT::SimpleValueType Ty, const TargetRegisterClass *RC); + /// \brief Enable MSA support for the given floating-point type and + /// Register class. + void addMSAFloatType(MVT::SimpleValueType Ty, + const TargetRegisterClass *RC); + + bool allowsMisalignedMemoryAccesses(EVT VT, unsigned AS = 0, + unsigned Align = 1, + bool *Fast = nullptr) const override; + + SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; + + SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override; + + MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *MBB) const override; + + bool isShuffleMaskLegal(const SmallVectorImpl<int> &Mask, + EVT VT) const override { + return false; + } + + const TargetRegisterClass *getRepRegClassFor(MVT VT) const override; + + private: + bool isEligibleForTailCallOptimization( + const CCState &CCInfo, unsigned NextStackOffset, + const MipsFunctionInfo &FI) const override; + + void + getOpndList(SmallVectorImpl<SDValue> &Ops, + std::deque< std::pair<unsigned, SDValue> > &RegsToPass, + bool IsPICCall, bool GlobalOrExternal, bool InternalLinkage, + bool IsCallReloc, CallLoweringInfo &CLI, SDValue Callee, + SDValue Chain) const override; + + SDValue lowerLOAD(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerSTORE(SDValue Op, SelectionDAG &DAG) const; + + SDValue lowerMulDiv(SDValue Op, unsigned NewOpc, bool HasLo, bool HasHi, + SelectionDAG &DAG) const; + + SDValue lowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const; + /// \brief Lower VECTOR_SHUFFLE into one of a number of instructions + /// depending on the indices in the shuffle. + SDValue lowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const; + + MachineBasicBlock *emitBPOSGE32(MachineInstr *MI, + MachineBasicBlock *BB) const; + MachineBasicBlock *emitMSACBranchPseudo(MachineInstr *MI, + MachineBasicBlock *BB, + unsigned BranchOp) const; + /// \brief Emit the COPY_FW pseudo instruction + MachineBasicBlock *emitCOPY_FW(MachineInstr *MI, + MachineBasicBlock *BB) const; + /// \brief Emit the COPY_FD pseudo instruction + MachineBasicBlock *emitCOPY_FD(MachineInstr *MI, + MachineBasicBlock *BB) const; + /// \brief Emit the INSERT_FW pseudo instruction + MachineBasicBlock *emitINSERT_FW(MachineInstr *MI, + MachineBasicBlock *BB) const; + /// \brief Emit the INSERT_FD pseudo instruction + MachineBasicBlock *emitINSERT_FD(MachineInstr *MI, + MachineBasicBlock *BB) const; + /// \brief Emit the INSERT_([BHWD]|F[WD])_VIDX pseudo instruction + MachineBasicBlock *emitINSERT_DF_VIDX(MachineInstr *MI, + MachineBasicBlock *BB, + unsigned EltSizeInBytes, + bool IsFP) const; + /// \brief Emit the FILL_FW pseudo instruction + MachineBasicBlock *emitFILL_FW(MachineInstr *MI, + MachineBasicBlock *BB) const; + /// \brief Emit the FILL_FD pseudo instruction + MachineBasicBlock *emitFILL_FD(MachineInstr *MI, + MachineBasicBlock *BB) const; + /// \brief Emit the FEXP2_W_1 pseudo instructions. + MachineBasicBlock *emitFEXP2_W_1(MachineInstr *MI, + MachineBasicBlock *BB) const; + /// \brief Emit the FEXP2_D_1 pseudo instructions. + MachineBasicBlock *emitFEXP2_D_1(MachineInstr *MI, + MachineBasicBlock *BB) const; + }; +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp new file mode 100644 index 0000000..e6f7fe9 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp @@ -0,0 +1,712 @@ +//===-- MipsSEInstrInfo.cpp - Mips32/64 Instruction Information -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips32/64 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "MipsSEInstrInfo.h" +#include "InstPrinter/MipsInstPrinter.h" +#include "MipsMachineFunction.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +MipsSEInstrInfo::MipsSEInstrInfo(const MipsSubtarget &STI) + : MipsInstrInfo(STI, STI.getRelocationModel() == Reloc::PIC_ ? Mips::B + : Mips::J), + RI() {} + +const MipsRegisterInfo &MipsSEInstrInfo::getRegisterInfo() const { + return RI; +} + +/// isLoadFromStackSlot - If the specified machine instruction is a direct +/// load from a stack slot, return the virtual or physical register number of +/// the destination along with the FrameIndex of the loaded stack slot. If +/// not, return 0. This predicate must return 0 if the instruction has +/// any side effects other than loading from the stack slot. +unsigned MipsSEInstrInfo::isLoadFromStackSlot(const MachineInstr *MI, + int &FrameIndex) const { + unsigned Opc = MI->getOpcode(); + + if ((Opc == Mips::LW) || (Opc == Mips::LD) || + (Opc == Mips::LWC1) || (Opc == Mips::LDC1) || (Opc == Mips::LDC164)) { + if ((MI->getOperand(1).isFI()) && // is a stack slot + (MI->getOperand(2).isImm()) && // the imm is zero + (isZeroImm(MI->getOperand(2)))) { + FrameIndex = MI->getOperand(1).getIndex(); + return MI->getOperand(0).getReg(); + } + } + + return 0; +} + +/// isStoreToStackSlot - If the specified machine instruction is a direct +/// store to a stack slot, return the virtual or physical register number of +/// the source reg along with the FrameIndex of the loaded stack slot. If +/// not, return 0. This predicate must return 0 if the instruction has +/// any side effects other than storing to the stack slot. +unsigned MipsSEInstrInfo::isStoreToStackSlot(const MachineInstr *MI, + int &FrameIndex) const { + unsigned Opc = MI->getOpcode(); + + if ((Opc == Mips::SW) || (Opc == Mips::SD) || + (Opc == Mips::SWC1) || (Opc == Mips::SDC1) || (Opc == Mips::SDC164)) { + if ((MI->getOperand(1).isFI()) && // is a stack slot + (MI->getOperand(2).isImm()) && // the imm is zero + (isZeroImm(MI->getOperand(2)))) { + FrameIndex = MI->getOperand(1).getIndex(); + return MI->getOperand(0).getReg(); + } + } + return 0; +} + +void MipsSEInstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const { + unsigned Opc = 0, ZeroReg = 0; + bool isMicroMips = Subtarget.inMicroMipsMode(); + + if (Mips::GPR32RegClass.contains(DestReg)) { // Copy to CPU Reg. + if (Mips::GPR32RegClass.contains(SrcReg)) { + if (isMicroMips) + Opc = Mips::MOVE16_MM; + else + Opc = Mips::OR, 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 = 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; + else if (Mips::DSPCCRegClass.contains(SrcReg)) { + BuildMI(MBB, I, DL, get(Mips::RDDSP), DestReg).addImm(1 << 4) + .addReg(SrcReg, RegState::Implicit | getKillRegState(KillSrc)); + return; + } + else if (Mips::MSACtrlRegClass.contains(SrcReg)) + Opc = Mips::CFCMSA; + } + else if (Mips::GPR32RegClass.contains(SrcReg)) { // Copy from CPU Reg. + if (Mips::CCRRegClass.contains(DestReg)) + Opc = Mips::CTC1; + else if (Mips::FGR32RegClass.contains(DestReg)) + Opc = Mips::MTC1; + else if (Mips::HI32RegClass.contains(DestReg)) + Opc = Mips::MTHI, DestReg = 0; + else if (Mips::LO32RegClass.contains(DestReg)) + Opc = Mips::MTLO, DestReg = 0; + else if (Mips::HI32DSPRegClass.contains(DestReg)) + Opc = Mips::MTHI_DSP; + else if (Mips::LO32DSPRegClass.contains(DestReg)) + Opc = Mips::MTLO_DSP; + else if (Mips::DSPCCRegClass.contains(DestReg)) { + BuildMI(MBB, I, DL, get(Mips::WRDSP)) + .addReg(SrcReg, getKillRegState(KillSrc)).addImm(1 << 4) + .addReg(DestReg, RegState::ImplicitDefine); + return; + } + else if (Mips::MSACtrlRegClass.contains(DestReg)) + Opc = Mips::CTCMSA; + } + else if (Mips::FGR32RegClass.contains(DestReg, SrcReg)) + Opc = Mips::FMOV_S; + else if (Mips::AFGR64RegClass.contains(DestReg, SrcReg)) + Opc = Mips::FMOV_D32; + else if (Mips::FGR64RegClass.contains(DestReg, SrcReg)) + Opc = Mips::FMOV_D64; + else if (Mips::GPR64RegClass.contains(DestReg)) { // Copy to CPU64 Reg. + if (Mips::GPR64RegClass.contains(SrcReg)) + Opc = Mips::OR64, ZeroReg = Mips::ZERO_64; + else if (Mips::HI64RegClass.contains(SrcReg)) + Opc = Mips::MFHI64, SrcReg = 0; + else if (Mips::LO64RegClass.contains(SrcReg)) + Opc = Mips::MFLO64, SrcReg = 0; + else if (Mips::FGR64RegClass.contains(SrcReg)) + Opc = Mips::DMFC1; + } + else if (Mips::GPR64RegClass.contains(SrcReg)) { // Copy from CPU64 Reg. + if (Mips::HI64RegClass.contains(DestReg)) + Opc = Mips::MTHI64, DestReg = 0; + else if (Mips::LO64RegClass.contains(DestReg)) + Opc = Mips::MTLO64, DestReg = 0; + else if (Mips::FGR64RegClass.contains(DestReg)) + Opc = Mips::DMTC1; + } + else if (Mips::MSA128BRegClass.contains(DestReg)) { // Copy to MSA reg + if (Mips::MSA128BRegClass.contains(SrcReg)) + Opc = Mips::MOVE_V; + } + + assert(Opc && "Cannot copy registers"); + + MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(Opc)); + + if (DestReg) + MIB.addReg(DestReg, RegState::Define); + + if (SrcReg) + MIB.addReg(SrcReg, getKillRegState(KillSrc)); + + if (ZeroReg) + MIB.addReg(ZeroReg); +} + +void MipsSEInstrInfo:: +storeRegToStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned SrcReg, bool isKill, int FI, + const TargetRegisterClass *RC, const TargetRegisterInfo *TRI, + int64_t Offset) const { + DebugLoc DL; + MachineMemOperand *MMO = GetMemOperand(MBB, FI, MachineMemOperand::MOStore); + + unsigned Opc = 0; + + if (Mips::GPR32RegClass.hasSubClassEq(RC)) + Opc = Mips::SW; + else if (Mips::GPR64RegClass.hasSubClassEq(RC)) + Opc = Mips::SD; + else if (Mips::ACC64RegClass.hasSubClassEq(RC)) + Opc = Mips::STORE_ACC64; + else if (Mips::ACC64DSPRegClass.hasSubClassEq(RC)) + Opc = Mips::STORE_ACC64DSP; + else if (Mips::ACC128RegClass.hasSubClassEq(RC)) + Opc = Mips::STORE_ACC128; + else if (Mips::DSPCCRegClass.hasSubClassEq(RC)) + Opc = Mips::STORE_CCOND_DSP; + else if (Mips::FGR32RegClass.hasSubClassEq(RC)) + Opc = Mips::SWC1; + else if (Mips::AFGR64RegClass.hasSubClassEq(RC)) + Opc = Mips::SDC1; + else if (Mips::FGR64RegClass.hasSubClassEq(RC)) + Opc = Mips::SDC164; + else if (RC->hasType(MVT::v16i8)) + Opc = Mips::ST_B; + else if (RC->hasType(MVT::v8i16) || RC->hasType(MVT::v8f16)) + Opc = Mips::ST_H; + else if (RC->hasType(MVT::v4i32) || RC->hasType(MVT::v4f32)) + Opc = Mips::ST_W; + else if (RC->hasType(MVT::v2i64) || RC->hasType(MVT::v2f64)) + Opc = Mips::ST_D; + else if (Mips::LO32RegClass.hasSubClassEq(RC)) + Opc = Mips::SW; + else if (Mips::LO64RegClass.hasSubClassEq(RC)) + Opc = Mips::SD; + else if (Mips::HI32RegClass.hasSubClassEq(RC)) + Opc = Mips::SW; + else if (Mips::HI64RegClass.hasSubClassEq(RC)) + Opc = Mips::SD; + + // Hi, Lo are normally caller save but they are callee save + // for interrupt handling. + const Function *Func = MBB.getParent()->getFunction(); + if (Func->hasFnAttribute("interrupt")) { + if (Mips::HI32RegClass.hasSubClassEq(RC)) { + BuildMI(MBB, I, DL, get(Mips::MFHI), Mips::K0); + SrcReg = Mips::K0; + } else if (Mips::HI64RegClass.hasSubClassEq(RC)) { + BuildMI(MBB, I, DL, get(Mips::MFHI64), Mips::K0_64); + SrcReg = Mips::K0_64; + } else if (Mips::LO32RegClass.hasSubClassEq(RC)) { + BuildMI(MBB, I, DL, get(Mips::MFLO), Mips::K0); + SrcReg = Mips::K0; + } else if (Mips::LO64RegClass.hasSubClassEq(RC)) { + BuildMI(MBB, I, DL, get(Mips::MFLO64), Mips::K0_64); + SrcReg = Mips::K0_64; + } + } + + assert(Opc && "Register class not handled!"); + BuildMI(MBB, I, DL, get(Opc)).addReg(SrcReg, getKillRegState(isKill)) + .addFrameIndex(FI).addImm(Offset).addMemOperand(MMO); +} + +void MipsSEInstrInfo:: +loadRegFromStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned DestReg, int FI, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, int64_t Offset) const { + DebugLoc DL; + if (I != MBB.end()) DL = I->getDebugLoc(); + MachineMemOperand *MMO = GetMemOperand(MBB, FI, MachineMemOperand::MOLoad); + unsigned Opc = 0; + + const Function *Func = MBB.getParent()->getFunction(); + bool ReqIndirectLoad = Func->hasFnAttribute("interrupt") && + (DestReg == Mips::LO0 || DestReg == Mips::LO0_64 || + DestReg == Mips::HI0 || DestReg == Mips::HI0_64); + + if (Mips::GPR32RegClass.hasSubClassEq(RC)) + Opc = Mips::LW; + else if (Mips::GPR64RegClass.hasSubClassEq(RC)) + Opc = Mips::LD; + else if (Mips::ACC64RegClass.hasSubClassEq(RC)) + Opc = Mips::LOAD_ACC64; + else if (Mips::ACC64DSPRegClass.hasSubClassEq(RC)) + Opc = Mips::LOAD_ACC64DSP; + else if (Mips::ACC128RegClass.hasSubClassEq(RC)) + Opc = Mips::LOAD_ACC128; + else if (Mips::DSPCCRegClass.hasSubClassEq(RC)) + Opc = Mips::LOAD_CCOND_DSP; + else if (Mips::FGR32RegClass.hasSubClassEq(RC)) + Opc = Mips::LWC1; + else if (Mips::AFGR64RegClass.hasSubClassEq(RC)) + Opc = Mips::LDC1; + else if (Mips::FGR64RegClass.hasSubClassEq(RC)) + Opc = Mips::LDC164; + else if (RC->hasType(MVT::v16i8)) + Opc = Mips::LD_B; + else if (RC->hasType(MVT::v8i16) || RC->hasType(MVT::v8f16)) + Opc = Mips::LD_H; + else if (RC->hasType(MVT::v4i32) || RC->hasType(MVT::v4f32)) + Opc = Mips::LD_W; + else if (RC->hasType(MVT::v2i64) || RC->hasType(MVT::v2f64)) + Opc = Mips::LD_D; + else if (Mips::HI32RegClass.hasSubClassEq(RC)) + Opc = Mips::LW; + else if (Mips::HI64RegClass.hasSubClassEq(RC)) + Opc = Mips::LD; + else if (Mips::LO32RegClass.hasSubClassEq(RC)) + Opc = Mips::LW; + else if (Mips::LO64RegClass.hasSubClassEq(RC)) + Opc = Mips::LD; + + assert(Opc && "Register class not handled!"); + + if (!ReqIndirectLoad) + BuildMI(MBB, I, DL, get(Opc), DestReg) + .addFrameIndex(FI) + .addImm(Offset) + .addMemOperand(MMO); + else { + // Load HI/LO through K0. Notably the DestReg is encoded into the + // instruction itself. + unsigned Reg = Mips::K0; + unsigned LdOp = Mips::MTLO; + if (DestReg == Mips::HI0) + LdOp = Mips::MTHI; + + if (Subtarget.getABI().ArePtrs64bit()) { + Reg = Mips::K0_64; + if (DestReg == Mips::HI0_64) + LdOp = Mips::MTHI64; + else + LdOp = Mips::MTLO64; + } + + BuildMI(MBB, I, DL, get(Opc), Reg) + .addFrameIndex(FI) + .addImm(Offset) + .addMemOperand(MMO); + BuildMI(MBB, I, DL, get(LdOp)).addReg(Reg); + } +} + +bool MipsSEInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { + MachineBasicBlock &MBB = *MI->getParent(); + bool isMicroMips = Subtarget.inMicroMipsMode(); + unsigned Opc; + + switch(MI->getDesc().getOpcode()) { + default: + return false; + case Mips::RetRA: + expandRetRA(MBB, MI); + break; + case Mips::ERet: + expandERet(MBB, MI); + break; + case Mips::PseudoMFHI: + Opc = isMicroMips ? Mips::MFHI16_MM : Mips::MFHI; + expandPseudoMFHiLo(MBB, MI, Opc); + break; + case Mips::PseudoMFLO: + Opc = isMicroMips ? Mips::MFLO16_MM : Mips::MFLO; + expandPseudoMFHiLo(MBB, MI, Opc); + break; + case Mips::PseudoMFHI64: + expandPseudoMFHiLo(MBB, MI, Mips::MFHI64); + break; + case Mips::PseudoMFLO64: + expandPseudoMFHiLo(MBB, MI, Mips::MFLO64); + break; + case Mips::PseudoMTLOHI: + expandPseudoMTLoHi(MBB, MI, Mips::MTLO, Mips::MTHI, false); + break; + case Mips::PseudoMTLOHI64: + expandPseudoMTLoHi(MBB, MI, Mips::MTLO64, Mips::MTHI64, false); + break; + case Mips::PseudoMTLOHI_DSP: + expandPseudoMTLoHi(MBB, MI, Mips::MTLO_DSP, Mips::MTHI_DSP, true); + break; + case Mips::PseudoCVT_S_W: + expandCvtFPInt(MBB, MI, Mips::CVT_S_W, Mips::MTC1, false); + break; + case Mips::PseudoCVT_D32_W: + expandCvtFPInt(MBB, MI, Mips::CVT_D32_W, Mips::MTC1, false); + break; + case Mips::PseudoCVT_S_L: + expandCvtFPInt(MBB, MI, Mips::CVT_S_L, Mips::DMTC1, true); + break; + case Mips::PseudoCVT_D64_W: + expandCvtFPInt(MBB, MI, Mips::CVT_D64_W, Mips::MTC1, true); + break; + case Mips::PseudoCVT_D64_L: + expandCvtFPInt(MBB, MI, Mips::CVT_D64_L, Mips::DMTC1, true); + break; + case Mips::BuildPairF64: + expandBuildPairF64(MBB, MI, false); + break; + case Mips::BuildPairF64_64: + expandBuildPairF64(MBB, MI, true); + break; + case Mips::ExtractElementF64: + expandExtractElementF64(MBB, MI, false); + break; + case Mips::ExtractElementF64_64: + expandExtractElementF64(MBB, MI, true); + break; + case Mips::MIPSeh_return32: + case Mips::MIPSeh_return64: + expandEhReturn(MBB, MI); + break; + } + + MBB.erase(MI); + return true; +} + +/// getOppositeBranchOpc - Return the inverse of the specified +/// opcode, e.g. turning BEQ to BNE. +unsigned MipsSEInstrInfo::getOppositeBranchOpc(unsigned Opc) const { + switch (Opc) { + default: llvm_unreachable("Illegal opcode!"); + case Mips::BEQ: return Mips::BNE; + case Mips::BNE: return Mips::BEQ; + case Mips::BGTZ: return Mips::BLEZ; + case Mips::BGEZ: return Mips::BLTZ; + case Mips::BLTZ: return Mips::BGEZ; + case Mips::BLEZ: return Mips::BGTZ; + case Mips::BEQ64: return Mips::BNE64; + case Mips::BNE64: return Mips::BEQ64; + case Mips::BGTZ64: return Mips::BLEZ64; + case Mips::BGEZ64: return Mips::BLTZ64; + case Mips::BLTZ64: return Mips::BGEZ64; + case Mips::BLEZ64: return Mips::BGTZ64; + case Mips::BC1T: return Mips::BC1F; + case Mips::BC1F: return Mips::BC1T; + case Mips::BEQZC_MM: return Mips::BNEZC_MM; + case Mips::BNEZC_MM: return Mips::BEQZC_MM; + } +} + +/// Adjust SP by Amount bytes. +void MipsSEInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + MipsABIInfo ABI = Subtarget.getABI(); + DebugLoc DL; + unsigned ADDu = ABI.GetPtrAdduOp(); + unsigned ADDiu = ABI.GetPtrAddiuOp(); + + if (Amount == 0) + return; + + if (isInt<16>(Amount))// addi sp, sp, amount + BuildMI(MBB, I, DL, get(ADDiu), SP).addReg(SP).addImm(Amount); + else { // Expand immediate that doesn't fit in 16-bit. + unsigned Reg = loadImmediate(Amount, MBB, I, DL, nullptr); + BuildMI(MBB, I, DL, get(ADDu), SP).addReg(SP).addReg(Reg, RegState::Kill); + } +} + +/// This function generates the sequence of instructions needed to get the +/// result of adding register REG and immediate IMM. +unsigned +MipsSEInstrInfo::loadImmediate(int64_t Imm, MachineBasicBlock &MBB, + MachineBasicBlock::iterator II, DebugLoc DL, + unsigned *NewImm) const { + MipsAnalyzeImmediate AnalyzeImm; + const MipsSubtarget &STI = Subtarget; + MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo(); + unsigned Size = STI.isABI_N64() ? 64 : 32; + unsigned LUi = STI.isABI_N64() ? Mips::LUi64 : Mips::LUi; + unsigned ZEROReg = STI.isABI_N64() ? Mips::ZERO_64 : Mips::ZERO; + const TargetRegisterClass *RC = STI.isABI_N64() ? + &Mips::GPR64RegClass : &Mips::GPR32RegClass; + bool LastInstrIsADDiu = NewImm; + + const MipsAnalyzeImmediate::InstSeq &Seq = + AnalyzeImm.Analyze(Imm, Size, LastInstrIsADDiu); + MipsAnalyzeImmediate::InstSeq::const_iterator Inst = Seq.begin(); + + assert(Seq.size() && (!LastInstrIsADDiu || (Seq.size() > 1))); + + // The first instruction can be a LUi, which is different from other + // instructions (ADDiu, ORI and SLL) in that it does not have a register + // operand. + unsigned Reg = RegInfo.createVirtualRegister(RC); + + if (Inst->Opc == LUi) + BuildMI(MBB, II, DL, get(LUi), Reg).addImm(SignExtend64<16>(Inst->ImmOpnd)); + else + BuildMI(MBB, II, DL, get(Inst->Opc), Reg).addReg(ZEROReg) + .addImm(SignExtend64<16>(Inst->ImmOpnd)); + + // Build the remaining instructions in Seq. + for (++Inst; Inst != Seq.end() - LastInstrIsADDiu; ++Inst) + BuildMI(MBB, II, DL, get(Inst->Opc), Reg).addReg(Reg, RegState::Kill) + .addImm(SignExtend64<16>(Inst->ImmOpnd)); + + if (LastInstrIsADDiu) + *NewImm = Inst->ImmOpnd; + + return Reg; +} + +unsigned MipsSEInstrInfo::getAnalyzableBrOpc(unsigned Opc) const { + return (Opc == Mips::BEQ || Opc == Mips::BNE || Opc == Mips::BGTZ || + Opc == Mips::BGEZ || Opc == Mips::BLTZ || Opc == Mips::BLEZ || + Opc == Mips::BEQ64 || Opc == Mips::BNE64 || Opc == Mips::BGTZ64 || + Opc == Mips::BGEZ64 || Opc == Mips::BLTZ64 || Opc == Mips::BLEZ64 || + Opc == Mips::BC1T || Opc == Mips::BC1F || Opc == Mips::B || + Opc == Mips::J || Opc == Mips::BEQZC_MM || Opc == Mips::BNEZC_MM) ? + Opc : 0; +} + +void MipsSEInstrInfo::expandRetRA(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + if (Subtarget.isGP64bit()) + BuildMI(MBB, I, I->getDebugLoc(), get(Mips::PseudoReturn64)) + .addReg(Mips::RA_64); + else + BuildMI(MBB, I, I->getDebugLoc(), get(Mips::PseudoReturn)).addReg(Mips::RA); +} + +void MipsSEInstrInfo::expandERet(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + BuildMI(MBB, I, I->getDebugLoc(), get(Mips::ERET)); +} + +std::pair<bool, bool> +MipsSEInstrInfo::compareOpndSize(unsigned Opc, + const MachineFunction &MF) const { + const MCInstrDesc &Desc = get(Opc); + assert(Desc.NumOperands == 2 && "Unary instruction expected."); + const MipsRegisterInfo *RI = &getRegisterInfo(); + unsigned DstRegSize = getRegClass(Desc, 0, RI, MF)->getSize(); + unsigned SrcRegSize = getRegClass(Desc, 1, RI, MF)->getSize(); + + return std::make_pair(DstRegSize > SrcRegSize, DstRegSize < SrcRegSize); +} + +void MipsSEInstrInfo::expandPseudoMFHiLo(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned NewOpc) const { + BuildMI(MBB, I, I->getDebugLoc(), get(NewOpc), I->getOperand(0).getReg()); +} + +void MipsSEInstrInfo::expandPseudoMTLoHi(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned LoOpc, + unsigned HiOpc, + bool HasExplicitDef) const { + // Expand + // lo_hi pseudomtlohi $gpr0, $gpr1 + // to these two instructions: + // mtlo $gpr0 + // mthi $gpr1 + + DebugLoc DL = I->getDebugLoc(); + const MachineOperand &SrcLo = I->getOperand(1), &SrcHi = I->getOperand(2); + MachineInstrBuilder LoInst = BuildMI(MBB, I, DL, get(LoOpc)); + MachineInstrBuilder HiInst = BuildMI(MBB, I, DL, get(HiOpc)); + LoInst.addReg(SrcLo.getReg(), getKillRegState(SrcLo.isKill())); + HiInst.addReg(SrcHi.getReg(), getKillRegState(SrcHi.isKill())); + + // Add lo/hi registers if the mtlo/hi instructions created have explicit + // def registers. + if (HasExplicitDef) { + unsigned DstReg = I->getOperand(0).getReg(); + unsigned DstLo = getRegisterInfo().getSubReg(DstReg, Mips::sub_lo); + unsigned DstHi = getRegisterInfo().getSubReg(DstReg, Mips::sub_hi); + LoInst.addReg(DstLo, RegState::Define); + HiInst.addReg(DstHi, RegState::Define); + } +} + +void MipsSEInstrInfo::expandCvtFPInt(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned CvtOpc, unsigned MovOpc, + bool IsI64) const { + const MCInstrDesc &CvtDesc = get(CvtOpc), &MovDesc = get(MovOpc); + const MachineOperand &Dst = I->getOperand(0), &Src = I->getOperand(1); + unsigned DstReg = Dst.getReg(), SrcReg = Src.getReg(), TmpReg = DstReg; + unsigned KillSrc = getKillRegState(Src.isKill()); + DebugLoc DL = I->getDebugLoc(); + bool DstIsLarger, SrcIsLarger; + + std::tie(DstIsLarger, SrcIsLarger) = + compareOpndSize(CvtOpc, *MBB.getParent()); + + if (DstIsLarger) + TmpReg = getRegisterInfo().getSubReg(DstReg, Mips::sub_lo); + + if (SrcIsLarger) + DstReg = getRegisterInfo().getSubReg(DstReg, Mips::sub_lo); + + BuildMI(MBB, I, DL, MovDesc, TmpReg).addReg(SrcReg, KillSrc); + BuildMI(MBB, I, DL, CvtDesc, DstReg).addReg(TmpReg, RegState::Kill); +} + +void MipsSEInstrInfo::expandExtractElementF64(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + bool FP64) const { + unsigned DstReg = I->getOperand(0).getReg(); + unsigned SrcReg = I->getOperand(1).getReg(); + unsigned N = I->getOperand(2).getImm(); + DebugLoc dl = I->getDebugLoc(); + + assert(N < 2 && "Invalid immediate"); + unsigned SubIdx = N ? Mips::sub_hi : Mips::sub_lo; + unsigned SubReg = getRegisterInfo().getSubReg(SrcReg, SubIdx); + + // FPXX on MIPS-II or MIPS32r1 should have been handled with a spill/reload + // in MipsSEFrameLowering.cpp. + assert(!(Subtarget.isABI_FPXX() && !Subtarget.hasMips32r2())); + + // FP64A (FP64 with nooddspreg) should have been handled with a spill/reload + // in MipsSEFrameLowering.cpp. + assert(!(Subtarget.isFP64bit() && !Subtarget.useOddSPReg())); + + if (SubIdx == Mips::sub_hi && Subtarget.hasMTHC1()) { + // FIXME: Strictly speaking MFHC1 only reads the top 32-bits however, we + // claim to read the whole 64-bits as part of a white lie used to + // temporarily work around a widespread bug in the -mfp64 support. + // The problem is that none of the 32-bit fpu ops mention the fact + // that they clobber the upper 32-bits of the 64-bit FPR. Fixing that + // requires a major overhaul of the FPU implementation which can't + // be done right now due to time constraints. + // MFHC1 is one of two instructions that are affected since they are + // the only instructions that don't read the lower 32-bits. + // We therefore pretend that it reads the bottom 32-bits to + // artificially create a dependency and prevent the scheduler + // changing the behaviour of the code. + BuildMI(MBB, I, dl, get(FP64 ? Mips::MFHC1_D64 : Mips::MFHC1_D32), DstReg) + .addReg(SrcReg); + } else + BuildMI(MBB, I, dl, get(Mips::MFC1), DstReg).addReg(SubReg); +} + +void MipsSEInstrInfo::expandBuildPairF64(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + bool FP64) const { + unsigned DstReg = I->getOperand(0).getReg(); + unsigned LoReg = I->getOperand(1).getReg(), HiReg = I->getOperand(2).getReg(); + const MCInstrDesc& Mtc1Tdd = get(Mips::MTC1); + DebugLoc dl = I->getDebugLoc(); + const TargetRegisterInfo &TRI = getRegisterInfo(); + + // When mthc1 is available, use: + // mtc1 Lo, $fp + // mthc1 Hi, $fp + // + // Otherwise, for O32 FPXX ABI: + // spill + reload via ldc1 + // This case is handled by the frame lowering code. + // + // Otherwise, for FP32: + // mtc1 Lo, $fp + // mtc1 Hi, $fp + 1 + // + // The case where dmtc1 is available doesn't need to be handled here + // because it never creates a BuildPairF64 node. + + // FPXX on MIPS-II or MIPS32r1 should have been handled with a spill/reload + // in MipsSEFrameLowering.cpp. + assert(!(Subtarget.isABI_FPXX() && !Subtarget.hasMips32r2())); + + // FP64A (FP64 with nooddspreg) should have been handled with a spill/reload + // in MipsSEFrameLowering.cpp. + assert(!(Subtarget.isFP64bit() && !Subtarget.useOddSPReg())); + + BuildMI(MBB, I, dl, Mtc1Tdd, TRI.getSubReg(DstReg, Mips::sub_lo)) + .addReg(LoReg); + + if (Subtarget.hasMTHC1()) { + // FIXME: The .addReg(DstReg) is a white lie used to temporarily work + // around a widespread bug in the -mfp64 support. + // The problem is that none of the 32-bit fpu ops mention the fact + // that they clobber the upper 32-bits of the 64-bit FPR. Fixing that + // requires a major overhaul of the FPU implementation which can't + // be done right now due to time constraints. + // MTHC1 is one of two instructions that are affected since they are + // the only instructions that don't read the lower 32-bits. + // We therefore pretend that it reads the bottom 32-bits to + // artificially create a dependency and prevent the scheduler + // changing the behaviour of the code. + BuildMI(MBB, I, dl, get(FP64 ? Mips::MTHC1_D64 : Mips::MTHC1_D32), DstReg) + .addReg(DstReg) + .addReg(HiReg); + } else if (Subtarget.isABI_FPXX()) + llvm_unreachable("BuildPairF64 not expanded in frame lowering code!"); + else + BuildMI(MBB, I, dl, Mtc1Tdd, TRI.getSubReg(DstReg, Mips::sub_hi)) + .addReg(HiReg); +} + +void MipsSEInstrInfo::expandEhReturn(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + // This pseudo instruction is generated as part of the lowering of + // ISD::EH_RETURN. We convert it to a stack increment by OffsetReg, and + // indirect jump to TargetReg + MipsABIInfo ABI = Subtarget.getABI(); + unsigned ADDU = ABI.GetPtrAdduOp(); + unsigned SP = Subtarget.isGP64bit() ? Mips::SP_64 : Mips::SP; + unsigned RA = Subtarget.isGP64bit() ? Mips::RA_64 : Mips::RA; + unsigned T9 = Subtarget.isGP64bit() ? Mips::T9_64 : Mips::T9; + unsigned ZERO = Subtarget.isGP64bit() ? Mips::ZERO_64 : Mips::ZERO; + unsigned OffsetReg = I->getOperand(0).getReg(); + unsigned TargetReg = I->getOperand(1).getReg(); + + // addu $ra, $v0, $zero + // addu $sp, $sp, $v1 + // jr $ra (via RetRA) + const TargetMachine &TM = MBB.getParent()->getTarget(); + if (TM.getRelocationModel() == Reloc::PIC_) + BuildMI(MBB, I, I->getDebugLoc(), get(ADDU), T9) + .addReg(TargetReg) + .addReg(ZERO); + BuildMI(MBB, I, I->getDebugLoc(), get(ADDU), RA) + .addReg(TargetReg) + .addReg(ZERO); + BuildMI(MBB, I, I->getDebugLoc(), get(ADDU), SP).addReg(SP).addReg(OffsetReg); + expandRetRA(MBB, I); +} + +const MipsInstrInfo *llvm::createMipsSEInstrInfo(const MipsSubtarget &STI) { + return new MipsSEInstrInfo(STI); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.h b/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.h new file mode 100644 index 0000000..5d73545 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.h @@ -0,0 +1,120 @@ +//===-- MipsSEInstrInfo.h - Mips32/64 Instruction Information ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips32/64 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSSEINSTRINFO_H +#define LLVM_LIB_TARGET_MIPS_MIPSSEINSTRINFO_H + +#include "MipsInstrInfo.h" +#include "MipsSERegisterInfo.h" + +namespace llvm { + +class MipsSEInstrInfo : public MipsInstrInfo { + const MipsSERegisterInfo RI; + +public: + explicit MipsSEInstrInfo(const MipsSubtarget &STI); + + const MipsRegisterInfo &getRegisterInfo() const override; + + /// isLoadFromStackSlot - If the specified machine instruction is a direct + /// load from a stack slot, return the virtual or physical register number of + /// the destination along with the FrameIndex of the loaded stack slot. If + /// not, return 0. This predicate must return 0 if the instruction has + /// any side effects other than loading from the stack slot. + unsigned isLoadFromStackSlot(const MachineInstr *MI, + int &FrameIndex) const override; + + /// isStoreToStackSlot - If the specified machine instruction is a direct + /// store to a stack slot, return the virtual or physical register number of + /// the source reg along with the FrameIndex of the loaded stack slot. If + /// not, return 0. This predicate must return 0 if the instruction has + /// any side effects other than storing to the stack slot. + unsigned isStoreToStackSlot(const MachineInstr *MI, + int &FrameIndex) const override; + + void copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const override; + + void storeRegToStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const override; + + void loadRegFromStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const override; + + bool expandPostRAPseudo(MachineBasicBlock::iterator MI) const override; + + unsigned getOppositeBranchOpc(unsigned Opc) const override; + + /// Adjust SP by Amount bytes. + void adjustStackPtr(unsigned SP, int64_t Amount, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const override; + + /// Emit a series of instructions to load an immediate. If NewImm is a + /// non-NULL parameter, the last instruction is not emitted, but instead + /// its immediate operand is returned in NewImm. + unsigned loadImmediate(int64_t Imm, MachineBasicBlock &MBB, + MachineBasicBlock::iterator II, DebugLoc DL, + unsigned *NewImm) const; + +private: + unsigned getAnalyzableBrOpc(unsigned Opc) const override; + + void expandRetRA(MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; + + void expandERet(MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; + + std::pair<bool, bool> compareOpndSize(unsigned Opc, + const MachineFunction &MF) const; + + void expandPseudoMFHiLo(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned NewOpc) const; + + void expandPseudoMTLoHi(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned LoOpc, unsigned HiOpc, + bool HasExplicitDef) const; + + /// Expand pseudo Int-to-FP conversion instructions. + /// + /// For example, the following pseudo instruction + /// PseudoCVT_D32_W D2, A5 + /// gets expanded into these two instructions: + /// MTC1 F4, A5 + /// CVT_D32_W D2, F4 + /// + /// We do this expansion post-RA to avoid inserting a floating point copy + /// instruction between MTC1 and CVT_D32_W. + void expandCvtFPInt(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned CvtOpc, unsigned MovOpc, bool IsI64) const; + + void expandExtractElementF64(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, bool FP64) const; + void expandBuildPairF64(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, bool FP64) const; + void expandEhReturn(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; +}; + +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsSERegisterInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsSERegisterInfo.cpp new file mode 100644 index 0000000..b1e2885 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSERegisterInfo.cpp @@ -0,0 +1,218 @@ +//===-- MipsSERegisterInfo.cpp - MIPS32/64 Register Information -== -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the MIPS32/64 implementation of the TargetRegisterInfo +// class. +// +//===----------------------------------------------------------------------===// + +#include "MipsSERegisterInfo.h" +#include "Mips.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsMachineFunction.h" +#include "MipsSEInstrInfo.h" +#include "MipsSubtarget.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/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" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" + +using namespace llvm; + +#define DEBUG_TYPE "mips-reg-info" + +MipsSERegisterInfo::MipsSERegisterInfo() : MipsRegisterInfo() {} + +bool MipsSERegisterInfo:: +requiresRegisterScavenging(const MachineFunction &MF) const { + return true; +} + +bool MipsSERegisterInfo:: +requiresFrameIndexScavenging(const MachineFunction &MF) const { + return true; +} + +const TargetRegisterClass * +MipsSERegisterInfo::intRegClass(unsigned Size) const { + if (Size == 4) + return &Mips::GPR32RegClass; + + assert(Size == 8); + return &Mips::GPR64RegClass; +} + +/// 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_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 8; + default: + return 1; + } +} + +void MipsSERegisterInfo::eliminateFI(MachineBasicBlock::iterator II, + unsigned OpNo, int FrameIndex, + uint64_t StackSize, + int64_t SPOffset) const { + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + MipsABIInfo ABI = + static_cast<const MipsTargetMachine &>(MF.getTarget()).getABI(); + const MipsRegisterInfo *RegInfo = + static_cast<const MipsRegisterInfo *>(MF.getSubtarget().getRegisterInfo()); + + const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); + int MinCSFI = 0; + int MaxCSFI = -1; + + if (CSI.size()) { + MinCSFI = CSI[0].getFrameIdx(); + MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); + } + + bool EhDataRegFI = MipsFI->isEhDataRegFI(FrameIndex); + bool IsISRRegFI = MipsFI->isISRRegFI(FrameIndex); + // The following stack frame objects are always referenced relative to $sp: + // 1. Outgoing arguments. + // 2. Pointer to dynamically allocated stack space. + // 3. Locations for callee-saved registers. + // 4. Locations for eh data registers. + // 5. Locations for ISR saved Coprocessor 0 registers 12 & 14. + // Everything else is referenced relative to whatever register + // getFrameRegister() returns. + unsigned FrameReg; + + if ((FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI) || EhDataRegFI || + IsISRRegFI) + FrameReg = ABI.GetStackPtr(); + else if (RegInfo->needsStackRealignment(MF)) { + if (MFI->hasVarSizedObjects() && !MFI->isFixedObjectIndex(FrameIndex)) + FrameReg = ABI.GetBasePtr(); + else if (MFI->isFixedObjectIndex(FrameIndex)) + FrameReg = getFrameRegister(MF); + else + FrameReg = ABI.GetStackPtr(); + } else + FrameReg = getFrameRegister(MF); + + // Calculate final offset. + // - There is no need to change the offset if the frame object is one of the + // following: an outgoing argument, pointer to a dynamically allocated + // stack space or a $gp restore location, + // - If the frame object is any of the following, its offset must be adjusted + // by adding the size of the stack: + // incoming argument, callee-saved register location or local variable. + bool IsKill = false; + int64_t Offset; + + Offset = SPOffset + (int64_t)StackSize; + Offset += MI.getOperand(OpNo + 1).getImm(); + + DEBUG(errs() << "Offset : " << Offset << "\n" << "<--------->\n"); + + if (!MI.isDebugValue()) { + // Make sure Offset fits within the field available. + // For MSA instructions, this is a 10-bit signed immediate (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(); + const TargetRegisterClass *PtrRC = + ABI.ArePtrs64bit() ? &Mips::GPR64RegClass : &Mips::GPR32RegClass; + MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo(); + unsigned Reg = RegInfo.createVirtualRegister(PtrRC); + const MipsSEInstrInfo &TII = + *static_cast<const MipsSEInstrInfo *>( + MBB.getParent()->getSubtarget().getInstrInfo()); + BuildMI(MBB, II, DL, TII.get(ABI.GetPtrAddiuOp()), Reg) + .addReg(FrameReg) + .addImm(Offset); + + FrameReg = Reg; + Offset = 0; + IsKill = true; + } else if (!isInt<16>(Offset)) { + // Otherwise split the offset into 16-bit pieces and add it in multiple + // instructions. + MachineBasicBlock &MBB = *MI.getParent(); + DebugLoc DL = II->getDebugLoc(); + unsigned NewImm = 0; + const MipsSEInstrInfo &TII = + *static_cast<const MipsSEInstrInfo *>( + MBB.getParent()->getSubtarget().getInstrInfo()); + unsigned Reg = TII.loadImmediate(Offset, MBB, II, DL, + OffsetBitSize == 16 ? &NewImm : nullptr); + BuildMI(MBB, II, DL, TII.get(ABI.GetPtrAdduOp()), Reg).addReg(FrameReg) + .addReg(Reg, RegState::Kill); + + FrameReg = Reg; + Offset = SignExtend64<16>(NewImm); + IsKill = true; + } + } + + MI.getOperand(OpNo).ChangeToRegister(FrameReg, false, false, IsKill); + MI.getOperand(OpNo + 1).ChangeToImmediate(Offset); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsSERegisterInfo.h b/contrib/llvm/lib/Target/Mips/MipsSERegisterInfo.h new file mode 100644 index 0000000..ebae190 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSERegisterInfo.h @@ -0,0 +1,41 @@ +//===-- MipsSERegisterInfo.h - Mips32/64 Register Information ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips32/64 implementation of the TargetRegisterInfo +// class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSSEREGISTERINFO_H +#define LLVM_LIB_TARGET_MIPS_MIPSSEREGISTERINFO_H + +#include "MipsRegisterInfo.h" + +namespace llvm { +class MipsSEInstrInfo; + +class MipsSERegisterInfo : public MipsRegisterInfo { +public: + MipsSERegisterInfo(); + + bool requiresRegisterScavenging(const MachineFunction &MF) const override; + + bool requiresFrameIndexScavenging(const MachineFunction &MF) const override; + + const TargetRegisterClass *intRegClass(unsigned Size) const override; + +private: + void eliminateFI(MachineBasicBlock::iterator II, unsigned OpNo, + int FrameIndex, uint64_t StackSize, + int64_t SPOffset) const override; +}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsSchedule.td b/contrib/llvm/lib/Target/Mips/MipsSchedule.td new file mode 100644 index 0000000..37f9e49 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSchedule.td @@ -0,0 +1,375 @@ +//===-- MipsSchedule.td - Mips Scheduling Definitions ------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Functional units across Mips chips sets. Based on GCC/Mips backend files. +//===----------------------------------------------------------------------===// +def ALU : FuncUnit; +def IMULDIV : FuncUnit; + +//===----------------------------------------------------------------------===// +// Instruction Itinerary classes used for Mips +//===----------------------------------------------------------------------===// +// IIM16Alu is a placeholder class for most MIPS16 instructions. +def IIM16Alu : 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_B : InstrItinClass; +def II_BADDU : InstrItinClass; +def II_BBIT : InstrItinClass; // bbit[01], bbit[01]32 +def II_BC : InstrItinClass; +def II_BC1F : InstrItinClass; +def II_BC1FL : InstrItinClass; +def II_BC1T : InstrItinClass; +def II_BC1TL : InstrItinClass; +def II_BCC : InstrItinClass; // beq and bne +def II_BCCZ : InstrItinClass; // b[gl][et]z +def II_BCCZAL : InstrItinClass; // bgezal and bltzal +def II_BCCZALS : InstrItinClass; // bgezals and bltzals +def II_BCCZC : InstrItinClass; // beqzc, bnezc +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_EXT : InstrItinClass; // Any EXT instruction +def II_FLOOR : InstrItinClass; +def II_INS : InstrItinClass; // Any INS instruction +def II_IndirectBranchPseudo : InstrItinClass; // Indirect branch pseudo. +def II_J : InstrItinClass; +def II_JAL : InstrItinClass; +def II_JALR : InstrItinClass; +def II_JALRC : InstrItinClass; +def II_JALRS : InstrItinClass; +def II_JALS : InstrItinClass; +def II_JR : InstrItinClass; +def II_JRADDIUSP : InstrItinClass; +def II_JRC : InstrItinClass; +def II_ReturnPseudo : InstrItinClass; // Return pseudo. +def II_LB : InstrItinClass; +def II_LBE : InstrItinClass; +def II_LBU : InstrItinClass; +def II_LBUE : 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_LHE : InstrItinClass; +def II_LHU : InstrItinClass; +def II_LHUE : InstrItinClass; +def II_LUI : InstrItinClass; +def II_LUXC1 : InstrItinClass; +def II_LW : InstrItinClass; +def II_LWE : InstrItinClass; +def II_LWC1 : InstrItinClass; +def II_LWL : InstrItinClass; +def II_LWLE : InstrItinClass; +def II_LWR : InstrItinClass; +def II_LWRE : 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_SBE : 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_SHE : 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_SWE : InstrItinClass; +def II_SWC1 : InstrItinClass; +def II_SWL : InstrItinClass; +def II_SWLE : InstrItinClass; +def II_SWR : InstrItinClass; +def II_SWRE : InstrItinClass; +def II_SWXC1 : InstrItinClass; +def II_TRUNC : InstrItinClass; +def II_WSBH : InstrItinClass; +def II_XOR : InstrItinClass; +def II_XORI : InstrItinClass; + +//===----------------------------------------------------------------------===// +// Mips Generic instruction itineraries. +//===----------------------------------------------------------------------===// +def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [ + InstrItinData<IIM16Alu , [InstrStage<1, [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_EXT , [InstrStage<1, [ALU]>]>, + InstrItinData<II_INS , [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<II_B , [InstrStage<1, [ALU]>]>, + InstrItinData<II_BBIT , [InstrStage<1, [ALU]>]>, + InstrItinData<II_BC , [InstrStage<1, [ALU]>]>, + InstrItinData<II_BC1F , [InstrStage<1, [ALU]>]>, + InstrItinData<II_BC1FL , [InstrStage<1, [ALU]>]>, + InstrItinData<II_BC1T , [InstrStage<1, [ALU]>]>, + InstrItinData<II_BC1TL , [InstrStage<1, [ALU]>]>, + InstrItinData<II_BCC , [InstrStage<1, [ALU]>]>, + InstrItinData<II_BCCZ , [InstrStage<1, [ALU]>]>, + InstrItinData<II_BCCZAL , [InstrStage<1, [ALU]>]>, + InstrItinData<II_BCCZALS , [InstrStage<1, [ALU]>]>, + InstrItinData<II_BCCZC , [InstrStage<1, [ALU]>]>, + InstrItinData<II_IndirectBranchPseudo, [InstrStage<1, [ALU]>]>, + InstrItinData<II_J , [InstrStage<1, [ALU]>]>, + InstrItinData<II_JAL , [InstrStage<1, [ALU]>]>, + InstrItinData<II_JALR , [InstrStage<1, [ALU]>]>, + InstrItinData<II_JALRC , [InstrStage<1, [ALU]>]>, + InstrItinData<II_JALRS , [InstrStage<1, [ALU]>]>, + InstrItinData<II_JALS , [InstrStage<1, [ALU]>]>, + InstrItinData<II_JR , [InstrStage<1, [ALU]>]>, + InstrItinData<II_JRADDIUSP , [InstrStage<1, [ALU]>]>, + InstrItinData<II_JRC , [InstrStage<1, [ALU]>]>, + InstrItinData<II_ReturnPseudo , [InstrStage<1, [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]>]> +]>; + +include "MipsScheduleP5600.td" diff --git a/contrib/llvm/lib/Target/Mips/MipsScheduleP5600.td b/contrib/llvm/lib/Target/Mips/MipsScheduleP5600.td new file mode 100644 index 0000000..d32ae4f --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsScheduleP5600.td @@ -0,0 +1,392 @@ +//==- MipsScheduleP5600.td - P5600 Scheduling Definitions --*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +def MipsP5600Model : SchedMachineModel { + int IssueWidth = 2; // 2x dispatched per cycle + int MicroOpBufferSize = 48; // min(48, 48, 64) + int LoadLatency = 4; + int MispredictPenalty = 8; // TODO: Estimated + + let CompleteModel = 1; +} + +let SchedModel = MipsP5600Model in { + +// ALQ Pipelines +// ============= + +def P5600ALQ : ProcResource<1> { let BufferSize = 16; } +def P5600IssueALU : ProcResource<1> { let Super = P5600ALQ; } + +// ALU Pipeline +// ------------ + +def P5600WriteALU : SchedWriteRes<[P5600IssueALU]>; + +// and, lui, nor, or, slti, sltiu, sub, subu, xor +def : ItinRW<[P5600WriteALU], + [II_AND, II_LUI, II_NOR, II_OR, II_SLTI_SLTIU, II_SUBU, II_XOR]>; + +// AGQ Pipelines +// ============= + +def P5600AGQ : ProcResource<3> { let BufferSize = 16; } +def P5600IssueAL2 : ProcResource<1> { let Super = P5600AGQ; } +def P5600IssueCTISTD : ProcResource<1> { let Super = P5600AGQ; } +def P5600IssueLDST : ProcResource<1> { let Super = P5600AGQ; } + +def P5600AL2Div : ProcResource<1>; +// Pseudo-resource used to block CTISTD when handling multi-pipeline splits. +def P5600CTISTD : ProcResource<1>; + +// CTISTD Pipeline +// --------------- + +def P5600WriteJump : SchedWriteRes<[P5600IssueCTISTD, P5600CTISTD]>; +def P5600WriteJumpAndLink : SchedWriteRes<[P5600IssueCTISTD, P5600CTISTD]> { + let Latency = 2; +} + +// b, beq, beql, bg[et]z, bl[et]z, bne, bnel, j, syscall, jal, bltzal, jalx, +// jalr, jr.hb, jr +def : ItinRW<[P5600WriteJump], [II_B, II_BCC, II_BCCZ, II_BCCZAL, II_J, II_JR]>; +def : ItinRW<[P5600WriteJumpAndLink], [II_JAL, II_JALR]>; + +// LDST Pipeline +// ------------- + +def P5600WriteLoad : SchedWriteRes<[P5600IssueLDST]> { + let Latency = 4; +} + +def P5600WriteLoadShifted : SchedWriteRes<[P5600IssueLDST, P5600CTISTD]> { + let Latency = 4; +} + +def P5600WritePref : SchedWriteRes<[P5600IssueLDST]>; + +def P5600WriteStore : SchedWriteRes<[P5600IssueLDST, P5600CTISTD]> { + // FIXME: This is a bit pessimistic. P5600CTISTD is only used during cycle 2 + // not during 0, 1, and 2. + let ResourceCycles = [ 1, 3 ]; +} + +def P5600WriteGPRFromBypass : SchedWriteRes<[P5600IssueLDST]> { + let Latency = 2; +} + +def P5600WriteStoreFromOtherUnits : SchedWriteRes<[P5600IssueLDST]>; +def P5600WriteLoadToOtherUnits : SchedWriteRes<[P5600IssueLDST]> { + let Latency = 0; +} + +// l[bhw], l[bh]u, ll +def : ItinRW<[P5600WriteLoad], [II_LB, II_LBU, II_LH, II_LHU, II_LW, II_LWU]>; + +// lw[lr] +def : ItinRW<[P5600WriteLoadShifted], [II_LWL, II_LWR]>; + +// s[bhw], sw[lr] +def : ItinRW<[P5600WriteStore], [II_SB, II_SH, II_SW, II_SWL, II_SWR]>; + +// pref +// (this instruction does not exist in the backend yet) +def : ItinRW<[P5600WritePref], []>; + +// sc +// (this instruction does not exist in the backend yet) +def : ItinRW<[P5600WriteStore], []>; + +// LDST is also used in moves from general purpose registers to floating point +// and MSA. +def P5600WriteMoveGPRToOtherUnits : SchedWriteRes<[P5600IssueLDST]> { + let Latency = 0; +} + +// AL2 Pipeline +// ------------ + +def P5600WriteAL2 : SchedWriteRes<[P5600IssueAL2]>; +def P5600WriteAL2BitExt : SchedWriteRes<[P5600IssueAL2]> { let Latency = 2; } +def P5600WriteAL2ShadowMov : SchedWriteRes<[P5600IssueAL2]> { let Latency = 2; } +def P5600WriteAL2CondMov : SchedWriteRes<[P5600IssueAL2, P5600CTISTD]> { + let Latency = 2; +} +def P5600WriteAL2Div : SchedWriteRes<[P5600IssueAL2, P5600AL2Div]> { + // Estimated worst case + let Latency = 34; + let ResourceCycles = [1, 34]; +} +def P5600WriteAL2DivU : SchedWriteRes<[P5600IssueAL2, P5600AL2Div]> { + // Estimated worst case + let Latency = 34; + let ResourceCycles = [1, 34]; +} +def P5600WriteAL2Mul : SchedWriteRes<[P5600IssueAL2]> { let Latency = 3; } +def P5600WriteAL2Mult: SchedWriteRes<[P5600IssueAL2]> { let Latency = 5; } +def P5600WriteAL2MAdd: SchedWriteRes<[P5600IssueAL2, P5600CTISTD]> { + let Latency = 5; +} + +// clo, clz, di, mfhi, mflo +def : ItinRW<[P5600WriteAL2], [II_CLO, II_CLZ, II_MFHI_MFLO]>; + +// ehb, rdhwr, rdpgpr, wrpgpr, wsbh +def : ItinRW<[P5600WriteAL2ShadowMov], [II_RDHWR]>; + +// mov[nz] +def : ItinRW<[P5600WriteAL2CondMov], [II_MOVN, II_MOVZ]>; + +// divu? +def : ItinRW<[P5600WriteAL2Div], [II_DIV]>; +def : ItinRW<[P5600WriteAL2DivU], [II_DIVU]>; + +// mul +def : ItinRW<[P5600WriteAL2Mul], [II_MUL]>; +// multu?, multu? +def : ItinRW<[P5600WriteAL2Mult], [II_MULT, II_MULTU]>; +// maddu?, msubu?, mthi, mtlo +def : ItinRW<[P5600WriteAL2MAdd], + [II_MADD, II_MADDU, II_MSUB, II_MSUBU, II_MTHI_MTLO]>; + +// ext, ins +def : ItinRW<[P5600WriteAL2BitExt], + [II_EXT, II_INS]>; + +// Either ALU or AL2 Pipelines +// --------------------------- +// +// Some instructions can choose between ALU and AL2, but once dispatched to +// ALQ or AGQ respectively they are committed to that path. +// The decision is based on the outcome of the most recent selection when the +// choice was last available. For now, we assume ALU is always chosen. + +def P5600WriteEitherALU : SchedWriteVariant< + // FIXME: Implement selection predicate + [SchedVar<SchedPredicate<[{1}]>, [P5600WriteALU]>, + SchedVar<SchedPredicate<[{0}]>, [P5600WriteAL2]> + ]>; + +// add, addi, addiu, addu, andi, ori, rotr, se[bh], sllv?, sr[al]v?, slt, sltu, +// xori +def : ItinRW<[P5600WriteEitherALU], + [II_ADDI, II_ADDIU, II_ANDI, II_ORI, II_ROTR, II_SEB, II_SEH, + II_SLT_SLTU, II_SLL, II_SRA, II_SRL, II_XORI, II_ADDU, II_SLLV, + II_SRAV, II_SRLV]>; + +// FPU Pipelines +// ============= + +def P5600FPQ : ProcResource<3> { let BufferSize = 16; } +def P5600IssueFPUS : ProcResource<1> { let Super = P5600FPQ; } +def P5600IssueFPUL : ProcResource<1> { let Super = P5600FPQ; } +def P5600IssueFPULoad : ProcResource<1> { let Super = P5600FPQ; } + +def P5600FPUDivSqrt : ProcResource<2>; + +def P5600WriteFPUS : SchedWriteRes<[P5600IssueFPUS]>; +def P5600WriteFPUL : SchedWriteRes<[P5600IssueFPUL]> { let Latency = 4; } +def P5600WriteFPUL_MADDSUB : SchedWriteRes<[P5600IssueFPUL]> { let Latency = 6; } +def P5600WriteFPUDivS : SchedWriteRes<[P5600IssueFPUL, P5600FPUDivSqrt]> { + // Best/Common/Worst case = 7 / 23 / 27 + let Latency = 23; // Using common case + let ResourceCycles = [ 1, 23 ]; +} +def P5600WriteFPUDivD : SchedWriteRes<[P5600IssueFPUL, P5600FPUDivSqrt]> { + // Best/Common/Worst case = 7 / 31 / 35 + let Latency = 31; // Using common case + let ResourceCycles = [ 1, 31 ]; +} +def P5600WriteFPURcpS : SchedWriteRes<[P5600IssueFPUL, P5600FPUDivSqrt]> { + // Best/Common/Worst case = 7 / 19 / 23 + let Latency = 19; // Using common case + let ResourceCycles = [ 1, 19 ]; +} +def P5600WriteFPURcpD : SchedWriteRes<[P5600IssueFPUL, P5600FPUDivSqrt]> { + // Best/Common/Worst case = 7 / 27 / 31 + let Latency = 27; // Using common case + let ResourceCycles = [ 1, 27 ]; +} +def P5600WriteFPURsqrtS : SchedWriteRes<[P5600IssueFPUL, P5600FPUDivSqrt]> { + // Best/Common/Worst case = 7 / 27 / 27 + let Latency = 27; // Using common case + let ResourceCycles = [ 1, 27 ]; +} +def P5600WriteFPURsqrtD : SchedWriteRes<[P5600IssueFPUL, P5600FPUDivSqrt]> { + // Best/Common/Worst case = 7 / 27 / 31 + let Latency = 27; // Using common case + let ResourceCycles = [ 1, 27 ]; +} +def P5600WriteFPUSqrtS : SchedWriteRes<[P5600IssueFPUL, P5600FPUDivSqrt]> { + // Best/Common/Worst case = 7 / 27 / 31 + let Latency = 27; // Using common case + let ResourceCycles = [ 1, 27 ]; +} +def P5600WriteFPUSqrtD : SchedWriteRes<[P5600IssueFPUL, P5600FPUDivSqrt]> { + // Best/Common/Worst case = 7 / 35 / 39 + let Latency = 35; // Using common case + let ResourceCycles = [ 1, 35 ]; +} +def P5600WriteMSAShortLogic : SchedWriteRes<[P5600IssueFPUS]>; +def P5600WriteMSAShortInt : SchedWriteRes<[P5600IssueFPUS]> { let Latency = 2; } +def P5600WriteMoveOtherUnitsToFPU : SchedWriteRes<[P5600IssueFPUS]>; + +// FPUS is also used in moves from floating point and MSA registers to general +// purpose registers. +def P5600WriteMoveFPUSToOtherUnits : SchedWriteRes<[P5600IssueFPUS]> { + let Latency = 0; +} + +// FPUL is also used in moves from floating point and MSA registers to general +// purpose registers. +def P5600WriteMoveFPULToOtherUnits : SchedWriteRes<[P5600IssueFPUL]>; + +// Short Pipe +// ---------- +// +// abs.[ds], abs.ps, bc1[tf]l?, mov[tf].[ds], mov[tf], mov.[ds], [cm][ft]c1, +// m[ft]hc1, neg.[ds], neg.ps, nor.v, nori.b, or.v, ori.b, xor.v, xori.b, +// sdxc1, sdc1, st.[bhwd], swc1, swxc1 +def : ItinRW<[P5600WriteFPUS], [II_ABS, II_MOVF_D, II_MOVF_S, II_MOVT_D, + II_MOVT_S, II_MOV_D, II_MOV_S, II_NEG]>; + +// adds_a.[bhwd], adds_[asu].[bhwd], addvi?.[bhwd], asub_[us].[bhwd], +// aver?_[us].[bhwd] +def : InstRW<[P5600WriteMSAShortInt], (instregex "^ADD_A_[BHWD]$")>; +def : InstRW<[P5600WriteMSAShortInt], (instregex "^ADDS_[ASU]_[BHWD]$")>; +// TODO: ADDVI_[BHW] might be 1 cycle latency rather than 2. Need to confirm it. +def : InstRW<[P5600WriteMSAShortInt], (instregex "^ADDVI?_[BHWD]$")>; +def : InstRW<[P5600WriteMSAShortInt], (instregex "^ASUB_[US].[BHWD]$")>; +def : InstRW<[P5600WriteMSAShortInt], (instregex "^AVER?_[US].[BHWD]$")>; + +// and.v, andi.b, move.v, ldi.[bhwd] +def : InstRW<[P5600WriteMSAShortLogic], (instregex "^MOVE_V$")>; +def : InstRW<[P5600WriteMSAShortLogic], (instregex "^LDI_[BHWD]$")>; +def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(AND|OR|[XN]OR)_V$")>; +def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(AND|OR|[XN]OR)I_B$")>; + +// Long Pipe +// ---------- +// +// add.[ds], add.ps, cvt.d.[sw], cvt.s.[dw], cvt.w.[sd], cvt.[sw].ps, +// cvt.ps.[sw], c.<cc>.[ds], c.<cc>.ps, mul.[ds], mul.ps, sub.[ds], sub.ps, +// trunc.w.[ds], trunc.w.ps +def : ItinRW<[P5600WriteFPUL], + [II_ADD_D, II_ADD_S, II_CVT, II_C_CC_D, II_C_CC_S, II_MUL_D, + II_MUL_S, II_SUB_D, II_SUB_S, II_TRUNC]>; + +// div.[ds], div.ps +def : ItinRW<[P5600WriteFPUDivS], [II_DIV_S]>; +def : ItinRW<[P5600WriteFPUDivD], [II_DIV_D]>; + +// sqrt.[ds], sqrt.ps +def : ItinRW<[P5600WriteFPUSqrtS], [II_SQRT_S]>; +def : ItinRW<[P5600WriteFPUSqrtD], [II_SQRT_D]>; + +// madd.[ds], msub.[ds], nmadd.[ds], nmsub.[ds], +// Operand 0 is read on cycle 5. All other operands are read on operand 0. +def : ItinRW<[SchedReadAdvance<5>, P5600WriteFPUL_MADDSUB], + [II_MADD_D, II_MADD_S, II_MSUB_D, II_MSUB_S, II_NMADD_D, + II_NMADD_S, II_NMSUB_D, II_NMSUB_S]>; + +// madd.ps, msub.ps, nmadd.ps, nmsub.ps +// Operand 0 and 1 are read on cycle 5. All others are read on operand 0. +// (none of these instructions exist in the backend yet) + +// Load Pipe +// --------- +// +// This is typically used in conjunction with the load pipeline under the AGQ +// All the instructions are in the 'Tricky Instructions' section. + +def P5600WriteLoadOtherUnitsToFPU : SchedWriteRes<[P5600IssueFPULoad]> { + let Latency = 4; +} + +// Tricky Instructions +// =================== +// +// These instructions are split across multiple uops (in different pipelines) +// that must cooperate to complete the operation + +// FIXME: This isn't quite right since the implementation of WriteSequence +// current aggregates the resources and ignores the exact cycle they are +// used. +def P5600WriteMoveGPRToFPU : WriteSequence<[P5600WriteMoveGPRToOtherUnits, + P5600WriteMoveOtherUnitsToFPU]>; + +// FIXME: This isn't quite right since the implementation of WriteSequence +// current aggregates the resources and ignores the exact cycle they are +// used. +def P5600WriteMoveFPUToGPR : WriteSequence<[P5600WriteMoveFPUSToOtherUnits, + P5600WriteGPRFromBypass]>; + +// FIXME: This isn't quite right since the implementation of WriteSequence +// current aggregates the resources and ignores the exact cycle they are +// used. +def P5600WriteStoreFPUS : WriteSequence<[P5600WriteMoveFPUSToOtherUnits, + P5600WriteStoreFromOtherUnits]>; + +// FIXME: This isn't quite right since the implementation of WriteSequence +// current aggregates the resources and ignores the exact cycle they are +// used. +def P5600WriteStoreFPUL : WriteSequence<[P5600WriteMoveFPULToOtherUnits, + P5600WriteStoreFromOtherUnits]>; + +// FIXME: This isn't quite right since the implementation of WriteSequence +// current aggregates the resources and ignores the exact cycle they are +// used. +def P5600WriteLoadFPU : WriteSequence<[P5600WriteLoadToOtherUnits, + P5600WriteLoadOtherUnitsToFPU]>; + +// ctc1, mtc1, mthc1 +def : ItinRW<[P5600WriteMoveGPRToFPU], [II_CTC1, II_MTC1, II_MTHC1]>; + +// bc1[ft], cfc1, mfc1, mfhc1, movf, movt +def : ItinRW<[P5600WriteMoveFPUToGPR], + [II_BC1F, II_BC1T, II_CFC1, II_MFC1, II_MFHC1, II_MOVF, II_MOVT]>; + +// swc1, swxc1, st.[bhwd] +def : ItinRW<[P5600WriteStoreFPUS], [II_SWC1, II_SWXC1]>; +def : InstRW<[P5600WriteStoreFPUS], (instregex "^ST_[BHWD]$")>; + +// movn.[ds], movz.[ds] +def : ItinRW<[P5600WriteStoreFPUL], [II_MOVN_D, II_MOVN_S, II_MOVZ_D, II_MOVZ_S]>; + +// l[dw]x?c1, ld.[bhwd] +def : ItinRW<[P5600WriteLoadFPU], [II_LDC1, II_LDXC1, II_LWC1, II_LWXC1]>; +def : InstRW<[P5600WriteLoadFPU], (instregex "LD_[BHWD]")>; + +// Unsupported Instructions +// ======================== +// +// The following instruction classes are never valid on P5600. +// II_DADDIU, II_DADDU, II_DMFC1, II_DMTC1, II_DMULT, II_DMULTU, II_DROTR, +// II_DROTR32, II_DROTRV, II_DDIV, II_DSLL, II_DSLL32, II_DSLLV, II_DSRA, +// II_DSRA32, II_DSRAV, II_DSRL, II_DSRL32, II_DSRLV, II_DSUBU, II_DDIVU, +// II_JALRC, II_LD, II_LD[LR], II_LUXC1, II_RESTORE, II_SAVE, II_SD, II_SDC1, +// II_SDL, II_SDR, II_SDXC1 +// +// The following instructions are never valid on P5600. +// addq.ph, rdhwr, repl.ph, repl.qb, subq.ph, subu_s.qb +// +// Guesswork +// ========= +// +// This section is largely temporary guesswork. + +// ceil.[lw].[ds], floor.[lw].[ds] +// Reason behind guess: trunc.[lw].ds and the various cvt's are in FPUL +def : ItinRW<[P5600WriteFPUL], [II_CEIL, II_FLOOR, II_ROUND]>; + +// rotrv +// Reason behind guess: rotr is in the same category and the two register forms +// generally follow the immediate forms in this category +def : ItinRW<[P5600WriteEitherALU], [II_ROTRV]>; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsSubtarget.cpp b/contrib/llvm/lib/Target/Mips/MipsSubtarget.cpp new file mode 100644 index 0000000..8a18b51 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSubtarget.cpp @@ -0,0 +1,171 @@ +//===-- MipsSubtarget.cpp - Mips Subtarget Information --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Mips specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#include "MipsMachineFunction.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" +#include "llvm/Support/Debug.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#define DEBUG_TYPE "mips-subtarget" + +#define GET_SUBTARGETINFO_TARGET_DESC +#define GET_SUBTARGETINFO_CTOR +#include "MipsGenSubtargetInfo.inc" + +// FIXME: Maybe this should be on by default when Mips16 is specified +// +static cl::opt<bool> + Mixed16_32("mips-mixed-16-32", cl::init(false), + cl::desc("Allow for a mixture of Mips16 " + "and Mips32 code in a single output file"), + cl::Hidden); + +static cl::opt<bool> Mips_Os16("mips-os16", cl::init(false), + cl::desc("Compile all functions that don't use " + "floating point as Mips 16"), + cl::Hidden); + +static cl::opt<bool> Mips16HardFloat("mips16-hard-float", cl::NotHidden, + cl::desc("Enable mips16 hard float."), + cl::init(false)); + +static cl::opt<bool> + Mips16ConstantIslands("mips16-constant-islands", cl::NotHidden, + cl::desc("Enable mips16 constant islands."), + cl::init(true)); + +static cl::opt<bool> + GPOpt("mgpopt", cl::Hidden, + cl::desc("Enable gp-relative addressing of mips small data items")); + +void MipsSubtarget::anchor() { } + +MipsSubtarget::MipsSubtarget(const Triple &TT, const std::string &CPU, + const std::string &FS, bool little, + const MipsTargetMachine &TM) + : MipsGenSubtargetInfo(TT, CPU, FS), MipsArchVersion(MipsDefault), + IsLittle(little), IsSoftFloat(false), IsSingleFloat(false), IsFPXX(false), + NoABICalls(false), IsFP64bit(false), UseOddSPReg(true), + IsNaN2008bit(false), IsGP64bit(false), HasVFPU(false), HasCnMips(false), + HasMips3_32(false), HasMips3_32r2(false), HasMips4_32(false), + HasMips4_32r2(false), HasMips5_32r2(false), InMips16Mode(false), + InMips16HardFloat(Mips16HardFloat), InMicroMipsMode(false), HasDSP(false), + HasDSPR2(false), HasDSPR3(false), AllowMixed16_32(Mixed16_32 | Mips_Os16), + Os16(Mips_Os16), HasMSA(false), UseTCCInDIV(false), HasEVA(false), TM(TM), + TargetTriple(TT), TSInfo(), + InstrInfo( + MipsInstrInfo::create(initializeSubtargetDependencies(CPU, FS, TM))), + FrameLowering(MipsFrameLowering::create(*this)), + TLInfo(MipsTargetLowering::create(TM, *this)) { + + PreviousInMips16Mode = InMips16Mode; + + if (MipsArchVersion == MipsDefault) + MipsArchVersion = Mips32; + + // Don't even attempt to generate code for MIPS-I and MIPS-V. They have not + // been tested and currently exist for the integrated assembler only. + if (MipsArchVersion == Mips1) + report_fatal_error("Code generation for MIPS-I is not implemented", false); + if (MipsArchVersion == Mips5) + report_fatal_error("Code generation for MIPS-V is not implemented", false); + + // Check if Architecture and ABI are compatible. + assert(((!isGP64bit() && (isABI_O32() || isABI_EABI())) || + (isGP64bit() && (isABI_N32() || isABI_N64()))) && + "Invalid Arch & ABI pair."); + + if (hasMSA() && !isFP64bit()) + report_fatal_error("MSA requires a 64-bit FPU register file (FR=1 mode). " + "See -mattr=+fp64.", + false); + + if (!isABI_O32() && !useOddSPReg()) + report_fatal_error("-mattr=+nooddspreg requires the O32 ABI.", false); + + if (IsFPXX && (isABI_N32() || isABI_N64())) + report_fatal_error("FPXX is not permitted for the N32/N64 ABI's.", false); + + if (hasMips32r6()) { + StringRef ISA = hasMips64r6() ? "MIPS64r6" : "MIPS32r6"; + + assert(isFP64bit()); + assert(isNaN2008()); + if (hasDSP()) + report_fatal_error(ISA + " is not compatible with the DSP ASE", false); + } + + if (NoABICalls && TM.getRelocationModel() == Reloc::PIC_) + report_fatal_error("position-independent code requires '-mabicalls'"); + + // Set UseSmallSection. + UseSmallSection = GPOpt; + if (!NoABICalls && GPOpt) { + errs() << "warning: cannot use small-data accesses for '-mabicalls'" + << "\n"; + UseSmallSection = false; + } +} + +/// This overrides the PostRAScheduler bit in the SchedModel for any CPU. +bool MipsSubtarget::enablePostRAScheduler() const { return true; } + +void MipsSubtarget::getCriticalPathRCs(RegClassVector &CriticalPathRCs) const { + CriticalPathRCs.clear(); + CriticalPathRCs.push_back(isGP64bit() ? + &Mips::GPR64RegClass : &Mips::GPR32RegClass); +} + +CodeGenOpt::Level MipsSubtarget::getOptLevelToEnablePostRAScheduler() const { + return CodeGenOpt::Aggressive; +} + +MipsSubtarget & +MipsSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS, + const TargetMachine &TM) { + std::string CPUName = MIPS_MC::selectMipsCPU(TM.getTargetTriple(), CPU); + + // Parse features string. + ParseSubtargetFeatures(CPUName, FS); + // Initialize scheduling itinerary for the specified CPU. + InstrItins = getInstrItineraryForCPU(CPUName); + + if (InMips16Mode && !IsSoftFloat) + InMips16HardFloat = true; + + return *this; +} + +bool MipsSubtarget::useConstantIslands() { + DEBUG(dbgs() << "use constant islands " << Mips16ConstantIslands << "\n"); + return Mips16ConstantIslands; +} + +Reloc::Model MipsSubtarget::getRelocationModel() const { + return TM.getRelocationModel(); +} + +bool MipsSubtarget::isABI_EABI() const { return getABI().IsEABI(); } +bool MipsSubtarget::isABI_N64() const { return getABI().IsN64(); } +bool MipsSubtarget::isABI_N32() const { return getABI().IsN32(); } +bool MipsSubtarget::isABI_O32() const { return getABI().IsO32(); } +const MipsABIInfo &MipsSubtarget::getABI() const { return TM.getABI(); } diff --git a/contrib/llvm/lib/Target/Mips/MipsSubtarget.h b/contrib/llvm/lib/Target/Mips/MipsSubtarget.h new file mode 100644 index 0000000..fbb01fe --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSubtarget.h @@ -0,0 +1,312 @@ +//===-- MipsSubtarget.h - Define Subtarget for the Mips ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the Mips specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSSUBTARGET_H +#define LLVM_LIB_TARGET_MIPS_MIPSSUBTARGET_H + +#include "MCTargetDesc/MipsABIInfo.h" +#include "MipsFrameLowering.h" +#include "MipsISelLowering.h" +#include "MipsInstrInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/MC/MCInstrItineraries.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetSelectionDAGInfo.h" +#include "llvm/Target/TargetSubtargetInfo.h" +#include <string> + +#define GET_SUBTARGETINFO_HEADER +#include "MipsGenSubtargetInfo.inc" + +namespace llvm { +class StringRef; + +class MipsTargetMachine; + +class MipsSubtarget : public MipsGenSubtargetInfo { + virtual void anchor(); + + enum MipsArchEnum { + MipsDefault, + Mips1, Mips2, Mips32, Mips32r2, Mips32r3, Mips32r5, Mips32r6, Mips32Max, + Mips3, Mips4, Mips5, Mips64, Mips64r2, Mips64r3, Mips64r5, Mips64r6 + }; + + enum class CPU { P5600 }; + + // Mips architecture version + MipsArchEnum MipsArchVersion; + + // Processor implementation (unused but required to exist by + // tablegen-erated code). + CPU ProcImpl; + + // IsLittle - The target is Little Endian + bool IsLittle; + + // IsSoftFloat - The target does not support any floating point instructions. + bool IsSoftFloat; + + // IsSingleFloat - The target only supports single precision float + // point operations. This enable the target to use all 32 32-bit + // floating point registers instead of only using even ones. + bool IsSingleFloat; + + // IsFPXX - MIPS O32 modeless ABI. + bool IsFPXX; + + // NoABICalls - Disable SVR4-style position-independent code. + bool NoABICalls; + + // IsFP64bit - The target processor has 64-bit floating point registers. + bool IsFP64bit; + + /// Are odd single-precision registers permitted? + /// This corresponds to -modd-spreg and -mno-odd-spreg + bool UseOddSPReg; + + // IsNan2008 - IEEE 754-2008 NaN encoding. + bool IsNaN2008bit; + + // IsFP64bit - General-purpose registers are 64 bits wide + bool IsGP64bit; + + // HasVFPU - Processor has a vector floating point unit. + bool HasVFPU; + + // CPU supports cnMIPS (Cavium Networks Octeon CPU). + bool HasCnMips; + + // isLinux - Target system is Linux. Is false we consider ELFOS for now. + bool IsLinux; + + // UseSmallSection - Small section is used. + bool UseSmallSection; + + /// Features related to the presence of specific instructions. + + // HasMips3_32 - The subset of MIPS-III instructions added to MIPS32 + bool HasMips3_32; + + // HasMips3_32r2 - The subset of MIPS-III instructions added to MIPS32r2 + bool HasMips3_32r2; + + // HasMips4_32 - Has the subset of MIPS-IV present in MIPS32 + bool HasMips4_32; + + // HasMips4_32r2 - Has the subset of MIPS-IV present in MIPS32r2 + bool HasMips4_32r2; + + // HasMips5_32r2 - Has the subset of MIPS-V present in MIPS32r2 + bool HasMips5_32r2; + + // InMips16 -- can process Mips16 instructions + bool InMips16Mode; + + // Mips16 hard float + bool InMips16HardFloat; + + // PreviousInMips16 -- the function we just processed was in Mips 16 Mode + bool PreviousInMips16Mode; + + // InMicroMips -- can process MicroMips instructions + bool InMicroMipsMode; + + // HasDSP, HasDSPR2, HasDSPR3 -- supports DSP ASE. + bool HasDSP, HasDSPR2, HasDSPR3; + + // Allow mixed Mips16 and Mips32 in one source file + bool AllowMixed16_32; + + // Optimize for space by compiling all functions as Mips 16 unless + // it needs floating point. Functions needing floating point are + // compiled as Mips32 + bool Os16; + + // HasMSA -- supports MSA ASE. + bool HasMSA; + + // UseTCCInDIV -- Enables the use of trapping in the assembler. + bool UseTCCInDIV; + + // HasEVA -- supports EVA ASE. + bool HasEVA; + + InstrItineraryData InstrItins; + + // We can override the determination of whether we are in mips16 mode + // as from the command line + enum {NoOverride, Mips16Override, NoMips16Override} OverrideMode; + + const MipsTargetMachine &TM; + + Triple TargetTriple; + + const TargetSelectionDAGInfo TSInfo; + std::unique_ptr<const MipsInstrInfo> InstrInfo; + std::unique_ptr<const MipsFrameLowering> FrameLowering; + std::unique_ptr<const MipsTargetLowering> TLInfo; + +public: + /// This overrides the PostRAScheduler bit in the SchedModel for each CPU. + bool enablePostRAScheduler() const override; + void getCriticalPathRCs(RegClassVector &CriticalPathRCs) const override; + CodeGenOpt::Level getOptLevelToEnablePostRAScheduler() const override; + + /// Only O32 and EABI supported right now. + bool isABI_EABI() const; + bool isABI_N64() const; + bool isABI_N32() const; + bool isABI_O32() const; + const MipsABIInfo &getABI() const; + bool isABI_FPXX() const { return isABI_O32() && IsFPXX; } + + /// This constructor initializes the data members to match that + /// of the specified triple. + MipsSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS, + bool little, const MipsTargetMachine &TM); + + /// ParseSubtargetFeatures - Parses features string setting specified + /// subtarget options. Definition of function is auto generated by tblgen. + void ParseSubtargetFeatures(StringRef CPU, StringRef FS); + + bool hasMips1() const { return MipsArchVersion >= Mips1; } + bool hasMips2() const { return MipsArchVersion >= Mips2; } + bool hasMips3() const { return MipsArchVersion >= Mips3; } + bool hasMips4() const { return MipsArchVersion >= Mips4; } + bool hasMips5() const { return MipsArchVersion >= Mips5; } + bool hasMips4_32() const { return HasMips4_32; } + bool hasMips4_32r2() const { return HasMips4_32r2; } + bool hasMips32() const { + return (MipsArchVersion >= Mips32 && MipsArchVersion < Mips32Max) || + hasMips64(); + } + bool hasMips32r2() const { + return (MipsArchVersion >= Mips32r2 && MipsArchVersion < Mips32Max) || + hasMips64r2(); + } + bool hasMips32r3() const { + return (MipsArchVersion >= Mips32r3 && MipsArchVersion < Mips32Max) || + hasMips64r2(); + } + bool hasMips32r5() const { + return (MipsArchVersion >= Mips32r5 && MipsArchVersion < Mips32Max) || + hasMips64r5(); + } + bool hasMips32r6() const { + return (MipsArchVersion >= Mips32r6 && MipsArchVersion < Mips32Max) || + hasMips64r6(); + } + bool hasMips64() const { return MipsArchVersion >= Mips64; } + bool hasMips64r2() const { return MipsArchVersion >= Mips64r2; } + bool hasMips64r3() const { return MipsArchVersion >= Mips64r3; } + bool hasMips64r5() const { return MipsArchVersion >= Mips64r5; } + bool hasMips64r6() const { return MipsArchVersion >= Mips64r6; } + + bool hasCnMips() const { return HasCnMips; } + + bool isLittle() const { return IsLittle; } + bool isABICalls() const { return !NoABICalls; } + bool isFPXX() const { return IsFPXX; } + bool isFP64bit() const { return IsFP64bit; } + bool useOddSPReg() const { return UseOddSPReg; } + bool noOddSPReg() const { return !UseOddSPReg; } + bool isNaN2008() const { return IsNaN2008bit; } + bool isGP64bit() const { return IsGP64bit; } + bool isGP32bit() const { return !IsGP64bit; } + unsigned getGPRSizeInBytes() const { return isGP64bit() ? 8 : 4; } + bool isSingleFloat() const { return IsSingleFloat; } + bool hasVFPU() const { return HasVFPU; } + bool inMips16Mode() const { return InMips16Mode; } + bool inMips16ModeDefault() const { + return InMips16Mode; + } + // Hard float for mips16 means essentially to compile as soft float + // but to use a runtime library for soft float that is written with + // native mips32 floating point instructions (those runtime routines + // run in mips32 hard float mode). + bool inMips16HardFloat() const { + return inMips16Mode() && InMips16HardFloat; + } + bool inMicroMipsMode() const { return InMicroMipsMode; } + bool inMicroMips32r6Mode() const { return InMicroMipsMode && hasMips32r6(); } + bool inMicroMips64r6Mode() const { return InMicroMipsMode && hasMips64r6(); } + bool hasDSP() const { return HasDSP; } + bool hasDSPR2() const { return HasDSPR2; } + bool hasDSPR3() const { return HasDSPR3; } + bool hasMSA() const { return HasMSA; } + bool hasEVA() const { return HasEVA; } + bool useSmallSection() const { return UseSmallSection; } + + bool hasStandardEncoding() const { return !inMips16Mode(); } + + bool useSoftFloat() const { return IsSoftFloat; } + + bool enableLongBranchPass() const { + return hasStandardEncoding() || allowMixed16_32(); + } + + /// Features related to the presence of specific instructions. + bool hasExtractInsert() const { return !inMips16Mode() && hasMips32r2(); } + bool hasMTHC1() const { return hasMips32r2(); } + + bool allowMixed16_32() const { return inMips16ModeDefault() | + AllowMixed16_32; } + + bool os16() const { return Os16; } + + bool isTargetNaCl() 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 + static bool useConstantIslands(); + + unsigned stackAlignment() const { return hasMips64() ? 16 : 8; } + + // Grab relocation model + Reloc::Model getRelocationModel() const; + + MipsSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS, + const TargetMachine &TM); + + /// Does the system support unaligned memory access. + /// + /// MIPS32r6/MIPS64r6 require full unaligned access support but does not + /// specify which component of the system provides it. Hardware, software, and + /// hybrid implementations are all valid. + bool systemSupportsUnalignedAccess() const { return hasMips32r6(); } + + // Set helper classes + void setHelperClassesMips16(); + void setHelperClassesMipsSE(); + + const TargetSelectionDAGInfo *getSelectionDAGInfo() const override { + return &TSInfo; + } + const MipsInstrInfo *getInstrInfo() const override { return InstrInfo.get(); } + const TargetFrameLowering *getFrameLowering() const override { + return FrameLowering.get(); + } + const MipsRegisterInfo *getRegisterInfo() const override { + return &InstrInfo->getRegisterInfo(); + } + const MipsTargetLowering *getTargetLowering() const override { + return TLInfo.get(); + } + const InstrItineraryData *getInstrItineraryData() const override { + return &InstrItins; + } +}; +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsTargetMachine.cpp b/contrib/llvm/lib/Target/Mips/MipsTargetMachine.cpp new file mode 100644 index 0000000..3e63872 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsTargetMachine.cpp @@ -0,0 +1,256 @@ +//===-- MipsTargetMachine.cpp - Define TargetMachine for Mips -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implements the info about Mips target spec. +// +//===----------------------------------------------------------------------===// + +#include "MipsTargetMachine.h" +#include "Mips.h" +#include "Mips16FrameLowering.h" +#include "Mips16ISelDAGToDAG.h" +#include "Mips16ISelLowering.h" +#include "Mips16InstrInfo.h" +#include "MipsFrameLowering.h" +#include "MipsInstrInfo.h" +#include "MipsSEFrameLowering.h" +#include "MipsSEISelDAGToDAG.h" +#include "MipsSEISelLowering.h" +#include "MipsSEInstrInfo.h" +#include "MipsTargetObjectFile.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Scalar.h" + +using namespace llvm; + +#define DEBUG_TYPE "mips" + +extern "C" void LLVMInitializeMipsTarget() { + // Register the target. + RegisterTargetMachine<MipsebTargetMachine> X(TheMipsTarget); + RegisterTargetMachine<MipselTargetMachine> Y(TheMipselTarget); + RegisterTargetMachine<MipsebTargetMachine> A(TheMips64Target); + RegisterTargetMachine<MipselTargetMachine> B(TheMips64elTarget); +} + +static std::string computeDataLayout(const Triple &TT, StringRef CPU, + const TargetOptions &Options, + bool isLittle) { + std::string Ret = ""; + MipsABIInfo ABI = MipsABIInfo::computeTargetABI(TT, CPU, Options.MCOptions); + + // There are both little and big endian mips. + if (isLittle) + Ret += "e"; + else + Ret += "E"; + + Ret += "-m:m"; + + // Pointers are 32 bit on some ABIs. + if (!ABI.IsN64()) + Ret += "-p:32:32"; + + // 8 and 16 bit integers only need to 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 (ABI.IsN64() || ABI.IsN32()) + 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 +// an easier handling. +// Using CodeModel::Large enables different CALL behavior. +MipsTargetMachine::MipsTargetMachine(const Target &T, const Triple &TT, + StringRef CPU, StringRef FS, + const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL, bool isLittle) + : LLVMTargetMachine(T, computeDataLayout(TT, CPU, Options, isLittle), TT, + CPU, FS, Options, RM, CM, OL), + isLittle(isLittle), TLOF(make_unique<MipsTargetObjectFile>()), + ABI(MipsABIInfo::computeTargetABI(TT, CPU, Options.MCOptions)), + Subtarget(nullptr), DefaultSubtarget(TT, CPU, FS, isLittle, *this), + NoMips16Subtarget(TT, CPU, FS.empty() ? "-mips16" : FS.str() + ",-mips16", + isLittle, *this), + Mips16Subtarget(TT, CPU, FS.empty() ? "+mips16" : FS.str() + ",+mips16", + isLittle, *this) { + Subtarget = &DefaultSubtarget; + initAsmInfo(); +} + +MipsTargetMachine::~MipsTargetMachine() {} + +void MipsebTargetMachine::anchor() { } + +MipsebTargetMachine::MipsebTargetMachine(const Target &T, const Triple &TT, + StringRef CPU, StringRef FS, + const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL) + : MipsTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {} + +void MipselTargetMachine::anchor() { } + +MipselTargetMachine::MipselTargetMachine(const Target &T, const Triple &TT, + StringRef CPU, StringRef FS, + const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL) + : MipsTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, true) {} + +const MipsSubtarget * +MipsTargetMachine::getSubtargetImpl(const Function &F) const { + Attribute CPUAttr = F.getFnAttribute("target-cpu"); + Attribute FSAttr = F.getFnAttribute("target-features"); + + std::string CPU = !CPUAttr.hasAttribute(Attribute::None) + ? CPUAttr.getValueAsString().str() + : TargetCPU; + std::string FS = !FSAttr.hasAttribute(Attribute::None) + ? FSAttr.getValueAsString().str() + : TargetFS; + bool hasMips16Attr = + !F.getFnAttribute("mips16").hasAttribute(Attribute::None); + bool hasNoMips16Attr = + !F.getFnAttribute("nomips16").hasAttribute(Attribute::None); + + // FIXME: This is related to the code below to reset the target options, + // we need to know whether or not the soft float flag is set on the + // function, so we can enable it as a subtarget feature. + bool softFloat = + F.hasFnAttribute("use-soft-float") && + F.getFnAttribute("use-soft-float").getValueAsString() == "true"; + + if (hasMips16Attr) + FS += FS.empty() ? "+mips16" : ",+mips16"; + else if (hasNoMips16Attr) + FS += FS.empty() ? "-mips16" : ",-mips16"; + if (softFloat) + FS += FS.empty() ? "+soft-float" : ",+soft-float"; + + auto &I = SubtargetMap[CPU + FS]; + if (!I) { + // This needs to be done before we create a new subtarget since any + // creation will depend on the TM and the code generation flags on the + // function that reside in TargetOptions. + resetTargetOptions(F); + I = llvm::make_unique<MipsSubtarget>(TargetTriple, CPU, FS, isLittle, + *this); + } + return I.get(); +} + +void MipsTargetMachine::resetSubtarget(MachineFunction *MF) { + DEBUG(dbgs() << "resetSubtarget\n"); + + Subtarget = const_cast<MipsSubtarget *>(getSubtargetImpl(*MF->getFunction())); + MF->setSubtarget(Subtarget); + return; +} + +namespace { +/// Mips Code Generator Pass Configuration Options. +class MipsPassConfig : public TargetPassConfig { +public: + MipsPassConfig(MipsTargetMachine *TM, PassManagerBase &PM) + : TargetPassConfig(TM, PM) { + // The current implementation of long branch pass requires a scratch + // register ($at) to be available before branch instructions. Tail merging + // can break this requirement, so disable it when long branch pass is + // enabled. + EnableTailMerge = !getMipsSubtarget().enableLongBranchPass(); + } + + MipsTargetMachine &getMipsTargetMachine() const { + return getTM<MipsTargetMachine>(); + } + + const MipsSubtarget &getMipsSubtarget() const { + return *getMipsTargetMachine().getSubtargetImpl(); + } + + void addIRPasses() override; + bool addInstSelector() override; + void addMachineSSAOptimization() override; + void addPreEmitPass() override; + + void addPreRegAlloc() override; + +}; +} // namespace + +TargetPassConfig *MipsTargetMachine::createPassConfig(PassManagerBase &PM) { + return new MipsPassConfig(this, PM); +} + +void MipsPassConfig::addIRPasses() { + TargetPassConfig::addIRPasses(); + addPass(createAtomicExpandPass(&getMipsTargetMachine())); + if (getMipsSubtarget().os16()) + addPass(createMipsOs16Pass(getMipsTargetMachine())); + if (getMipsSubtarget().inMips16HardFloat()) + addPass(createMips16HardFloatPass(getMipsTargetMachine())); +} +// Install an instruction selector pass using +// the ISelDag to gen Mips code. +bool MipsPassConfig::addInstSelector() { + addPass(createMipsModuleISelDagPass(getMipsTargetMachine())); + addPass(createMips16ISelDag(getMipsTargetMachine())); + addPass(createMipsSEISelDag(getMipsTargetMachine())); + return false; +} + +void MipsPassConfig::addMachineSSAOptimization() { + addPass(createMipsOptimizePICCallPass(getMipsTargetMachine())); + TargetPassConfig::addMachineSSAOptimization(); +} + +void MipsPassConfig::addPreRegAlloc() { + if (getOptLevel() == CodeGenOpt::None) + addPass(createMipsOptimizePICCallPass(getMipsTargetMachine())); +} + +TargetIRAnalysis MipsTargetMachine::getTargetIRAnalysis() { + return TargetIRAnalysis([this](const Function &F) { + if (Subtarget->allowMixed16_32()) { + DEBUG(errs() << "No Target Transform Info Pass Added\n"); + // FIXME: This is no longer necessary as the TTI returned is per-function. + return TargetTransformInfo(F.getParent()->getDataLayout()); + } + + DEBUG(errs() << "Target Transform Info Pass Added\n"); + return TargetTransformInfo(BasicTTIImpl(this, F)); + }); +} + +// Implemented by targets that want to run passes immediately before +// machine code is emitted. return true if -print-machineinstrs should +// print out the code after the passes. +void MipsPassConfig::addPreEmitPass() { + MipsTargetMachine &TM = getMipsTargetMachine(); + addPass(createMipsDelaySlotFillerPass(TM)); + addPass(createMipsLongBranchPass(TM)); + addPass(createMipsConstantIslandPass(TM)); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsTargetMachine.h b/contrib/llvm/lib/Target/Mips/MipsTargetMachine.h new file mode 100644 index 0000000..38b2ecf --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsTargetMachine.h @@ -0,0 +1,95 @@ +//===-- MipsTargetMachine.h - Define TargetMachine for Mips -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the Mips specific subclass of TargetMachine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSTARGETMACHINE_H +#define LLVM_LIB_TARGET_MIPS_MIPSTARGETMACHINE_H + +#include "MCTargetDesc/MipsABIInfo.h" +#include "MipsSubtarget.h" +#include "llvm/CodeGen/BasicTTIImpl.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { +class formatted_raw_ostream; +class MipsRegisterInfo; + +class MipsTargetMachine : public LLVMTargetMachine { + bool isLittle; + std::unique_ptr<TargetLoweringObjectFile> TLOF; + // Selected ABI + MipsABIInfo ABI; + MipsSubtarget *Subtarget; + MipsSubtarget DefaultSubtarget; + MipsSubtarget NoMips16Subtarget; + MipsSubtarget Mips16Subtarget; + + mutable StringMap<std::unique_ptr<MipsSubtarget>> SubtargetMap; + +public: + MipsTargetMachine(const Target &T, const Triple &TT, StringRef CPU, + StringRef FS, const TargetOptions &Options, Reloc::Model RM, + CodeModel::Model CM, CodeGenOpt::Level OL, bool isLittle); + ~MipsTargetMachine() override; + + TargetIRAnalysis getTargetIRAnalysis() override; + + const MipsSubtarget *getSubtargetImpl() const { + if (Subtarget) + return Subtarget; + return &DefaultSubtarget; + } + + const MipsSubtarget *getSubtargetImpl(const Function &F) const override; + + /// \brief Reset the subtarget for the Mips target. + void resetSubtarget(MachineFunction *MF); + + // Pass Pipeline Configuration + TargetPassConfig *createPassConfig(PassManagerBase &PM) override; + + TargetLoweringObjectFile *getObjFileLowering() const override { + return TLOF.get(); + } + + bool isLittleEndian() const { return isLittle; } + const MipsABIInfo &getABI() const { return ABI; } +}; + +/// MipsebTargetMachine - Mips32/64 big endian target machine. +/// +class MipsebTargetMachine : public MipsTargetMachine { + virtual void anchor(); +public: + MipsebTargetMachine(const Target &T, const Triple &TT, StringRef CPU, + StringRef FS, const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL); +}; + +/// MipselTargetMachine - Mips32/64 little endian target machine. +/// +class MipselTargetMachine : public MipsTargetMachine { + virtual void anchor(); +public: + MipselTargetMachine(const Target &T, const Triple &TT, StringRef CPU, + StringRef FS, const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL); +}; + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp b/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp new file mode 100644 index 0000000..146f33b --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp @@ -0,0 +1,148 @@ +//===-- MipsTargetObjectFile.cpp - Mips Object Files ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsTargetObjectFile.h" +#include "MipsSubtarget.h" +#include "MipsTargetMachine.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ELF.h" +#include "llvm/Target/TargetMachine.h" +using namespace llvm; + +static cl::opt<unsigned> +SSThreshold("mips-ssection-threshold", cl::Hidden, + cl::desc("Small data and bss section threshold size (default=8)"), + cl::init(8)); + +static cl::opt<bool> +LocalSData("mlocal-sdata", cl::Hidden, + cl::desc("MIPS: Use gp_rel for object-local data."), + cl::init(true)); + +static cl::opt<bool> +ExternSData("mextern-sdata", cl::Hidden, + cl::desc("MIPS: Use gp_rel for data that is not defined by the " + "current object."), + cl::init(true)); + +void MipsTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM){ + TargetLoweringObjectFileELF::Initialize(Ctx, TM); + InitializeELF(TM.Options.UseInitArray); + + SmallDataSection = getContext().getELFSection( + ".sdata", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); + + SmallBSSSection = getContext().getELFSection(".sbss", ELF::SHT_NOBITS, + ELF::SHF_WRITE | ELF::SHF_ALLOC); + this->TM = &static_cast<const MipsTargetMachine &>(TM); +} + +// A address must be loaded from a small section if its size is less than the +// small section size threshold. Data in this section must be addressed using +// gp_rel operator. +static bool IsInSmallSection(uint64_t Size) { + // gcc has traditionally not treated zero-sized objects as small data, so this + // is effectively part of the ABI. + return Size > 0 && Size <= SSThreshold; +} + +/// Return true if this global address should be placed into small data/bss +/// section. +bool MipsTargetObjectFile:: +IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM) const { + // We first check the case where global is a declaration, because finding + // section kind using getKindForGlobal() is only allowed for global + // definitions. + if (GV->isDeclaration() || GV->hasAvailableExternallyLinkage()) + return IsGlobalInSmallSectionImpl(GV, TM); + + return IsGlobalInSmallSection(GV, TM, getKindForGlobal(GV, TM)); +} + +/// Return true if this global address should be placed into small data/bss +/// section. +bool MipsTargetObjectFile:: +IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM, + SectionKind Kind) const { + return (IsGlobalInSmallSectionImpl(GV, TM) && + (Kind.isData() || Kind.isBSS() || Kind.isCommon())); +} + +/// Return true if this global address should be placed into small data/bss +/// section. This method does all the work, except for checking the section +/// kind. +bool MipsTargetObjectFile:: +IsGlobalInSmallSectionImpl(const GlobalValue *GV, + const TargetMachine &TM) const { + const MipsSubtarget &Subtarget = + *static_cast<const MipsTargetMachine &>(TM).getSubtargetImpl(); + + // Return if small section is not available. + if (!Subtarget.useSmallSection()) + return false; + + // Only global variables, not functions. + const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GV); + if (!GVA) + return false; + + // Enforce -mlocal-sdata. + if (!LocalSData && GV->hasLocalLinkage()) + return false; + + // Enforce -mextern-sdata. + if (!ExternSData && ((GV->hasExternalLinkage() && GV->isDeclaration()) || + GV->hasCommonLinkage())) + return false; + + Type *Ty = GV->getType()->getElementType(); + return IsInSmallSection( + GV->getParent()->getDataLayout().getTypeAllocSize(Ty)); +} + +MCSection * +MipsTargetObjectFile::SelectSectionForGlobal(const GlobalValue *GV, + SectionKind Kind, Mangler &Mang, + const TargetMachine &TM) const { + // TODO: Could also support "weak" symbols as well with ".gnu.linkonce.s.*" + // sections? + + // Handle Small Section classification here. + if (Kind.isBSS() && IsGlobalInSmallSection(GV, TM, Kind)) + return SmallBSSSection; + if (Kind.isData() && IsGlobalInSmallSection(GV, TM, Kind)) + return SmallDataSection; + + // Otherwise, we work the same as ELF. + return TargetLoweringObjectFileELF::SelectSectionForGlobal(GV, Kind, Mang,TM); +} + +/// Return true if this constant should be placed into small data section. +bool MipsTargetObjectFile::IsConstantInSmallSection( + const DataLayout &DL, const Constant *CN, const TargetMachine &TM) const { + return (static_cast<const MipsTargetMachine &>(TM) + .getSubtargetImpl() + ->useSmallSection() && + LocalSData && IsInSmallSection(DL.getTypeAllocSize(CN->getType()))); +} + +/// Return true if this constant should be placed into small data section. +MCSection *MipsTargetObjectFile::getSectionForConstant( + const DataLayout &DL, SectionKind Kind, const Constant *C) const { + if (IsConstantInSmallSection(DL, C, *TM)) + return SmallDataSection; + + // Otherwise, we work the same as ELF. + return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.h b/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.h new file mode 100644 index 0000000..ba04343 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.h @@ -0,0 +1,47 @@ +//===-- llvm/Target/MipsTargetObjectFile.h - Mips Object Info ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSTARGETOBJECTFILE_H +#define LLVM_LIB_TARGET_MIPS_MIPSTARGETOBJECTFILE_H + +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" + +namespace llvm { +class MipsTargetMachine; + class MipsTargetObjectFile : public TargetLoweringObjectFileELF { + MCSection *SmallDataSection; + MCSection *SmallBSSSection; + const MipsTargetMachine *TM; + public: + + void Initialize(MCContext &Ctx, const TargetMachine &TM) override; + + /// Return true if this global address should be placed into small data/bss + /// section. + bool IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM, + SectionKind Kind) const; + bool IsGlobalInSmallSection(const GlobalValue *GV, + const TargetMachine &TM) const; + bool IsGlobalInSmallSectionImpl(const GlobalValue *GV, + const TargetMachine &TM) const; + + MCSection *SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, + Mangler &Mang, + const TargetMachine &TM) const override; + + /// Return true if this constant should be placed into small data section. + bool IsConstantInSmallSection(const DataLayout &DL, const Constant *CN, + const TargetMachine &TM) const; + + MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, + const Constant *C) const override; + }; +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsTargetStreamer.h b/contrib/llvm/lib/Target/Mips/MipsTargetStreamer.h new file mode 100644 index 0000000..b3222f5 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsTargetStreamer.h @@ -0,0 +1,259 @@ +//===-- MipsTargetStreamer.h - Mips Target Streamer ------------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSTARGETSTREAMER_H +#define LLVM_LIB_TARGET_MIPS_MIPSTARGETSTREAMER_H + +#include "MCTargetDesc/MipsABIFlagsSection.h" +#include "MCTargetDesc/MipsABIInfo.h" +#include "llvm/ADT/Optional.h" +#include "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" + +namespace llvm { + +struct MipsABIFlagsSection; + +class MipsTargetStreamer : public MCTargetStreamer { +public: + MipsTargetStreamer(MCStreamer &S); + virtual void emitDirectiveSetMicroMips(); + virtual void emitDirectiveSetNoMicroMips(); + virtual void emitDirectiveSetMips16(); + virtual void emitDirectiveSetNoMips16(); + + virtual void emitDirectiveSetReorder(); + virtual void emitDirectiveSetNoReorder(); + virtual void emitDirectiveSetMacro(); + virtual void emitDirectiveSetNoMacro(); + virtual void emitDirectiveSetMsa(); + virtual void emitDirectiveSetNoMsa(); + virtual void emitDirectiveSetAt(); + virtual void emitDirectiveSetAtWithArg(unsigned RegNo); + virtual void emitDirectiveSetNoAt(); + virtual void emitDirectiveEnd(StringRef Name); + + virtual void emitDirectiveEnt(const MCSymbol &Symbol); + virtual void emitDirectiveAbiCalls(); + virtual void emitDirectiveNaN2008(); + virtual void emitDirectiveNaNLegacy(); + virtual void emitDirectiveOptionPic0(); + virtual void emitDirectiveOptionPic2(); + virtual void emitDirectiveInsn(); + 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 emitDirectiveSetArch(StringRef Arch); + virtual void emitDirectiveSetMips0(); + virtual void emitDirectiveSetMips1(); + virtual void emitDirectiveSetMips2(); + virtual void emitDirectiveSetMips3(); + virtual void emitDirectiveSetMips4(); + virtual void emitDirectiveSetMips5(); + virtual void emitDirectiveSetMips32(); + virtual void emitDirectiveSetMips32R2(); + virtual void emitDirectiveSetMips32R3(); + virtual void emitDirectiveSetMips32R5(); + virtual void emitDirectiveSetMips32R6(); + virtual void emitDirectiveSetMips64(); + virtual void emitDirectiveSetMips64R2(); + virtual void emitDirectiveSetMips64R3(); + virtual void emitDirectiveSetMips64R5(); + virtual void emitDirectiveSetMips64R6(); + virtual void emitDirectiveSetDsp(); + virtual void emitDirectiveSetNoDsp(); + virtual void emitDirectiveSetPop(); + virtual void emitDirectiveSetPush(); + virtual void emitDirectiveSetSoftFloat(); + virtual void emitDirectiveSetHardFloat(); + + // PIC support + virtual void emitDirectiveCpLoad(unsigned RegNo); + virtual void emitDirectiveCpRestore(SmallVector<MCInst, 3> &StoreInsts, + int Offset); + virtual void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, + const MCSymbol &Sym, bool IsReg); + virtual void emitDirectiveCpreturn(unsigned SaveLocation, + bool SaveLocationIsRegister); + + // FP abiflags directives + virtual void emitDirectiveModuleFP(); + virtual void emitDirectiveModuleOddSPReg(); + virtual void emitDirectiveModuleSoftFloat(); + virtual void emitDirectiveModuleHardFloat(); + virtual void emitDirectiveSetFp(MipsABIFlagsSection::FpABIKind Value); + virtual void emitDirectiveSetOddSPReg(); + virtual void emitDirectiveSetNoOddSPReg(); + + void forbidModuleDirective() { ModuleDirectiveAllowed = false; } + void reallowModuleDirective() { ModuleDirectiveAllowed = true; } + bool isModuleDirectiveAllowed() { return ModuleDirectiveAllowed; } + + // This method enables template classes to set internal abi flags + // structure values. + template <class PredicateLibrary> + void updateABIInfo(const PredicateLibrary &P) { + ABI = P.getABI(); + ABIFlagsSection.setAllFromPredicates(P); + } + + MipsABIFlagsSection &getABIFlagsSection() { return ABIFlagsSection; } + const MipsABIInfo &getABI() const { + assert(ABI.hasValue() && "ABI hasn't been set!"); + return *ABI; + } + +protected: + llvm::Optional<MipsABIInfo> ABI; + MipsABIFlagsSection ABIFlagsSection; + + bool GPRInfoSet; + unsigned GPRBitMask; + int GPROffset; + + bool FPRInfoSet; + unsigned FPRBitMask; + int FPROffset; + + bool FrameInfoSet; + int FrameOffset; + unsigned FrameReg; + unsigned ReturnReg; + +private: + bool ModuleDirectiveAllowed; +}; + +// This part is for ascii assembly output +class MipsTargetAsmStreamer : public MipsTargetStreamer { + formatted_raw_ostream &OS; + +public: + MipsTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS); + void emitDirectiveSetMicroMips() override; + void emitDirectiveSetNoMicroMips() override; + void emitDirectiveSetMips16() override; + void emitDirectiveSetNoMips16() override; + + void emitDirectiveSetReorder() override; + void emitDirectiveSetNoReorder() override; + void emitDirectiveSetMacro() override; + void emitDirectiveSetNoMacro() override; + void emitDirectiveSetMsa() override; + void emitDirectiveSetNoMsa() override; + void emitDirectiveSetAt() override; + void emitDirectiveSetAtWithArg(unsigned RegNo) override; + void emitDirectiveSetNoAt() override; + void emitDirectiveEnd(StringRef Name) override; + + void emitDirectiveEnt(const MCSymbol &Symbol) override; + void emitDirectiveAbiCalls() override; + void emitDirectiveNaN2008() override; + void emitDirectiveNaNLegacy() override; + void emitDirectiveOptionPic0() override; + void emitDirectiveOptionPic2() override; + void emitDirectiveInsn() override; + void emitFrame(unsigned StackReg, unsigned StackSize, + unsigned ReturnReg) override; + void emitMask(unsigned CPUBitmask, int CPUTopSavedRegOff) override; + void emitFMask(unsigned FPUBitmask, int FPUTopSavedRegOff) override; + + void emitDirectiveSetArch(StringRef Arch) override; + void emitDirectiveSetMips0() override; + void emitDirectiveSetMips1() override; + void emitDirectiveSetMips2() override; + void emitDirectiveSetMips3() override; + void emitDirectiveSetMips4() override; + void emitDirectiveSetMips5() override; + void emitDirectiveSetMips32() override; + void emitDirectiveSetMips32R2() override; + void emitDirectiveSetMips32R3() override; + void emitDirectiveSetMips32R5() override; + void emitDirectiveSetMips32R6() override; + void emitDirectiveSetMips64() override; + void emitDirectiveSetMips64R2() override; + void emitDirectiveSetMips64R3() override; + void emitDirectiveSetMips64R5() override; + void emitDirectiveSetMips64R6() override; + void emitDirectiveSetDsp() override; + void emitDirectiveSetNoDsp() override; + void emitDirectiveSetPop() override; + void emitDirectiveSetPush() override; + void emitDirectiveSetSoftFloat() override; + void emitDirectiveSetHardFloat() override; + + // PIC support + void emitDirectiveCpLoad(unsigned RegNo) override; + void emitDirectiveCpRestore(SmallVector<MCInst, 3> &StoreInsts, + int Offset) override; + void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, + const MCSymbol &Sym, bool IsReg) override; + void emitDirectiveCpreturn(unsigned SaveLocation, + bool SaveLocationIsRegister) override; + + // FP abiflags directives + void emitDirectiveModuleFP() override; + void emitDirectiveModuleOddSPReg() override; + void emitDirectiveModuleSoftFloat() override; + void emitDirectiveModuleHardFloat() override; + void emitDirectiveSetFp(MipsABIFlagsSection::FpABIKind Value) override; + void emitDirectiveSetOddSPReg() override; + void emitDirectiveSetNoOddSPReg() override; +}; + +// This part is for ELF object output +class MipsTargetELFStreamer : public MipsTargetStreamer { + bool MicroMipsEnabled; + const MCSubtargetInfo &STI; + bool Pic; + +public: + bool isMicroMipsEnabled() const { return MicroMipsEnabled; } + MCELFStreamer &getStreamer(); + MipsTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI); + + void emitLabel(MCSymbol *Symbol) override; + void emitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; + void finish() override; + + void emitDirectiveSetMicroMips() override; + void emitDirectiveSetNoMicroMips() override; + void emitDirectiveSetMips16() override; + + void emitDirectiveSetNoReorder() override; + void emitDirectiveEnd(StringRef Name) override; + + void emitDirectiveEnt(const MCSymbol &Symbol) override; + void emitDirectiveAbiCalls() override; + void emitDirectiveNaN2008() override; + void emitDirectiveNaNLegacy() override; + void emitDirectiveOptionPic0() override; + void emitDirectiveOptionPic2() override; + void emitDirectiveInsn() override; + void emitFrame(unsigned StackReg, unsigned StackSize, + unsigned ReturnReg) override; + void emitMask(unsigned CPUBitmask, int CPUTopSavedRegOff) override; + void emitFMask(unsigned FPUBitmask, int FPUTopSavedRegOff) override; + + // PIC support + void emitDirectiveCpLoad(unsigned RegNo) override; + void emitDirectiveCpRestore(SmallVector<MCInst, 3> &StoreInsts, + int Offset) override; + void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, + const MCSymbol &Sym, bool IsReg) override; + void emitDirectiveCpreturn(unsigned SaveLocation, + bool SaveLocationIsRegister) override; + + void emitMipsAbiFlags(); +}; +} +#endif diff --git a/contrib/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp b/contrib/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp new file mode 100644 index 0000000..6a65943 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp @@ -0,0 +1,31 @@ +//===-- MipsTargetInfo.cpp - Mips Target Implementation -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Mips.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/TargetRegistry.h" +using namespace llvm; + +Target llvm::TheMipsTarget, llvm::TheMipselTarget; +Target llvm::TheMips64Target, llvm::TheMips64elTarget; + +extern "C" void LLVMInitializeMipsTargetInfo() { + RegisterTarget<Triple::mips, + /*HasJIT=*/true> X(TheMipsTarget, "mips", "Mips"); + + RegisterTarget<Triple::mipsel, + /*HasJIT=*/true> Y(TheMipselTarget, "mipsel", "Mipsel"); + + RegisterTarget<Triple::mips64, + /*HasJIT=*/true> A(TheMips64Target, "mips64", "Mips64 [experimental]"); + + RegisterTarget<Triple::mips64el, + /*HasJIT=*/true> B(TheMips64elTarget, + "mips64el", "Mips64el [experimental]"); +} |