diff options
Diffstat (limited to 'lib/Target/Mips')
67 files changed, 3408 insertions, 1046 deletions
diff --git a/lib/Target/Mips/Android.mk b/lib/Target/Mips/Android.mk index 4e8831c..9f437f8 100644 --- a/lib/Target/Mips/Android.mk +++ b/lib/Target/Mips/Android.mk @@ -8,6 +8,7 @@ mips_codegen_TBLGEN_TABLES := \ MipsGenMCPseudoLowering.inc \ MipsGenAsmWriter.inc \ MipsGenDAGISel.inc \ + MipsGenFastISel.inc \ MipsGenCallingConv.inc \ MipsGenSubtargetInfo.inc diff --git a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index 86fd386..0c06be8 100644 --- a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -72,72 +72,69 @@ class MipsAsmParser : public MCTargetAsmParser { #define GET_ASSEMBLER_HEADER #include "MipsGenAsmMatcher.inc" + unsigned checkTargetMatchPredicate(MCInst &Inst) override; + bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, - SmallVectorImpl<MCParsedAsmOperand *> &Operands, - MCStreamer &Out, unsigned &ErrorInfo, + OperandVector &Operands, MCStreamer &Out, + unsigned &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, - SmallVectorImpl<MCParsedAsmOperand *> &Operands); + bool ParseParenSuffix(StringRef Name, OperandVector &Operands); - bool ParseBracketSuffix(StringRef Name, - SmallVectorImpl<MCParsedAsmOperand *> &Operands); + bool ParseBracketSuffix(StringRef Name, OperandVector &Operands); - bool - ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, - SmallVectorImpl<MCParsedAsmOperand *> &Operands) override; + bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) override; bool ParseDirective(AsmToken DirectiveID) override; - MipsAsmParser::OperandMatchResultTy - parseMemOperand(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy MatchAnyRegisterNameWithoutDollar( - SmallVectorImpl<MCParsedAsmOperand *> &Operands, StringRef Identifier, - SMLoc S); + MipsAsmParser::OperandMatchResultTy parseMemOperand(OperandVector &Operands); MipsAsmParser::OperandMatchResultTy - MatchAnyRegisterWithoutDollar(SmallVectorImpl<MCParsedAsmOperand *> &Operands, - SMLoc S); + MatchAnyRegisterNameWithoutDollar(OperandVector &Operands, + StringRef Identifier, SMLoc S); MipsAsmParser::OperandMatchResultTy - ParseAnyRegister(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MatchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S); - MipsAsmParser::OperandMatchResultTy - ParseImm(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MipsAsmParser::OperandMatchResultTy ParseAnyRegister(OperandVector &Operands); - MipsAsmParser::OperandMatchResultTy - ParseJumpTarget(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MipsAsmParser::OperandMatchResultTy ParseImm(OperandVector &Operands); - MipsAsmParser::OperandMatchResultTy - parseInvNum(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MipsAsmParser::OperandMatchResultTy ParseJumpTarget(OperandVector &Operands); - MipsAsmParser::OperandMatchResultTy - ParseLSAImm(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MipsAsmParser::OperandMatchResultTy parseInvNum(OperandVector &Operands); - bool searchSymbolAlias(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MipsAsmParser::OperandMatchResultTy ParseLSAImm(OperandVector &Operands); - bool ParseOperand(SmallVectorImpl<MCParsedAsmOperand *> &, - StringRef Mnemonic); + bool searchSymbolAlias(OperandVector &Operands); + + bool ParseOperand(OperandVector &, StringRef Mnemonic); bool needsExpansion(MCInst &Inst); - void expandInstruction(MCInst &Inst, SMLoc IDLoc, + // Expands assembly pseudo instructions. + // Returns false on success, true otherwise. + bool expandInstruction(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); - void expandLoadImm(MCInst &Inst, SMLoc IDLoc, + + bool expandLoadImm(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); - void expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, + + bool expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); - void expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, + + bool expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); + void expandMemInst(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions, bool isLoad, bool isImmOpnd); - bool reportParseError(StringRef ErrorMsg); - bool reportParseError(SMLoc Loc, StringRef ErrorMsg); + bool reportParseError(Twine ErrorMsg); + bool reportParseError(SMLoc Loc, Twine ErrorMsg); bool parseMemOffset(const MCExpr *&Res, bool isParenExpr); bool parseRelocOperand(const MCExpr *&Res); @@ -159,32 +156,20 @@ class MipsAsmParser : public MCTargetAsmParser { bool parseSetReorderDirective(); bool parseSetNoReorderDirective(); bool parseSetNoMips16Directive(); + bool parseSetFpDirective(); bool parseSetAssignment(); bool parseDataDirective(unsigned Size, SMLoc L); bool parseDirectiveGpWord(); bool parseDirectiveGpDWord(); + bool parseDirectiveModule(); + bool parseDirectiveModuleFP(); + bool parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI, + StringRef Directive); MCSymbolRefExpr::VariantKind getVariantKind(StringRef Symbol); - bool isGP64() const { - return (STI.getFeatureBits() & Mips::FeatureGP64Bit) != 0; - } - - bool isFP64() const { - return (STI.getFeatureBits() & Mips::FeatureFP64Bit) != 0; - } - - bool isN32() const { return STI.getFeatureBits() & Mips::FeatureN32; } - bool isN64() const { return STI.getFeatureBits() & Mips::FeatureN64; } - - bool isMicroMips() const { - return STI.getFeatureBits() & Mips::FeatureMicroMips; - } - - bool parseRegister(unsigned &RegNum); - bool eatComma(StringRef ErrorStr); int matchCPURegisterName(StringRef Symbol); @@ -205,7 +190,7 @@ class MipsAsmParser : public MCTargetAsmParser { unsigned getGPR(int RegNo); - int getATReg(); + int getATReg(SMLoc Loc); bool processInstruction(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); @@ -230,23 +215,85 @@ class MipsAsmParser : public MCTargetAsmParser { } public: + enum MipsMatchResultTy { + Match_RequiresDifferentSrcAndDst = FIRST_TARGET_MATCH_RESULT_TY +#define GET_OPERAND_DIAGNOSTIC_TYPES +#include "MipsGenAsmMatcher.inc" +#undef GET_OPERAND_DIAGNOSTIC_TYPES + + }; + MipsAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser, - const MCInstrInfo &MII, - const MCTargetOptions &Options) + const MCInstrInfo &MII, const MCTargetOptions &Options) : MCTargetAsmParser(), STI(sti), Parser(parser) { // Initialize the set of available features. setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + getTargetStreamer().updateABIInfo(*this); + // Assert exactly one ABI was chosen. assert((((STI.getFeatureBits() & Mips::FeatureO32) != 0) + ((STI.getFeatureBits() & Mips::FeatureEABI) != 0) + ((STI.getFeatureBits() & Mips::FeatureN32) != 0) + ((STI.getFeatureBits() & Mips::FeatureN64) != 0)) == 1); + + if (!isABI_O32() && !allowOddSPReg() != 0) + report_fatal_error("-mno-odd-spreg requires the O32 ABI"); } MCAsmParser &getParser() const { return Parser; } MCAsmLexer &getLexer() const { return Parser.getLexer(); } + /// True if all of $fcc0 - $fcc7 exist for the current ISA. + bool hasEightFccRegisters() const { return hasMips4() || hasMips32(); } + + bool isGP64bit() const { return STI.getFeatureBits() & Mips::FeatureGP64Bit; } + bool isFP64bit() const { return STI.getFeatureBits() & Mips::FeatureFP64Bit; } + bool isABI_N32() const { return STI.getFeatureBits() & Mips::FeatureN32; } + bool isABI_N64() const { return STI.getFeatureBits() & Mips::FeatureN64; } + bool isABI_O32() const { return STI.getFeatureBits() & Mips::FeatureO32; } + bool isABI_FPXX() const { return false; } // TODO: add check for FeatureXX + + bool allowOddSPReg() const { + return !(STI.getFeatureBits() & Mips::FeatureNoOddSPReg); + } + + bool inMicroMipsMode() const { + return STI.getFeatureBits() & Mips::FeatureMicroMips; + } + bool hasMips1() const { return STI.getFeatureBits() & Mips::FeatureMips1; } + bool hasMips2() const { return STI.getFeatureBits() & Mips::FeatureMips2; } + bool hasMips3() const { return STI.getFeatureBits() & Mips::FeatureMips3; } + bool hasMips4() const { return STI.getFeatureBits() & Mips::FeatureMips4; } + bool hasMips5() const { return STI.getFeatureBits() & Mips::FeatureMips5; } + bool hasMips32() const { + return (STI.getFeatureBits() & Mips::FeatureMips32); + } + bool hasMips64() const { + return (STI.getFeatureBits() & Mips::FeatureMips64); + } + bool hasMips32r2() const { + return (STI.getFeatureBits() & Mips::FeatureMips32r2); + } + bool hasMips64r2() const { + return (STI.getFeatureBits() & Mips::FeatureMips64r2); + } + bool hasMips32r6() const { + return (STI.getFeatureBits() & Mips::FeatureMips32r6); + } + bool hasMips64r6() const { + return (STI.getFeatureBits() & Mips::FeatureMips64r6); + } + bool hasDSP() const { return (STI.getFeatureBits() & Mips::FeatureDSP); } + bool hasDSPR2() const { return (STI.getFeatureBits() & Mips::FeatureDSPR2); } + bool hasMSA() const { return (STI.getFeatureBits() & Mips::FeatureMSA); } + + bool inMips16Mode() const { + return STI.getFeatureBits() & Mips::FeatureMips16; + } + // TODO: see how can we get this info. + bool mipsSEUsesSoftFloat() const { return false; } + /// Warn if RegNo is the current assembler temporary. void WarnIfAssemblerTemporary(int RegNo, SMLoc Loc); }; @@ -261,9 +308,9 @@ 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 isGP64()) + RegKind_GPR = 1, /// GPR32 and GPR64 (depending on isGP64bit()) RegKind_FGR = 2, /// FGR32, FGR64, AFGR64 (depending on context and - /// isFP64()) + /// isFP64bit()) RegKind_FCC = 4, /// FCC RegKind_MSA128 = 8, /// MSA128[BHWD] (makes no difference which) RegKind_MSACtrl = 16, /// MSA control registers @@ -289,9 +336,11 @@ private: k_Token /// A simple token } Kind; +public: MipsOperand(KindTy K, MipsAsmParser &Parser) : MCParsedAsmOperand(), Kind(K), AsmParser(Parser) {} +private: /// For diagnostics, and checking the assembler temporary MipsAsmParser &AsmParser; @@ -330,10 +379,11 @@ private: SMLoc StartLoc, EndLoc; /// Internal constructor for register kinds - static MipsOperand *CreateReg(unsigned Index, RegKind RegKind, - const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, - MipsAsmParser &Parser) { - MipsOperand *Op = new MipsOperand(k_RegisterIndex, Parser); + 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; @@ -521,6 +571,10 @@ public: 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.allowOddSPReg() && RegIdx.Index & 1) + AsmParser.Error(StartLoc, "-mno-odd-spreg prohibits the use of odd FPU " + "registers"); } void addFGRH32AsmRegOperands(MCInst &Inst, unsigned N) const { @@ -612,6 +666,12 @@ public: return Kind == k_Token; } bool isMem() const override { return Kind == k_Memory; } + bool isConstantMemOff() const { + return isMem() && dyn_cast<MCConstantExpr>(getMemOff()); + } + template <unsigned Bits> bool isMemWithSimmOffset() const { + return isMem() && isConstantMemOff() && isInt<Bits>(getConstantMemOff()); + } bool isInvNum() const { return Kind == k_Immediate; } bool isLSAImm() const { if (!isConstantImm()) @@ -656,9 +716,13 @@ public: return Mem.Off; } - static MipsOperand *CreateToken(StringRef Str, SMLoc S, - MipsAsmParser &Parser) { - MipsOperand *Op = new MipsOperand(k_Token, Parser); + int64_t getConstantMemOff() const { + return static_cast<const MCConstantExpr *>(getMemOff())->getValue(); + } + + static std::unique_ptr<MipsOperand> CreateToken(StringRef Str, SMLoc S, + MipsAsmParser &Parser) { + auto Op = make_unique<MipsOperand>(k_Token, Parser); Op->Tok.Data = Str.data(); Op->Tok.Length = Str.size(); Op->StartLoc = S; @@ -668,74 +732,75 @@ public: /// Create a numeric register (e.g. $1). The exact register remains /// unresolved until an instruction successfully matches - static MipsOperand *CreateNumericReg(unsigned Index, - const MCRegisterInfo *RegInfo, SMLoc S, - SMLoc E, MipsAsmParser &Parser) { + 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 MipsOperand *CreateGPRReg(unsigned Index, - const MCRegisterInfo *RegInfo, SMLoc S, - SMLoc E, MipsAsmParser &Parser) { + 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 MipsOperand *CreateFGRReg(unsigned Index, - const MCRegisterInfo *RegInfo, SMLoc S, - SMLoc E, MipsAsmParser &Parser) { + 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 an FCC. /// This is typically only used for named registers such as $fcc0. - static MipsOperand *CreateFCCReg(unsigned Index, - const MCRegisterInfo *RegInfo, SMLoc S, - SMLoc E, MipsAsmParser &Parser) { + 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 MipsOperand *CreateACCReg(unsigned Index, - const MCRegisterInfo *RegInfo, SMLoc S, - SMLoc E, MipsAsmParser &Parser) { + 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 MipsOperand *CreateMSA128Reg(unsigned Index, - const MCRegisterInfo *RegInfo, SMLoc S, - SMLoc E, MipsAsmParser &Parser) { + 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 MipsOperand *CreateMSACtrlReg(unsigned Index, - const MCRegisterInfo *RegInfo, SMLoc S, - SMLoc E, MipsAsmParser &Parser) { + 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 MipsOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E, - MipsAsmParser &Parser) { - MipsOperand *Op = new MipsOperand(k_Immediate, 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 MipsOperand *CreateMem(MipsOperand *Base, const MCExpr *Off, SMLoc S, - SMLoc E, MipsAsmParser &Parser) { - MipsOperand *Op = new MipsOperand(k_Memory, Parser); - Op->Mem.Base = Base; + 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; @@ -756,7 +821,11 @@ public: return isRegIdx() && RegIdx.Kind & RegKind_CCR && RegIdx.Index <= 31; } bool isFCCAsmReg() const { - return isRegIdx() && RegIdx.Kind & RegKind_FCC && RegIdx.Index <= 7; + 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; @@ -849,9 +918,10 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, Offset = Inst.getOperand(2); if (!Offset.isImm()) break; // We'll deal with this situation later on when applying fixups. - if (!isIntN(isMicroMips() ? 17 : 18, Offset.getImm())) + if (!isIntN(inMicroMipsMode() ? 17 : 18, Offset.getImm())) return Error(IDLoc, "branch target out of range"); - if (OffsetToAlignment(Offset.getImm(), 1LL << (isMicroMips() ? 1 : 2))) + if (OffsetToAlignment(Offset.getImm(), + 1LL << (inMicroMipsMode() ? 1 : 2))) return Error(IDLoc, "branch to misaligned address"); break; case Mips::BGEZ: @@ -874,14 +944,23 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, Offset = Inst.getOperand(1); if (!Offset.isImm()) break; // We'll deal with this situation later on when applying fixups. - if (!isIntN(isMicroMips() ? 17 : 18, Offset.getImm())) + if (!isIntN(inMicroMipsMode() ? 17 : 18, Offset.getImm())) return Error(IDLoc, "branch target out of range"); - if (OffsetToAlignment(Offset.getImm(), 1LL << (isMicroMips() ? 1 : 2))) + if (OffsetToAlignment(Offset.getImm(), + 1LL << (inMicroMipsMode() ? 1 : 2))) return Error(IDLoc, "branch to misaligned address"); break; } } + // SSNOP is deprecated on MIPS32r6/MIPS64r6 + // We still accept it but it is a normal nop. + if (hasMips32r6() && Inst.getOpcode() == Mips::SSNOP) { + std::string ISA = hasMips64r6() ? "MIPS64r6" : "MIPS32r6"; + Warning(IDLoc, "ssnop is deprecated for " + ISA + " and is equivalent to a " + "nop instruction"); + } + if (MCID.hasDelaySlot() && Options.isReorder()) { // If this instruction has a delay slot and .set reorder is active, // emit a NOP after it. @@ -930,7 +1009,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, } // if load/store if (needsExpansion(Inst)) - expandInstruction(Inst, IDLoc, Instructions); + return expandInstruction(Inst, IDLoc, Instructions); else Instructions.push_back(Inst); @@ -943,17 +1022,27 @@ bool MipsAsmParser::needsExpansion(MCInst &Inst) { case Mips::LoadImm32Reg: case Mips::LoadAddr32Imm: case Mips::LoadAddr32Reg: + case Mips::LoadImm64Reg: return true; default: return false; } } -void MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc, +bool MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { switch (Inst.getOpcode()) { + default: + assert(0 && "unimplemented expansion"); + return true; case Mips::LoadImm32Reg: return expandLoadImm(Inst, IDLoc, Instructions); + case Mips::LoadImm64Reg: + if (!isGP64bit()) { + Error(IDLoc, "instruction requires a CPU feature not currently enabled"); + return true; + } + return expandLoadImm(Inst, IDLoc, Instructions); case Mips::LoadAddr32Imm: return expandLoadAddressImm(Inst, IDLoc, Instructions); case Mips::LoadAddr32Reg: @@ -961,7 +1050,31 @@ void MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc, } } -void MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc, +namespace { +template <int Shift, bool PerformShift> +void createShiftOr(int64_t Value, unsigned RegNo, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + MCInst tmpInst; + if (PerformShift) { + tmpInst.setOpcode(Mips::DSLL); + tmpInst.addOperand(MCOperand::CreateReg(RegNo)); + tmpInst.addOperand(MCOperand::CreateReg(RegNo)); + tmpInst.addOperand(MCOperand::CreateImm(16)); + tmpInst.setLoc(IDLoc); + Instructions.push_back(tmpInst); + tmpInst.clear(); + } + tmpInst.setOpcode(Mips::ORi); + tmpInst.addOperand(MCOperand::CreateReg(RegNo)); + tmpInst.addOperand(MCOperand::CreateReg(RegNo)); + tmpInst.addOperand( + MCOperand::CreateImm(((Value & (0xffffLL << Shift)) >> Shift))); + tmpInst.setLoc(IDLoc); + Instructions.push_back(tmpInst); +} +} + +bool MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { MCInst tmpInst; const MCOperand &ImmOp = Inst.getOperand(1); @@ -969,8 +1082,10 @@ void MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc, const MCOperand &RegOp = Inst.getOperand(0); assert(RegOp.isReg() && "expected register operand kind"); - int ImmValue = ImmOp.getImm(); + int64_t ImmValue = ImmOp.getImm(); tmpInst.setLoc(IDLoc); + // FIXME: gas has a special case for values that are 000...1111, which + // becomes a li -1 and then a dsrl if (0 <= ImmValue && ImmValue <= 65535) { // For 0 <= j <= 65535. // li d,j => ori d,$zero,j @@ -987,25 +1102,76 @@ void MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc, tmpInst.addOperand(MCOperand::CreateReg(Mips::ZERO)); tmpInst.addOperand(MCOperand::CreateImm(ImmValue)); Instructions.push_back(tmpInst); - } else { - // For any other value of j that is representable as a 32-bit integer. + } else if ((ImmValue & 0xffffffff) == ImmValue) { + // For any value of j that is representable as a 32-bit integer, create + // a sequence of: // li d,j => lui d,hi16(j) // ori d,d,lo16(j) tmpInst.setOpcode(Mips::LUi); tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); tmpInst.addOperand(MCOperand::CreateImm((ImmValue & 0xffff0000) >> 16)); Instructions.push_back(tmpInst); - tmpInst.clear(); - tmpInst.setOpcode(Mips::ORi); + createShiftOr<0, false>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + } else if ((ImmValue & (0xffffLL << 48)) == 0) { + if (!isGP64bit()) { + Error(IDLoc, "instruction requires a CPU feature not currently enabled"); + return true; + } + + // <------- lo32 ------> + // <------- hi32 ------> + // <- hi16 -> <- lo16 -> + // _________________________________ + // | | | | + // | 16-bytes | 16-bytes | 16-bytes | + // |__________|__________|__________| + // + // For any value of j that is representable as a 48-bit integer, create + // a sequence of: + // li d,j => lui d,hi16(j) + // ori d,d,hi16(lo32(j)) + // dsll d,d,16 + // ori d,d,lo16(lo32(j)) + tmpInst.setOpcode(Mips::LUi); tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); + tmpInst.addOperand( + MCOperand::CreateImm((ImmValue & (0xffffLL << 32)) >> 32)); + Instructions.push_back(tmpInst); + createShiftOr<16, false>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + createShiftOr<0, true>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + } else { + if (!isGP64bit()) { + Error(IDLoc, "instruction requires a CPU feature not currently enabled"); + return true; + } + + // <------- hi32 ------> <------- lo32 ------> + // <- hi16 -> <- lo16 -> + // ___________________________________________ + // | | | | | + // | 16-bytes | 16-bytes | 16-bytes | 16-bytes | + // |__________|__________|__________|__________| + // + // For any value of j that isn't representable as a 48-bit integer. + // li d,j => lui d,hi16(j) + // ori d,d,lo16(hi32(j)) + // dsll d,d,16 + // ori d,d,hi16(lo32(j)) + // dsll d,d,16 + // ori d,d,lo16(lo32(j)) + tmpInst.setOpcode(Mips::LUi); tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); - tmpInst.addOperand(MCOperand::CreateImm(ImmValue & 0xffff)); - tmpInst.setLoc(IDLoc); + tmpInst.addOperand( + MCOperand::CreateImm((ImmValue & (0xffffLL << 48)) >> 48)); Instructions.push_back(tmpInst); + createShiftOr<32, false>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + createShiftOr<16, true>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + createShiftOr<0, true>(ImmValue, RegOp.getReg(), IDLoc, Instructions); } + return false; } -void +bool MipsAsmParser::expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { MCInst tmpInst; @@ -1046,9 +1212,10 @@ MipsAsmParser::expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, tmpInst.addOperand(MCOperand::CreateReg(SrcRegOp.getReg())); Instructions.push_back(tmpInst); } + return false; } -void +bool MipsAsmParser::expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { MCInst tmpInst; @@ -1080,6 +1247,7 @@ MipsAsmParser::expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, tmpInst.addOperand(MCOperand::CreateImm(ImmValue & 0xffff)); Instructions.push_back(tmpInst); } + return false; } void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, @@ -1090,8 +1258,6 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, unsigned ImmOffset, HiOffset, LoOffset; const MCExpr *ExprOffset; unsigned TmpRegNum; - unsigned AtRegNum = getReg( - (isGP64()) ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, getATReg()); // 1st operand is either the source or destination register. assert(Inst.getOperand(0).isReg() && "expected register operand kind"); unsigned RegOpNum = Inst.getOperand(0).getReg(); @@ -1111,10 +1277,46 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, ExprOffset = Inst.getOperand(2).getExpr(); // All instructions will have the same location. TempInst.setLoc(IDLoc); - // 1st instruction in expansion is LUi. For load instruction we can use - // the dst register as a temporary if base and dst are different, - // but for stores we must use $at. - TmpRegNum = (isLoad && (BaseRegNum != RegOpNum)) ? RegOpNum : AtRegNum; + // These are some of the types of expansions we perform here: + // 1) lw $8, sym => lui $8, %hi(sym) + // lw $8, %lo(sym)($8) + // 2) lw $8, offset($9) => lui $8, %hi(offset) + // add $8, $8, $9 + // lw $8, %lo(offset)($9) + // 3) lw $8, offset($8) => lui $at, %hi(offset) + // add $at, $at, $8 + // lw $8, %lo(offset)($at) + // 4) sw $8, sym => lui $at, %hi(sym) + // sw $8, %lo(sym)($at) + // 5) sw $8, offset($8) => lui $at, %hi(offset) + // add $at, $at, $8 + // sw $8, %lo(offset)($at) + // 6) ldc1 $f0, sym => lui $at, %hi(sym) + // ldc1 $f0, %lo(sym)($at) + // + // For load instructions we can use the destination register as a temporary + // if base and dst are different (examples 1 and 2) and if the base register + // is general purpose otherwise we must use $at (example 6) and error if it's + // not available. For stores we must use $at (examples 4 and 5) because we + // must not clobber the source register setting up the offset. + const MCInstrDesc &Desc = getInstDesc(Inst.getOpcode()); + int16_t RegClassOp0 = Desc.OpInfo[0].RegClass; + unsigned RegClassIDOp0 = + getContext().getRegisterInfo()->getRegClass(RegClassOp0).getID(); + bool IsGPR = (RegClassIDOp0 == Mips::GPR32RegClassID) || + (RegClassIDOp0 == Mips::GPR64RegClassID); + if (isLoad && IsGPR && (BaseRegNum != RegOpNum)) + TmpRegNum = RegOpNum; + else { + int AT = getATReg(IDLoc); + // At this point we need AT to perform the expansions and we exit if it is + // not available. + if (!AT) + return; + TmpRegNum = getReg( + (isGP64bit()) ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, AT); + } + TempInst.setOpcode(Mips::LUi); TempInst.addOperand(MCOperand::CreateReg(TmpRegNum)); if (isImmOpnd) @@ -1164,10 +1366,24 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, TempInst.clear(); } -bool MipsAsmParser::MatchAndEmitInstruction( - SMLoc IDLoc, unsigned &Opcode, - SmallVectorImpl<MCParsedAsmOperand *> &Operands, MCStreamer &Out, - unsigned &ErrorInfo, bool MatchingInlineAsm) { +unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) { + // As described by the Mips32r2 spec, the registers Rd and Rs for + // jalr.hb must be different. + unsigned Opcode = Inst.getOpcode(); + + if (Opcode == Mips::JALR_HB && + (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg())) + return Match_RequiresDifferentSrcAndDst; + + return Match_Success; +} + +bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, + MCStreamer &Out, + unsigned &ErrorInfo, + bool MatchingInlineAsm) { + MCInst Inst; SmallVector<MCInst, 8> Instructions; unsigned MatchResult = @@ -1192,7 +1408,7 @@ bool MipsAsmParser::MatchAndEmitInstruction( if (ErrorInfo >= Operands.size()) return Error(IDLoc, "too few operands for instruction"); - ErrorLoc = ((MipsOperand *)Operands[ErrorInfo])->getStartLoc(); + ErrorLoc = ((MipsOperand &)*Operands[ErrorInfo]).getStartLoc(); if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc; } @@ -1201,6 +1417,8 @@ bool MipsAsmParser::MatchAndEmitInstruction( } case Match_MnemonicFail: return Error(IDLoc, "invalid instruction"); + case Match_RequiresDifferentSrcAndDst: + return Error(IDLoc, "source and destination must be different"); } return true; } @@ -1254,7 +1472,7 @@ int MipsAsmParser::matchCPURegisterName(StringRef Name) { .Case("t9", 25) .Default(-1); - if (isN32() || isN64()) { + if (isABI_N32() || isABI_N64()) { // Although SGI documentation just cuts out t0-t3 for n32/n64, // GNU pushes the values of t0-t3 to override the o32/o64 values for t4-t7 // We are supporting both cases, so for t0-t3 we'll just push them to t4-t7. @@ -1354,10 +1572,11 @@ bool MipsAssemblerOptions::setATReg(unsigned Reg) { return true; } -int MipsAsmParser::getATReg() { +int MipsAsmParser::getATReg(SMLoc Loc) { int AT = Options.getATRegNum(); if (AT == 0) - TokError("Pseudo instruction requires $at, which is not available"); + reportParseError(Loc, + "Pseudo instruction requires $at, which is not available"); return AT; } @@ -1366,7 +1585,7 @@ unsigned MipsAsmParser::getReg(int RC, int RegNo) { } unsigned MipsAsmParser::getGPR(int RegNo) { - return getReg(isGP64() ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, + return getReg(isGP64bit() ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, RegNo); } @@ -1378,9 +1597,7 @@ int MipsAsmParser::matchRegisterByNumber(unsigned RegNum, unsigned RegClass) { return getReg(RegClass, RegNum); } -bool -MipsAsmParser::ParseOperand(SmallVectorImpl<MCParsedAsmOperand *> &Operands, - StringRef Mnemonic) { +bool MipsAsmParser::ParseOperand(OperandVector &Operands, StringRef Mnemonic) { DEBUG(dbgs() << "ParseOperand\n"); // Check if the current operand has a custom associated parser, if so, try to @@ -1431,6 +1648,7 @@ MipsAsmParser::ParseOperand(SmallVectorImpl<MCParsedAsmOperand *> &Operands, case AsmToken::Minus: case AsmToken::Plus: case AsmToken::Integer: + case AsmToken::Tilde: case AsmToken::String: { DEBUG(dbgs() << ".. generic integer\n"); OperandMatchResultTy ResTy = ParseImm(Operands); @@ -1578,11 +1796,11 @@ bool MipsAsmParser::parseRelocOperand(const MCExpr *&Res) { bool MipsAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { - SmallVector<MCParsedAsmOperand *, 1> Operands; + 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()); + MipsOperand &Operand = static_cast<MipsOperand &>(*Operands.front()); StartLoc = Operand.getStartLoc(); EndLoc = Operand.getEndLoc(); @@ -1592,11 +1810,9 @@ bool MipsAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, // register is a parse error. if (Operand.isGPRAsmReg()) { // Resolve to GPR32 or GPR64 appropriately. - RegNo = isGP64() ? Operand.getGPR64Reg() : Operand.getGPR32Reg(); + RegNo = isGP64bit() ? Operand.getGPR64Reg() : Operand.getGPR32Reg(); } - delete &Operand; - return (RegNo == (unsigned)-1); } @@ -1632,8 +1848,8 @@ bool MipsAsmParser::parseMemOffset(const MCExpr *&Res, bool isParenExpr) { return Result; } -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseMemOperand(OperandVector &Operands) { DEBUG(dbgs() << "parseMemOperand\n"); const MCExpr *IdVal = nullptr; SMLoc S; @@ -1653,8 +1869,8 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( const AsmToken &Tok = Parser.getTok(); // Get the next token. if (Tok.isNot(AsmToken::LParen)) { - MipsOperand *Mnemonic = static_cast<MipsOperand *>(Operands[0]); - if (Mnemonic->getToken() == "la") { + MipsOperand &Mnemonic = static_cast<MipsOperand &>(*Operands[0]); + if (Mnemonic.getToken() == "la") { SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this)); @@ -1666,9 +1882,10 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( // Zero register assumed, add a memory operand with ZERO as its base. // "Base" will be managed by k_Memory. - MipsOperand *Base = MipsOperand::CreateGPRReg( - 0, getContext().getRegisterInfo(), S, E, *this); - Operands.push_back(MipsOperand::CreateMem(Base, IdVal, S, E, *this)); + 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"); @@ -1695,7 +1912,8 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( IdVal = MCConstantExpr::Create(0, getContext()); // Replace the register operand with the memory operand. - MipsOperand *op = static_cast<MipsOperand *>(Operands.back()); + 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(); @@ -1709,12 +1927,11 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( getContext()); } - Operands.push_back(MipsOperand::CreateMem(op, IdVal, S, E, *this)); + Operands.push_back(MipsOperand::CreateMem(std::move(op), IdVal, S, E, *this)); return MatchOperand_Success; } -bool MipsAsmParser::searchSymbolAlias( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { +bool MipsAsmParser::searchSymbolAlias(OperandVector &Operands) { MCSymbol *Sym = getContext().LookupSymbol(Parser.getTok().getIdentifier()); if (Sym) { @@ -1740,9 +1957,8 @@ bool MipsAsmParser::searchSymbolAlias( } else if (Expr->getKind() == MCExpr::Constant) { Parser.Lex(); const MCConstantExpr *Const = static_cast<const MCConstantExpr *>(Expr); - MipsOperand *op = - MipsOperand::CreateImm(Const, S, Parser.getTok().getLoc(), *this); - Operands.push_back(op); + Operands.push_back( + MipsOperand::CreateImm(Const, S, Parser.getTok().getLoc(), *this)); return true; } } @@ -1750,9 +1966,9 @@ bool MipsAsmParser::searchSymbolAlias( } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::MatchAnyRegisterNameWithoutDollar( - SmallVectorImpl<MCParsedAsmOperand *> &Operands, StringRef Identifier, - SMLoc S) { +MipsAsmParser::MatchAnyRegisterNameWithoutDollar(OperandVector &Operands, + StringRef Identifier, + SMLoc S) { int Index = matchCPURegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::CreateGPRReg( @@ -1799,8 +2015,7 @@ MipsAsmParser::MatchAnyRegisterNameWithoutDollar( } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::MatchAnyRegisterWithoutDollar( - SmallVectorImpl<MCParsedAsmOperand *> &Operands, SMLoc S) { +MipsAsmParser::MatchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S) { auto Token = Parser.getLexer().peekTok(false); if (Token.is(AsmToken::Identifier)) { @@ -1822,8 +2037,8 @@ MipsAsmParser::MatchAnyRegisterWithoutDollar( return MatchOperand_NoMatch; } -MipsAsmParser::OperandMatchResultTy MipsAsmParser::ParseAnyRegister( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::ParseAnyRegister(OperandVector &Operands) { DEBUG(dbgs() << "ParseAnyRegister\n"); auto Token = Parser.getTok(); @@ -1850,7 +2065,7 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::ParseAnyRegister( } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::ParseImm(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { +MipsAsmParser::ParseImm(OperandVector &Operands) { switch (getLexer().getKind()) { default: return MatchOperand_NoMatch; @@ -1858,6 +2073,7 @@ MipsAsmParser::ParseImm(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { case AsmToken::Minus: case AsmToken::Plus: case AsmToken::Integer: + case AsmToken::Tilde: case AsmToken::String: break; } @@ -1872,8 +2088,8 @@ MipsAsmParser::ParseImm(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { return MatchOperand_Success; } -MipsAsmParser::OperandMatchResultTy MipsAsmParser::ParseJumpTarget( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::ParseJumpTarget(OperandVector &Operands) { DEBUG(dbgs() << "ParseJumpTarget\n"); SMLoc S = getLexer().getLoc(); @@ -1899,7 +2115,7 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::ParseJumpTarget( } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseInvNum(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { +MipsAsmParser::parseInvNum(OperandVector &Operands) { const MCExpr *IdVal; // If the first token is '$' we may have register operand. if (Parser.getTok().is(AsmToken::Dollar)) @@ -1917,7 +2133,7 @@ MipsAsmParser::parseInvNum(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::ParseLSAImm(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { +MipsAsmParser::ParseLSAImm(OperandVector &Operands) { switch (getLexer().getKind()) { default: return MatchOperand_NoMatch; @@ -1996,8 +2212,7 @@ MCSymbolRefExpr::VariantKind MipsAsmParser::getVariantKind(StringRef Symbol) { /// ::= '(', register, ')' /// handle it before we iterate so we don't get tripped up by the lack of /// a comma. -bool MipsAsmParser::ParseParenSuffix( - StringRef Name, SmallVectorImpl<MCParsedAsmOperand *> &Operands) { +bool MipsAsmParser::ParseParenSuffix(StringRef Name, OperandVector &Operands) { if (getLexer().is(AsmToken::LParen)) { Operands.push_back( MipsOperand::CreateToken("(", getLexer().getLoc(), *this)); @@ -2025,8 +2240,8 @@ bool MipsAsmParser::ParseParenSuffix( /// ::= '[', integer, ']' /// handle it before we iterate so we don't get tripped up by the lack of /// a comma. -bool MipsAsmParser::ParseBracketSuffix( - StringRef Name, SmallVectorImpl<MCParsedAsmOperand *> &Operands) { +bool MipsAsmParser::ParseBracketSuffix(StringRef Name, + OperandVector &Operands) { if (getLexer().is(AsmToken::LBrac)) { Operands.push_back( MipsOperand::CreateToken("[", getLexer().getLoc(), *this)); @@ -2048,10 +2263,12 @@ bool MipsAsmParser::ParseBracketSuffix( return false; } -bool MipsAsmParser::ParseInstruction( - ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { +bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) { DEBUG(dbgs() << "ParseInstruction\n"); + // We have reached first instruction, module directive after + // this is forbidden. + getTargetStreamer().setCanHaveModuleDir(false); // Check if we have valid mnemonic if (!mnemonicIsValid(Name, 0)) { Parser.eatToEndOfStatement(); @@ -2098,13 +2315,13 @@ bool MipsAsmParser::ParseInstruction( return false; } -bool MipsAsmParser::reportParseError(StringRef ErrorMsg) { +bool MipsAsmParser::reportParseError(Twine ErrorMsg) { SMLoc Loc = getLexer().getLoc(); Parser.eatToEndOfStatement(); return Error(Loc, ErrorMsg); } -bool MipsAsmParser::reportParseError(SMLoc Loc, StringRef ErrorMsg) { +bool MipsAsmParser::reportParseError(SMLoc Loc, Twine ErrorMsg) { return Error(Loc, ErrorMsg); } @@ -2238,6 +2455,32 @@ bool MipsAsmParser::parseSetNoMips16Directive() { return false; } +bool MipsAsmParser::parseSetFpDirective() { + MipsABIFlagsSection::FpABIKind FpAbiVal; + // Line can be: .set fp=32 + // .set fp=xx + // .set fp=64 + Parser.Lex(); // Eat fp token + AsmToken Tok = Parser.getTok(); + if (Tok.isNot(AsmToken::Equal)) { + reportParseError("unexpected token in statement"); + return false; + } + Parser.Lex(); // Eat '=' token. + Tok = Parser.getTok(); + + if (!parseFpABIValue(FpAbiVal, ".set")) + return false; + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token in statement"); + return false; + } + getTargetStreamer().emitDirectiveSetFp(FpAbiVal); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + bool MipsAsmParser::parseSetAssignment() { StringRef Name; const MCExpr *Value; @@ -2296,25 +2539,6 @@ bool MipsAsmParser::parseSetFeature(uint64_t Feature) { return false; } -bool MipsAsmParser::parseRegister(unsigned &RegNum) { - if (!getLexer().is(AsmToken::Dollar)) - return false; - - Parser.Lex(); - - const AsmToken &Reg = Parser.getTok(); - if (Reg.is(AsmToken::Identifier)) { - RegNum = matchCPURegisterName(Reg.getIdentifier()); - } else if (Reg.is(AsmToken::Integer)) { - RegNum = Reg.getIntVal(); - } else { - return false; - } - - Parser.Lex(); - return true; -} - bool MipsAsmParser::eatComma(StringRef ErrorStr) { if (getLexer().isNot(AsmToken::Comma)) { SMLoc Loc = getLexer().getLoc(); @@ -2332,21 +2556,20 @@ bool MipsAsmParser::parseDirectiveCPLoad(SMLoc Loc) { // FIXME: Warn if cpload is used in Mips16 mode. - SmallVector<MCParsedAsmOperand *, 1> Reg; + 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"); + MipsOperand &RegOpnd = static_cast<MipsOperand &>(*Reg[0]); + if (!RegOpnd.isGPRAsmReg()) { + reportParseError(RegOpnd.getStartLoc(), "invalid register"); return false; } - getTargetStreamer().emitDirectiveCpload(RegOpnd->getGPR32Reg()); - delete RegOpnd; + getTargetStreamer().emitDirectiveCpload(RegOpnd.getGPR32Reg()); return false; } @@ -2355,23 +2578,48 @@ bool MipsAsmParser::parseDirectiveCPSetup() { unsigned Save; bool SaveIsReg = true; - if (!parseRegister(FuncReg)) - return reportParseError("expected register containing function address"); - FuncReg = getGPR(FuncReg); + SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> TmpReg; + OperandMatchResultTy ResTy = ParseAnyRegister(TmpReg); + if (ResTy == MatchOperand_NoMatch) { + reportParseError("expected register containing function address"); + Parser.eatToEndOfStatement(); + return false; + } + + MipsOperand &FuncRegOpnd = static_cast<MipsOperand &>(*TmpReg[0]); + if (!FuncRegOpnd.isGPRAsmReg()) { + reportParseError(FuncRegOpnd.getStartLoc(), "invalid register"); + Parser.eatToEndOfStatement(); + return false; + } + + FuncReg = FuncRegOpnd.getGPR32Reg(); + TmpReg.clear(); if (!eatComma("expected comma parsing directive")) return true; - if (!parseRegister(Save)) { + ResTy = ParseAnyRegister(TmpReg); + if (ResTy == MatchOperand_NoMatch) { const AsmToken &Tok = Parser.getTok(); if (Tok.is(AsmToken::Integer)) { Save = Tok.getIntVal(); SaveIsReg = false; Parser.Lex(); - } else - return reportParseError("expected save register or stack offset"); - } else - Save = getGPR(Save); + } else { + reportParseError("expected save register or stack offset"); + Parser.eatToEndOfStatement(); + return false; + } + } else { + MipsOperand &SaveOpnd = static_cast<MipsOperand &>(*TmpReg[0]); + if (!SaveOpnd.isGPRAsmReg()) { + reportParseError(SaveOpnd.getStartLoc(), "invalid register"); + Parser.eatToEndOfStatement(); + return false; + } + Save = SaveOpnd.getGPR32Reg(); + } if (!eatComma("expected comma parsing directive")) return true; @@ -2414,6 +2662,8 @@ bool MipsAsmParser::parseDirectiveSet() { return parseSetNoAtDirective(); } else if (Tok.getString() == "at") { return parseSetAtDirective(); + } else if (Tok.getString() == "fp") { + return parseSetFpDirective(); } else if (Tok.getString() == "reorder") { return parseSetReorderDirective(); } else if (Tok.getString() == "noreorder") { @@ -2546,6 +2796,134 @@ bool MipsAsmParser::parseDirectiveOption() { return false; } +/// parseDirectiveModule +/// ::= .module oddspreg +/// ::= .module nooddspreg +/// ::= .module fp=value +bool MipsAsmParser::parseDirectiveModule() { + MCAsmLexer &Lexer = getLexer(); + SMLoc L = Lexer.getLoc(); + + if (!getTargetStreamer().getCanHaveModuleDir()) { + // TODO : get a better message. + reportParseError(".module directive must appear before any code"); + return false; + } + + if (Lexer.is(AsmToken::Identifier)) { + StringRef Option = Parser.getTok().getString(); + Parser.Lex(); + + if (Option == "oddspreg") { + getTargetStreamer().emitDirectiveModuleOddSPReg(true, isABI_O32()); + clearFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("Expected end of statement"); + return false; + } + + return false; + } else if (Option == "nooddspreg") { + if (!isABI_O32()) { + Error(L, "'.module nooddspreg' requires the O32 ABI"); + return false; + } + + getTargetStreamer().emitDirectiveModuleOddSPReg(false, isABI_O32()); + setFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("Expected end of statement"); + return false; + } + + return false; + } else if (Option == "fp") { + return parseDirectiveModuleFP(); + } + + return Error(L, "'" + Twine(Option) + "' is not a valid .module option."); + } + + return false; +} + +/// parseDirectiveModuleFP +/// ::= =32 +/// ::= =xx +/// ::= =64 +bool MipsAsmParser::parseDirectiveModuleFP() { + MCAsmLexer &Lexer = getLexer(); + + if (Lexer.isNot(AsmToken::Equal)) { + reportParseError("unexpected token in statement"); + return false; + } + Parser.Lex(); // Eat '=' token. + + MipsABIFlagsSection::FpABIKind FpABI; + if (!parseFpABIValue(FpABI, ".module")) + return false; + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token in statement"); + return false; + } + + // Emit appropriate flags. + getTargetStreamer().emitDirectiveModuleFP(FpABI, isABI_O32()); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI, + StringRef Directive) { + MCAsmLexer &Lexer = getLexer(); + + if (Lexer.is(AsmToken::Identifier)) { + StringRef Value = Parser.getTok().getString(); + Parser.Lex(); + + if (Value != "xx") { + reportParseError("unsupported value, expected 'xx', '32' or '64'"); + return false; + } + + if (!isABI_O32()) { + reportParseError("'" + Directive + " fp=xx' requires the O32 ABI"); + return false; + } + + FpABI = MipsABIFlagsSection::FpABIKind::XX; + return true; + } + + if (Lexer.is(AsmToken::Integer)) { + unsigned Value = Parser.getTok().getIntVal(); + Parser.Lex(); + + if (Value != 32 && Value != 64) { + reportParseError("unsupported value, expected 'xx', '32' or '64'"); + return false; + } + + if (Value == 32) { + if (!isABI_O32()) { + reportParseError("'" + Directive + " fp=32' requires the O32 ABI"); + return false; + } + + FpABI = MipsABIFlagsSection::FpABIKind::S32; + } else + FpABI = MipsABIFlagsSection::FpABIKind::S64; + + return true; + } + + return false; +} + bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { StringRef IDVal = DirectiveID.getString(); @@ -2624,6 +3002,9 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { if (IDVal == ".cpsetup") return parseDirectiveCPSetup(); + if (IDVal == ".module") + return parseDirectiveModule(); + return true; } diff --git a/lib/Target/Mips/Disassembler/MipsDisassembler.cpp b/lib/Target/Mips/Disassembler/MipsDisassembler.cpp index 95670aa..902b877 100644 --- a/lib/Target/Mips/Disassembler/MipsDisassembler.cpp +++ b/lib/Target/Mips/Disassembler/MipsDisassembler.cpp @@ -57,16 +57,24 @@ class MipsDisassembler : public MipsDisassemblerBase { public: /// Constructor - Initializes the disassembler. /// - MipsDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, - bool bigEndian) : - MipsDisassemblerBase(STI, Ctx, bigEndian) { - IsMicroMips = STI.getFeatureBits() & Mips::FeatureMicroMips; - } + MipsDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, bool bigEndian) + : MipsDisassemblerBase(STI, Ctx, bigEndian) { + IsMicroMips = STI.getFeatureBits() & Mips::FeatureMicroMips; + } - bool isMips32r6() const { + bool hasMips3() const { return STI.getFeatureBits() & Mips::FeatureMips3; } + bool hasMips32() const { return STI.getFeatureBits() & Mips::FeatureMips32; } + bool hasMips32r6() const { return STI.getFeatureBits() & Mips::FeatureMips32r6; } + bool isGP64() const { return STI.getFeatureBits() & Mips::FeatureGP64Bit; } + + bool hasCOP3() const { + // Only present in MIPS-I and MIPS-II + return !hasMips32() && !hasMips3(); + } + /// getInstruction - See MCDisassembler. DecodeStatus getInstruction(MCInst &instr, uint64_t &size, @@ -149,6 +157,10 @@ static DecodeStatus DecodeFCCRegisterClass(MCInst &Inst, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeFGRCCRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, + const void *Decoder); + static DecodeStatus DecodeHWRegsRegisterClass(MCInst &Inst, unsigned Insn, uint64_t Address, @@ -260,6 +272,11 @@ static DecodeStatus DecodeFMem(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeSpecial3LlSc(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + static DecodeStatus DecodeSimm16(MCInst &Inst, unsigned Insn, uint64_t Address, @@ -285,6 +302,9 @@ static DecodeStatus DecodeExtSize(MCInst &Inst, static DecodeStatus DecodeSimm19Lsl2(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeSimm18Lsl3(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); + /// INSVE_[BHWD] have an implicit operand that the generated decoder doesn't /// handle. template <typename InsnType> @@ -316,6 +336,11 @@ static DecodeStatus DecodeBgtzGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, const void *Decoder); +template <typename InsnType> +static DecodeStatus +DecodeBlezGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + namespace llvm { extern Target TheMipselTarget, TheMipsTarget, TheMips64Target, TheMips64elTarget; @@ -511,6 +536,7 @@ static DecodeStatus DecodeBlezlGroupBranch(MCInst &MI, InsnType insn, InsnType Rs = fieldFromInstruction(insn, 21, 5); InsnType Rt = fieldFromInstruction(insn, 16, 5); InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) << 2; + bool HasRs = false; if (Rt == 0) return MCDisassembler::Fail; @@ -518,8 +544,14 @@ static DecodeStatus DecodeBlezlGroupBranch(MCInst &MI, InsnType insn, MI.setOpcode(Mips::BLEZC); else if (Rs == Rt) MI.setOpcode(Mips::BGEZC); - else - return MCDisassembler::Fail; // FIXME: BGEC is not implemented yet. + 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))); @@ -544,6 +576,8 @@ static DecodeStatus DecodeBgtzlGroupBranch(MCInst &MI, InsnType insn, // BLTZC if rs == rt && rt != 0 // BLTC if rs != rt && rs != 0 && rt != 0 + bool HasRs = false; + InsnType Rs = fieldFromInstruction(insn, 21, 5); InsnType Rt = fieldFromInstruction(insn, 16, 5); InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) << 2; @@ -554,8 +588,14 @@ static DecodeStatus DecodeBgtzlGroupBranch(MCInst &MI, InsnType insn, MI.setOpcode(Mips::BGTZC); else if (Rs == Rt) MI.setOpcode(Mips::BLTZC); - else - return MCDisassembler::Fail; // FIXME: BLTC is not implemented yet. + 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))); @@ -595,8 +635,11 @@ static DecodeStatus DecodeBgtzGroupBranch(MCInst &MI, InsnType insn, } else if (Rs == Rt) { MI.setOpcode(Mips::BLTZALC); HasRs = true; - } else - return MCDisassembler::Fail; // BLTUC not implemented yet + } else { + MI.setOpcode(Mips::BLTUC); + HasRs = true; + HasRt = true; + } if (HasRs) MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, @@ -611,6 +654,48 @@ static DecodeStatus DecodeBgtzGroupBranch(MCInst &MI, InsnType insn, return MCDisassembler::Success; } +template <typename InsnType> +static DecodeStatus DecodeBlezGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the BLEZL instruction from the earlier + // ISA's instead). + // + // We have: + // 0b000110 sssss ttttt iiiiiiiiiiiiiiii + // Invalid if rs == 0 + // BLEZALC if rs == 0 && rt != 0 + // BGEZALC if rs == rt && rt != 0 + // BGEUC if rs != rt && rs != 0 && rt != 0 + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) << 2; + bool HasRs = false; + + if (Rt == 0) + return MCDisassembler::Fail; + else if (Rs == 0) + MI.setOpcode(Mips::BLEZALC); + else if (Rs == Rt) + MI.setOpcode(Mips::BGEZALC); + else { + HasRs = true; + MI.setOpcode(Mips::BGEUC); + } + + if (HasRs) + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + + MI.addOperand(MCOperand::CreateImm(Imm)); + + return MCDisassembler::Success; +} + /// readInstruction - read four bytes from the MemoryObject /// and return 32 bit word sorted according to the given endianess static DecodeStatus readInstruction32(const MemoryObject ®ion, @@ -670,6 +755,7 @@ MipsDisassembler::getInstruction(MCInst &instr, return MCDisassembler::Fail; if (IsMicroMips) { + DEBUG(dbgs() << "Trying MicroMips32 table (32-bit opcodes):\n"); // Calling the auto-generated decoder function. Result = decodeInstruction(DecoderTableMicroMips32, instr, Insn, Address, this, STI); @@ -680,7 +766,28 @@ MipsDisassembler::getInstruction(MCInst &instr, return MCDisassembler::Fail; } - if (isMips32r6()) { + 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) { @@ -689,6 +796,7 @@ MipsDisassembler::getInstruction(MCInst &instr, } } + DEBUG(dbgs() << "Trying Mips table (32-bit opcodes):\n"); // Calling the auto-generated decoder function. Result = decodeInstruction(DecoderTableMips32, instr, Insn, Address, this, STI); @@ -840,6 +948,17 @@ static DecodeStatus DecodeFCCRegisterClass(MCInst &Inst, return MCDisassembler::Success; } +static DecodeStatus DecodeFGRCCRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::FGRCCRegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + static DecodeStatus DecodeMem(MCInst &Inst, unsigned Insn, uint64_t Address, @@ -965,6 +1084,27 @@ static DecodeStatus DecodeFMem(MCInst &Inst, return MCDisassembler::Success; } +static DecodeStatus DecodeSpecial3LlSc(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int64_t Offset = SignExtend64<9>((Insn >> 7) & 0x1ff); + unsigned Rt = fieldFromInstruction(Insn, 16, 5); + unsigned Base = fieldFromInstruction(Insn, 21, 5); + + Rt = getReg(Decoder, Mips::GPR32RegClassID, Rt); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + if(Inst.getOpcode() == Mips::SC_R6 || Inst.getOpcode() == Mips::SCD_R6){ + Inst.addOperand(MCOperand::CreateReg(Rt)); + } + + Inst.addOperand(MCOperand::CreateReg(Rt)); + Inst.addOperand(MCOperand::CreateReg(Base)); + Inst.addOperand(MCOperand::CreateImm(Offset)); + + return MCDisassembler::Success; +} static DecodeStatus DecodeHWRegsRegisterClass(MCInst &Inst, unsigned RegNo, @@ -1197,3 +1337,9 @@ static DecodeStatus DecodeSimm19Lsl2(MCInst &Inst, unsigned Insn, Inst.addOperand(MCOperand::CreateImm(SignExtend32<19>(Insn) << 2)); return MCDisassembler::Success; } + +static DecodeStatus DecodeSimm18Lsl3(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + Inst.addOperand(MCOperand::CreateImm(SignExtend32<18>(Insn) << 3)); + return MCDisassembler::Success; +} diff --git a/lib/Target/Mips/MCTargetDesc/Android.mk b/lib/Target/Mips/MCTargetDesc/Android.mk index 7ee11a1..c8d18fc 100644 --- a/lib/Target/Mips/MCTargetDesc/Android.mk +++ b/lib/Target/Mips/MCTargetDesc/Android.mk @@ -7,6 +7,7 @@ mips_mc_desc_TBLGEN_TABLES := \ MipsGenSubtargetInfo.inc mips_mc_desc_SRC_FILES := \ + MipsABIFlagsSection.cpp \ MipsAsmBackend.cpp \ MipsELFObjectWriter.cpp \ MipsELFStreamer.cpp \ diff --git a/lib/Target/Mips/MCTargetDesc/CMakeLists.txt b/lib/Target/Mips/MCTargetDesc/CMakeLists.txt index d3e2fd7..c14ee35 100644 --- a/lib/Target/Mips/MCTargetDesc/CMakeLists.txt +++ b/lib/Target/Mips/MCTargetDesc/CMakeLists.txt @@ -1,4 +1,5 @@ add_llvm_library(LLVMMipsDesc + MipsABIFlagsSection.cpp MipsAsmBackend.cpp MipsELFObjectWriter.cpp MipsELFStreamer.cpp diff --git a/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.cpp b/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.cpp new file mode 100644 index 0000000..52d5dd3 --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.cpp @@ -0,0 +1,60 @@ +//===-- MipsABIFlagsSection.cpp - Mips ELF ABI Flags Section ---*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsABIFlagsSection.h" + +using namespace llvm; + +uint8_t MipsABIFlagsSection::getFpABIValue() { + switch (FpABI) { + case FpABIKind::ANY: + return Val_GNU_MIPS_ABI_FP_ANY; + case FpABIKind::XX: + return Val_GNU_MIPS_ABI_FP_XX; + case FpABIKind::S32: + return Val_GNU_MIPS_ABI_FP_DOUBLE; + case FpABIKind::S64: + if (Is32BitABI) + return OddSPReg ? Val_GNU_MIPS_ABI_FP_64 : Val_GNU_MIPS_ABI_FP_64A; + return Val_GNU_MIPS_ABI_FP_DOUBLE; + } + + llvm_unreachable("unexpected fp abi value"); +} + +StringRef MipsABIFlagsSection::getFpABIString(FpABIKind Value) { + switch (Value) { + case FpABIKind::XX: + return "xx"; + case FpABIKind::S32: + return "32"; + case FpABIKind::S64: + return "64"; + default: + llvm_unreachable("unsupported fp abi value"); + } +} + +namespace llvm { +MCStreamer &operator<<(MCStreamer &OS, MipsABIFlagsSection &ABIFlagsSection) { + // Write out a Elf_Internal_ABIFlags_v0 struct + OS.EmitIntValue(ABIFlagsSection.getVersionValue(), 2); // version + OS.EmitIntValue(ABIFlagsSection.getISALevelValue(), 1); // isa_level + OS.EmitIntValue(ABIFlagsSection.getISARevisionValue(), 1); // isa_rev + OS.EmitIntValue(ABIFlagsSection.getGPRSizeValue(), 1); // gpr_size + OS.EmitIntValue(ABIFlagsSection.getCPR1SizeValue(), 1); // cpr1_size + OS.EmitIntValue(ABIFlagsSection.getCPR2SizeValue(), 1); // cpr2_size + OS.EmitIntValue(ABIFlagsSection.getFpABIValue(), 1); // fp_abi + OS.EmitIntValue(ABIFlagsSection.getISAExtensionSetValue(), 4); // isa_ext + OS.EmitIntValue(ABIFlagsSection.getASESetValue(), 4); // ases + OS.EmitIntValue(ABIFlagsSection.getFlags1Value(), 4); // flags1 + OS.EmitIntValue(ABIFlagsSection.getFlags2Value(), 4); // flags2 + return OS; +} +} diff --git a/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h b/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h new file mode 100644 index 0000000..ab18c44 --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h @@ -0,0 +1,237 @@ +//===-- MipsABIFlagsSection.h - Mips ELF ABI Flags Section -----*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSABIFLAGSSECTION_H +#define MIPSABIFLAGSSECTION_H + +#include "llvm/MC/MCStreamer.h" + +namespace llvm { + +class MCStreamer; + +struct MipsABIFlagsSection { + // Values for the xxx_size bytes of an ABI flags structure. + enum AFL_REG { + AFL_REG_NONE = 0x00, // No registers. + AFL_REG_32 = 0x01, // 32-bit registers. + AFL_REG_64 = 0x02, // 64-bit registers. + AFL_REG_128 = 0x03 // 128-bit registers. + }; + + // Masks for the ases word of an ABI flags structure. + enum AFL_ASE { + AFL_ASE_DSP = 0x00000001, // DSP ASE. + AFL_ASE_DSPR2 = 0x00000002, // DSP R2 ASE. + AFL_ASE_EVA = 0x00000004, // Enhanced VA Scheme. + AFL_ASE_MCU = 0x00000008, // MCU (MicroController) ASE. + AFL_ASE_MDMX = 0x00000010, // MDMX ASE. + AFL_ASE_MIPS3D = 0x00000020, // MIPS-3D ASE. + AFL_ASE_MT = 0x00000040, // MT ASE. + AFL_ASE_SMARTMIPS = 0x00000080, // SmartMIPS ASE. + AFL_ASE_VIRT = 0x00000100, // VZ ASE. + AFL_ASE_MSA = 0x00000200, // MSA ASE. + AFL_ASE_MIPS16 = 0x00000400, // MIPS16 ASE. + AFL_ASE_MICROMIPS = 0x00000800, // MICROMIPS ASE. + AFL_ASE_XPA = 0x00001000 // XPA ASE. + }; + + // Values for the isa_ext word of an ABI flags structure. + enum AFL_EXT { + AFL_EXT_XLR = 1, // RMI Xlr instruction. + AFL_EXT_OCTEON2 = 2, // Cavium Networks Octeon2. + AFL_EXT_OCTEONP = 3, // Cavium Networks OcteonP. + AFL_EXT_LOONGSON_3A = 4, // Loongson 3A. + AFL_EXT_OCTEON = 5, // Cavium Networks Octeon. + AFL_EXT_5900 = 6, // MIPS R5900 instruction. + AFL_EXT_4650 = 7, // MIPS R4650 instruction. + AFL_EXT_4010 = 8, // LSI R4010 instruction. + AFL_EXT_4100 = 9, // NEC VR4100 instruction. + AFL_EXT_3900 = 10, // Toshiba R3900 instruction. + AFL_EXT_10000 = 11, // MIPS R10000 instruction. + AFL_EXT_SB1 = 12, // Broadcom SB-1 instruction. + AFL_EXT_4111 = 13, // NEC VR4111/VR4181 instruction. + AFL_EXT_4120 = 14, // NEC VR4120 instruction. + AFL_EXT_5400 = 15, // NEC VR5400 instruction. + AFL_EXT_5500 = 16, // NEC VR5500 instruction. + AFL_EXT_LOONGSON_2E = 17, // ST Microelectronics Loongson 2E. + AFL_EXT_LOONGSON_2F = 18 // ST Microelectronics Loongson 2F. + }; + + // Values for the fp_abi word of an ABI flags structure. + enum Val_GNU_MIPS_ABI { + Val_GNU_MIPS_ABI_FP_ANY = 0, + Val_GNU_MIPS_ABI_FP_DOUBLE = 1, + Val_GNU_MIPS_ABI_FP_XX = 5, + Val_GNU_MIPS_ABI_FP_64 = 6, + Val_GNU_MIPS_ABI_FP_64A = 7 + }; + + enum AFL_FLAGS1 { + AFL_FLAGS1_ODDSPREG = 1 + }; + + // Internal representation of the values used in .module fp=value + enum class FpABIKind { ANY, XX, S32, S64 }; + + // Version of flags structure. + uint16_t Version; + // The level of the ISA: 1-5, 32, 64. + uint8_t ISALevel; + // The revision of ISA: 0 for MIPS V and below, 1-n otherwise. + uint8_t ISARevision; + // The size of general purpose registers. + AFL_REG GPRSize; + // The size of co-processor 1 registers. + AFL_REG CPR1Size; + // The size of co-processor 2 registers. + AFL_REG CPR2Size; + // Processor-specific extension. + uint32_t ISAExtensionSet; + // Mask of ASEs used. + uint32_t ASESet; + + bool OddSPReg; + + bool Is32BitABI; + +protected: + // The floating-point ABI. + FpABIKind FpABI; + +public: + MipsABIFlagsSection() + : Version(0), ISALevel(0), ISARevision(0), GPRSize(AFL_REG_NONE), + CPR1Size(AFL_REG_NONE), CPR2Size(AFL_REG_NONE), ISAExtensionSet(0), + ASESet(0), OddSPReg(false), Is32BitABI(false), FpABI(FpABIKind::ANY) {} + + uint16_t getVersionValue() { return (uint16_t)Version; } + uint8_t getISALevelValue() { return (uint8_t)ISALevel; } + uint8_t getISARevisionValue() { return (uint8_t)ISARevision; } + uint8_t getGPRSizeValue() { return (uint8_t)GPRSize; } + uint8_t getCPR1SizeValue() { return (uint8_t)CPR1Size; } + uint8_t getCPR2SizeValue() { return (uint8_t)CPR2Size; } + uint8_t getFpABIValue(); + uint32_t getISAExtensionSetValue() { return (uint32_t)ISAExtensionSet; } + uint32_t getASESetValue() { return (uint32_t)ASESet; } + + uint32_t getFlags1Value() { + uint32_t Value = 0; + + if (OddSPReg) + Value |= (uint32_t)AFL_FLAGS1_ODDSPREG; + + return Value; + } + + uint32_t getFlags2Value() { return 0; } + + FpABIKind getFpABI() { return FpABI; } + void setFpABI(FpABIKind Value, bool IsABI32Bit) { + FpABI = Value; + Is32BitABI = IsABI32Bit; + } + StringRef getFpABIString(FpABIKind Value); + + template <class PredicateLibrary> + void setISALevelAndRevisionFromPredicates(const PredicateLibrary &P) { + if (P.hasMips64()) { + ISALevel = 64; + if (P.hasMips64r6()) + ISARevision = 6; + else if (P.hasMips64r2()) + ISARevision = 2; + else + ISARevision = 1; + } else if (P.hasMips32()) { + ISALevel = 32; + if (P.hasMips32r6()) + ISARevision = 6; + else if (P.hasMips32r2()) + ISARevision = 2; + else + ISARevision = 1; + } else { + ISARevision = 0; + if (P.hasMips5()) + ISALevel = 5; + else if (P.hasMips4()) + ISALevel = 4; + else if (P.hasMips3()) + ISALevel = 3; + else if (P.hasMips2()) + ISALevel = 2; + else if (P.hasMips1()) + ISALevel = 1; + else + llvm_unreachable("Unknown ISA level!"); + } + } + + template <class PredicateLibrary> + void setGPRSizeFromPredicates(const PredicateLibrary &P) { + GPRSize = P.isGP64bit() ? AFL_REG_64 : AFL_REG_32; + } + + template <class PredicateLibrary> + void setCPR1SizeFromPredicates(const PredicateLibrary &P) { + if (P.mipsSEUsesSoftFloat()) + CPR1Size = AFL_REG_NONE; + else if (P.hasMSA()) + CPR1Size = AFL_REG_128; + else + CPR1Size = P.isFP64bit() ? AFL_REG_64 : AFL_REG_32; + } + + template <class PredicateLibrary> + void setASESetFromPredicates(const PredicateLibrary &P) { + ASESet = 0; + if (P.hasDSP()) + ASESet |= AFL_ASE_DSP; + if (P.hasDSPR2()) + ASESet |= AFL_ASE_DSPR2; + if (P.hasMSA()) + ASESet |= AFL_ASE_MSA; + if (P.inMicroMipsMode()) + ASESet |= AFL_ASE_MICROMIPS; + if (P.inMips16Mode()) + ASESet |= AFL_ASE_MIPS16; + } + + template <class PredicateLibrary> + void setFpAbiFromPredicates(const PredicateLibrary &P) { + Is32BitABI = P.isABI_O32(); + + FpABI = FpABIKind::ANY; + if (P.isABI_N32() || P.isABI_N64()) + FpABI = FpABIKind::S64; + else if (P.isABI_O32()) { + if (P.isFP64bit()) + FpABI = FpABIKind::S64; + else if (P.isABI_FPXX()) + FpABI = FpABIKind::XX; + else + FpABI = FpABIKind::S32; + } + } + + template <class PredicateLibrary> + void setAllFromPredicates(const PredicateLibrary &P) { + setISALevelAndRevisionFromPredicates(P); + setGPRSizeFromPredicates(P); + setCPR1SizeFromPredicates(P); + setASESetFromPredicates(P); + setFpAbiFromPredicates(P); + } +}; + +MCStreamer &operator<<(MCStreamer &OS, MipsABIFlagsSection &ABIFlagsSection); +} + +#endif diff --git a/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp index 5375a00..d8e6128 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp @@ -70,6 +70,13 @@ static unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value, if (!isIntN(16, Value) && Ctx) Ctx->FatalError(Fixup.getLoc(), "out of range PC16 fixup"); break; + case Mips::fixup_MIPS_PC19_S2: + // Forcing a signed division because Value can be negative. + Value = (int64_t)Value / 4; + // We now check if Value can be encoded as a 19-bit signed immediate. + if (!isIntN(19, Value) && Ctx) + Ctx->FatalError(Fixup.getLoc(), "out of range PC19 fixup"); + break; case Mips::fixup_Mips_26: // So far we are only using this type for jumps. // The displacement is then divided by 4 to give us an 28 bit @@ -104,6 +111,13 @@ static unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value, if (!isIntN(16, Value) && Ctx) Ctx->FatalError(Fixup.getLoc(), "out of range PC16 fixup"); break; + case Mips::fixup_MIPS_PC18_S3: + // Forcing a signed division because Value can be negative. + Value = (int64_t)Value / 8; + // We now check if Value can be encoded as a 18-bit signed immediate. + if (!isIntN(18, Value) && Ctx) + Ctx->FatalError(Fixup.getLoc(), "out of range PC18 fixup"); + break; case Mips::fixup_MIPS_PC21_S2: Value -= 4; // Forcing a signed division because Value can be negative. @@ -247,6 +261,8 @@ getFixupKindInfo(MCFixupKind Kind) const { { "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 }, @@ -308,6 +324,8 @@ getFixupKindInfo(MCFixupKind Kind) const { { "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 }, diff --git a/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h b/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h index bc695e6..d5c3dbc 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h +++ b/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h @@ -65,7 +65,7 @@ public: const MCRelaxableFragment *DF, const MCAsmLayout &Layout) const override { // FIXME. - assert(0 && "RelaxInstruction() unimplemented"); + llvm_unreachable("RelaxInstruction() unimplemented"); return false; } diff --git a/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp b/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp index 74c12ff..49ac256 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp @@ -193,6 +193,12 @@ unsigned MipsELFObjectWriter::GetRelocType(const MCValue &Target, case Mips::fixup_MICROMIPS_TLS_TPREL_LO16: Type = ELF::R_MICROMIPS_TLS_TPREL_LO16; break; + case Mips::fixup_MIPS_PC19_S2: + Type = ELF::R_MIPS_PC19_S2; + break; + case Mips::fixup_MIPS_PC18_S3: + Type = ELF::R_MIPS_PC18_S3; + break; case Mips::fixup_MIPS_PC21_S2: Type = ELF::R_MIPS_PC21_S2; break; diff --git a/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h b/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h index 3079004..05080f0 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h +++ b/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h @@ -128,6 +128,12 @@ namespace Mips { // resulting in - R_MIPS_CALL_LO16 fixup_Mips_CALL_LO16, + // resulting in - R_MIPS_PC18_S3 + fixup_MIPS_PC18_S3, + + // resulting in - R_MIPS_PC19_S2 + fixup_MIPS_PC19_S2, + // resulting in - R_MIPS_PC21_S2 fixup_MIPS_PC21_S2, diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp index 6aa3c76..e415412 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp @@ -38,7 +38,7 @@ MipsMCAsmInfo::MipsMCAsmInfo(StringRef TT) { ZeroDirective = "\t.space\t"; GPRel32Directive = "\t.gpword\t"; GPRel64Directive = "\t.gpdword\t"; - DebugLabelSuffix = "=."; + UseAssignmentForEHBegin = true; SupportsDebugInformation = true; ExceptionsType = ExceptionHandling::DwarfCFI; HasLEB128 = true; diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp index 85e0bf1..43fc521 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -621,11 +621,42 @@ unsigned MipsMCCodeEmitter::getSimm19Lsl2Encoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { - assert(MI.getOperand(OpNo).isImm()); - // The immediate is encoded as 'immediate << 2'. - unsigned Res = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI); - assert((Res & 3) == 0); - return Res >> 2; + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isImm()) { + // The immediate is encoded as 'immediate << 2'. + unsigned Res = getMachineOpValue(MI, MO, Fixups, STI); + assert((Res & 3) == 0); + return Res >> 2; + } + + assert(MO.isExpr() && + "getSimm19Lsl2Encoding expects only expressions or an immediate"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::Create(0, Expr, + MCFixupKind(Mips::fixup_MIPS_PC19_S2))); + return 0; +} + +unsigned +MipsMCCodeEmitter::getSimm18Lsl3Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isImm()) { + // The immediate is encoded as 'immediate << 3'. + unsigned Res = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI); + assert((Res & 7) == 0); + return Res >> 3; + } + + assert(MO.isExpr() && + "getSimm18Lsl2Encoding expects only expressions or an immediate"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::Create(0, Expr, + MCFixupKind(Mips::fixup_MIPS_PC18_S3))); + return 0; } #include "MipsGenMCCodeEmitter.inc" diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h b/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h index 3f7daab..304167f 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h +++ b/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h @@ -141,6 +141,10 @@ public: SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const; + unsigned getSimm18Lsl3Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getExprOpValue(const MCExpr *Expr, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const; diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp index 21ccc3c..5bba3e5 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp @@ -11,6 +11,7 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectStreamer.h" using namespace llvm; @@ -83,33 +84,6 @@ MipsMCExpr::EvaluateAsRelocatableImpl(MCValue &Res, return getSubExpr()->EvaluateAsRelocatable(Res, Layout); } -// FIXME: This basically copies MCObjectStreamer::AddValueSymbols. Perhaps -// that method should be made public? -static void AddValueSymbolsImpl(const MCExpr *Value, MCAssembler *Asm) { - switch (Value->getKind()) { - case MCExpr::Target: - llvm_unreachable("Can't handle nested target expr!"); - - case MCExpr::Constant: - break; - - case MCExpr::Binary: { - const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value); - AddValueSymbolsImpl(BE->getLHS(), Asm); - AddValueSymbolsImpl(BE->getRHS(), Asm); - break; - } - - case MCExpr::SymbolRef: - Asm->getOrCreateSymbolData(cast<MCSymbolRefExpr>(Value)->getSymbol()); - break; - - case MCExpr::Unary: - AddValueSymbolsImpl(cast<MCUnaryExpr>(Value)->getSubExpr(), Asm); - break; - } -} - -void MipsMCExpr::AddValueSymbols(MCAssembler *Asm) const { - AddValueSymbolsImpl(getSubExpr(), Asm); +void MipsMCExpr::visitUsedExpr(MCStreamer &Streamer) const { + Streamer.visitUsedExpr(*getSubExpr()); } diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h b/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h index 8d7aacd..f193dc9 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h +++ b/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h @@ -49,7 +49,7 @@ public: void PrintImpl(raw_ostream &OS) const override; bool EvaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout) const override; - void AddValueSymbols(MCAssembler *) const override; + void visitUsedExpr(MCStreamer &Streamer) const override; const MCSection *FindAssociatedSection() const override { return getSubExpr()->FindAssociatedSection(); } diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp index 660e5a7..d2b929b 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp @@ -133,6 +133,12 @@ createMCAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS, return S; } +static MCStreamer *createMipsNullStreamer(MCContext &Ctx) { + MCStreamer *S = llvm::createNullStreamer(Ctx); + new MipsTargetStreamer(*S); + return S; +} + extern "C" void LLVMInitializeMipsTargetMC() { // Register the MC asm info. RegisterMCAsmInfoFn X(TheMipsTarget, createMipsMCAsmInfo); @@ -187,6 +193,12 @@ extern "C" void LLVMInitializeMipsTargetMC() { TargetRegistry::RegisterAsmStreamer(TheMips64Target, createMCAsmStreamer); TargetRegistry::RegisterAsmStreamer(TheMips64elTarget, createMCAsmStreamer); + TargetRegistry::RegisterNullStreamer(TheMipsTarget, createMipsNullStreamer); + TargetRegistry::RegisterNullStreamer(TheMipselTarget, createMipsNullStreamer); + TargetRegistry::RegisterNullStreamer(TheMips64Target, createMipsNullStreamer); + TargetRegistry::RegisterNullStreamer(TheMips64elTarget, + createMipsNullStreamer); + // Register the asm backend. TargetRegistry::RegisterMCAsmBackend(TheMipsTarget, createMipsAsmBackendEB32); diff --git a/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp b/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp index cd6be73..6cde8f9 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp @@ -48,7 +48,13 @@ private: bool PendingCall; bool isIndirectJump(const MCInst &MI) { - return MI.getOpcode() == Mips::JR || MI.getOpcode() == Mips::RET; + 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) { @@ -56,7 +62,9 @@ private: && MI.getOperand(0).getReg() == Mips::SP); } - bool isCall(unsigned Opcode, bool *IsIndirectCall) { + bool isCall(const MCInst &MI, bool *IsIndirectCall) { + unsigned Opcode = MI.getOpcode(); + *IsIndirectCall = false; switch (Opcode) { @@ -64,12 +72,19 @@ private: 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; } @@ -137,24 +152,23 @@ public: &IsStore); bool IsSPFirstOperand = isStackPointerFirstOperand(Inst); if (IsMemAccess || IsSPFirstOperand) { - if (PendingCall) - report_fatal_error("Dangerous instruction in branch delay slot!"); - bool MaskBefore = (IsMemAccess && baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx) .getReg())); bool MaskAfter = IsSPFirstOperand && !IsStore; - if (MaskBefore || MaskAfter) + if (MaskBefore || MaskAfter) { + if (PendingCall) + report_fatal_error("Dangerous instruction in branch delay slot!"); sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter); - else - MipsELFStreamer::EmitInstruction(Inst, STI); - return; + 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.getOpcode(), &IsIndirectCall)) { + if (isCall(Inst, &IsIndirectCall)) { if (PendingCall) report_fatal_error("Dangerous instruction in branch delay slot!"); @@ -203,6 +217,7 @@ bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx, case Mips::LWC1: case Mips::LDC1: case Mips::LL: + case Mips::LL_R6: case Mips::LWL: case Mips::LWR: *AddrIdx = 1; @@ -223,6 +238,7 @@ bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx, // Store instructions with base address register in position 2. case Mips::SC: + case Mips::SC_R6: *AddrIdx = 2; if (IsStore) *IsStore = true; diff --git a/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp b/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp index a8fa272..fbe375b 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -27,10 +27,43 @@ using namespace llvm; -// Pin vtable to this file. -void MipsTargetStreamer::anchor() {} - -MipsTargetStreamer::MipsTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {} +MipsTargetStreamer::MipsTargetStreamer(MCStreamer &S) + : MCTargetStreamer(S), canHaveModuleDirective(true) {} +void MipsTargetStreamer::emitDirectiveSetMicroMips() {} +void MipsTargetStreamer::emitDirectiveSetNoMicroMips() {} +void MipsTargetStreamer::emitDirectiveSetMips16() {} +void MipsTargetStreamer::emitDirectiveSetNoMips16() {} +void MipsTargetStreamer::emitDirectiveSetReorder() {} +void MipsTargetStreamer::emitDirectiveSetNoReorder() {} +void MipsTargetStreamer::emitDirectiveSetMacro() {} +void MipsTargetStreamer::emitDirectiveSetNoMacro() {} +void MipsTargetStreamer::emitDirectiveSetAt() {} +void MipsTargetStreamer::emitDirectiveSetNoAt() {} +void MipsTargetStreamer::emitDirectiveEnd(StringRef Name) {} +void MipsTargetStreamer::emitDirectiveEnt(const MCSymbol &Symbol) {} +void MipsTargetStreamer::emitDirectiveAbiCalls() {} +void MipsTargetStreamer::emitDirectiveNaN2008() {} +void MipsTargetStreamer::emitDirectiveNaNLegacy() {} +void MipsTargetStreamer::emitDirectiveOptionPic0() {} +void MipsTargetStreamer::emitDirectiveOptionPic2() {} +void MipsTargetStreamer::emitFrame(unsigned StackReg, unsigned StackSize, + unsigned ReturnReg) {} +void MipsTargetStreamer::emitMask(unsigned CPUBitmask, int CPUTopSavedRegOff) {} +void MipsTargetStreamer::emitFMask(unsigned FPUBitmask, int FPUTopSavedRegOff) { +} +void MipsTargetStreamer::emitDirectiveSetMips32R2() {} +void MipsTargetStreamer::emitDirectiveSetMips64() {} +void MipsTargetStreamer::emitDirectiveSetMips64R2() {} +void MipsTargetStreamer::emitDirectiveSetDsp() {} +void MipsTargetStreamer::emitDirectiveCpload(unsigned RegNo) {} +void MipsTargetStreamer::emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, + const MCSymbol &Sym, bool IsReg) { +} +void MipsTargetStreamer::emitDirectiveModuleOddSPReg(bool Enabled, + bool IsO32ABI) { + if (!Enabled && !IsO32ABI) + report_fatal_error("+nooddspreg is only valid for O32"); +} MipsTargetAsmStreamer::MipsTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS) @@ -38,42 +71,52 @@ MipsTargetAsmStreamer::MipsTargetAsmStreamer(MCStreamer &S, void MipsTargetAsmStreamer::emitDirectiveSetMicroMips() { OS << "\t.set\tmicromips\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetNoMicroMips() { OS << "\t.set\tnomicromips\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetMips16() { OS << "\t.set\tmips16\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetNoMips16() { OS << "\t.set\tnomips16\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetReorder() { OS << "\t.set\treorder\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetNoReorder() { OS << "\t.set\tnoreorder\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetMacro() { OS << "\t.set\tmacro\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetNoMacro() { OS << "\t.set\tnomacro\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetAt() { OS << "\t.set\tat\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetNoAt() { OS << "\t.set\tnoat\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveEnd(StringRef Name) { @@ -110,24 +153,28 @@ void MipsTargetAsmStreamer::emitFrame(unsigned StackReg, unsigned StackSize, void MipsTargetAsmStreamer::emitDirectiveSetMips32R2() { OS << "\t.set\tmips32r2\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetMips64() { OS << "\t.set\tmips64\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetMips64R2() { OS << "\t.set\tmips64r2\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetDsp() { OS << "\t.set\tdsp\n"; + setCanHaveModuleDir(false); } // Print a 32 bit hex number with all numbers. static void printHex32(unsigned Value, raw_ostream &OS) { OS << "0x"; for (int i = 7; i >= 0; i--) - OS.write_hex((Value & (0xF << (i*4))) >> (i*4)); + OS.write_hex((Value & (0xF << (i * 4))) >> (i * 4)); } void MipsTargetAsmStreamer::emitMask(unsigned CPUBitmask, @@ -147,6 +194,7 @@ void MipsTargetAsmStreamer::emitFMask(unsigned FPUBitmask, void MipsTargetAsmStreamer::emitDirectiveCpload(unsigned RegNo) { OS << "\t.cpload\t$" << StringRef(MipsInstPrinter::getRegisterName(RegNo)).lower() << "\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveCpsetup(unsigned RegNo, @@ -165,6 +213,34 @@ void MipsTargetAsmStreamer::emitDirectiveCpsetup(unsigned RegNo, OS << ", "; OS << Sym.getName() << "\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveModuleFP( + MipsABIFlagsSection::FpABIKind Value, bool Is32BitABI) { + MipsTargetStreamer::emitDirectiveModuleFP(Value, Is32BitABI); + + StringRef ModuleValue; + OS << "\t.module\tfp="; + OS << ABIFlagsSection.getFpABIString(Value) << "\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveSetFp( + MipsABIFlagsSection::FpABIKind Value) { + StringRef ModuleValue; + OS << "\t.set\tfp="; + OS << ABIFlagsSection.getFpABIString(Value) << "\n"; +} + +void MipsTargetAsmStreamer::emitMipsAbiFlags() { + // No action required for text output. +} + +void MipsTargetAsmStreamer::emitDirectiveModuleOddSPReg(bool Enabled, + bool IsO32ABI) { + MipsTargetStreamer::emitDirectiveModuleOddSPReg(Enabled, IsO32ABI); + + OS << "\t.module\t" << (Enabled ? "" : "no") << "oddspreg\n"; } // This part is for ELF object output. @@ -174,7 +250,7 @@ MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S, MCAssembler &MCA = getStreamer().getAssembler(); uint64_t Features = STI.getFeatureBits(); Triple T(STI.getTargetTriple()); - Pic = (MCA.getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_) + Pic = (MCA.getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_) ? true : false; @@ -182,16 +258,28 @@ MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S, unsigned EFlags = 0; // Architecture - if (Features & Mips::FeatureMips64r2) + if (Features & Mips::FeatureMips64r6) + EFlags |= ELF::EF_MIPS_ARCH_64R6; + else if (Features & Mips::FeatureMips64r2) EFlags |= ELF::EF_MIPS_ARCH_64R2; else if (Features & Mips::FeatureMips64) EFlags |= ELF::EF_MIPS_ARCH_64; + else if (Features & Mips::FeatureMips5) + EFlags |= ELF::EF_MIPS_ARCH_5; else if (Features & Mips::FeatureMips4) EFlags |= ELF::EF_MIPS_ARCH_4; + else if (Features & Mips::FeatureMips3) + EFlags |= ELF::EF_MIPS_ARCH_3; + else if (Features & Mips::FeatureMips32r6) + EFlags |= ELF::EF_MIPS_ARCH_32R6; else if (Features & Mips::FeatureMips32r2) EFlags |= ELF::EF_MIPS_ARCH_32R2; else if (Features & Mips::FeatureMips32) EFlags |= ELF::EF_MIPS_ARCH_32; + else if (Features & Mips::FeatureMips2) + EFlags |= ELF::EF_MIPS_ARCH_2; + else + EFlags |= ELF::EF_MIPS_ARCH_1; if (T.isArch64Bit()) { if (Features & Mips::FeatureN32) @@ -244,17 +332,17 @@ void MipsTargetELFStreamer::finish() { ELF::SHF_ALLOC | ELF::SHF_MIPS_NOSTRIP, SectionKind::getMetadata()); OS.SwitchSection(Sec); - OS.EmitIntValue(1, 1); // kind + OS.EmitIntValue(1, 1); // kind OS.EmitIntValue(40, 1); // size - OS.EmitIntValue(0, 2); // section - OS.EmitIntValue(0, 4); // info - OS.EmitIntValue(0, 4); // ri_gprmask - OS.EmitIntValue(0, 4); // pad - OS.EmitIntValue(0, 4); // ri_cpr[0]mask - OS.EmitIntValue(0, 4); // ri_cpr[1]mask - OS.EmitIntValue(0, 4); // ri_cpr[2]mask - OS.EmitIntValue(0, 4); // ri_cpr[3]mask - OS.EmitIntValue(0, 8); // ri_gp_value + OS.EmitIntValue(0, 2); // section + OS.EmitIntValue(0, 4); // info + OS.EmitIntValue(0, 4); // ri_gprmask + OS.EmitIntValue(0, 4); // pad + OS.EmitIntValue(0, 4); // ri_cpr[0]mask + OS.EmitIntValue(0, 4); // ri_cpr[1]mask + OS.EmitIntValue(0, 4); // ri_cpr[2]mask + OS.EmitIntValue(0, 4); // ri_cpr[3]mask + OS.EmitIntValue(0, 8); // ri_gp_value } else { const MCSectionELF *Sec = Context.getELFSection(".reginfo", ELF::SHT_MIPS_REGINFO, ELF::SHF_ALLOC, @@ -268,6 +356,7 @@ void MipsTargetELFStreamer::finish() { OS.EmitIntValue(0, 4); // ri_cpr[3]mask OS.EmitIntValue(0, 4); // ri_gp_value } + emitMipsAbiFlags(); } void MipsTargetELFStreamer::emitAssignment(MCSymbol *Symbol, @@ -276,11 +365,11 @@ void MipsTargetELFStreamer::emitAssignment(MCSymbol *Symbol, if (Value->getKind() != MCExpr::SymbolRef) return; const MCSymbol &RhsSym = - static_cast<const MCSymbolRefExpr *>(Value)->getSymbol(); + static_cast<const MCSymbolRefExpr *>(Value)->getSymbol(); MCSymbolData &Data = getStreamer().getOrCreateSymbolData(&RhsSym); uint8_t Type = MCELF::GetType(Data); - if ((Type != ELF::STT_FUNC) - || !(MCELF::getOther(Data) & (ELF::STO_MIPS_MICROMIPS >> 2))) + if ((Type != ELF::STT_FUNC) || + !(MCELF::getOther(Data) & (ELF::STO_MIPS_MICROMIPS >> 2))) return; MCSymbolData &SymbolData = getStreamer().getOrCreateSymbolData(Symbol); @@ -305,6 +394,7 @@ void MipsTargetELFStreamer::emitDirectiveSetMicroMips() { void MipsTargetELFStreamer::emitDirectiveSetNoMicroMips() { MicroMipsEnabled = false; + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetMips16() { @@ -312,14 +402,17 @@ void MipsTargetELFStreamer::emitDirectiveSetMips16() { unsigned Flags = MCA.getELFHeaderEFlags(); Flags |= ELF::EF_MIPS_ARCH_ASE_M16; MCA.setELFHeaderEFlags(Flags); + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetNoMips16() { // FIXME: implement. + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetReorder() { // FIXME: implement. + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetNoReorder() { @@ -327,22 +420,27 @@ void MipsTargetELFStreamer::emitDirectiveSetNoReorder() { unsigned Flags = MCA.getELFHeaderEFlags(); Flags |= ELF::EF_MIPS_NOREORDER; MCA.setELFHeaderEFlags(Flags); + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetMacro() { // FIXME: implement. + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetNoMacro() { // FIXME: implement. + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetAt() { // FIXME: implement. + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetNoAt() { // FIXME: implement. + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveEnd(StringRef Name) { @@ -411,19 +509,19 @@ void MipsTargetELFStreamer::emitFMask(unsigned FPUBitmask, } void MipsTargetELFStreamer::emitDirectiveSetMips32R2() { - // No action required for ELF output. + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetMips64() { - // No action required for ELF output. + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetMips64R2() { - // No action required for ELF output. + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetDsp() { - // No action required for ELF output. + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveCpload(unsigned RegNo) { @@ -473,6 +571,8 @@ void MipsTargetELFStreamer::emitDirectiveCpload(unsigned RegNo) { TmpInst.addOperand(MCOperand::CreateReg(Mips::GP)); TmpInst.addOperand(MCOperand::CreateReg(RegNo)); getStreamer().EmitInstruction(TmpInst, STI); + + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo, @@ -528,4 +628,27 @@ void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo, Inst.addOperand(MCOperand::CreateReg(Mips::GP)); Inst.addOperand(MCOperand::CreateReg(RegNo)); getStreamer().EmitInstruction(Inst, STI); + + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitMipsAbiFlags() { + MCAssembler &MCA = getStreamer().getAssembler(); + MCContext &Context = MCA.getContext(); + MCStreamer &OS = getStreamer(); + const MCSectionELF *Sec = + Context.getELFSection(".MIPS.abiflags", ELF::SHT_MIPS_ABIFLAGS, + ELF::SHF_ALLOC, SectionKind::getMetadata()); + MCSectionData &ABIShndxSD = MCA.getOrCreateSectionData(*Sec); + ABIShndxSD.setAlignment(8); + OS.SwitchSection(Sec); + + OS << ABIFlagsSection; +} + +void MipsTargetELFStreamer::emitDirectiveModuleOddSPReg(bool Enabled, + bool IsO32ABI) { + MipsTargetStreamer::emitDirectiveModuleOddSPReg(Enabled, IsO32ABI); + + ABIFlagsSection.OddSPReg = Enabled; } diff --git a/lib/Target/Mips/MicroMipsInstrFPU.td b/lib/Target/Mips/MicroMipsInstrFPU.td index d95f9b0..b93017a 100644 --- a/lib/Target/Mips/MicroMipsInstrFPU.td +++ b/lib/Target/Mips/MicroMipsInstrFPU.td @@ -24,13 +24,13 @@ 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>; + 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>; + 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; + 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; + 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>; @@ -38,9 +38,9 @@ def FCMP_D32_MM : MMRel, CEQS_FT<"d", AFGR64, II_C_CC_D, MipsFPCmp>, CEQS_FM_MM<1>; def BC1F_MM : MMRel, BC1F_FT<"bc1f", brtarget_mm, IIBranch, MIPS_BRANCH_F>, - BC1F_FM_MM<0x1c>; + BC1F_FM_MM<0x1c>, ISA_MIPS1_NOT_32R6_64R6; def BC1T_MM : MMRel, BC1F_FT<"bc1t", brtarget_mm, IIBranch, MIPS_BRANCH_T>, - BC1F_FM_MM<0x1d>; + BC1F_FM_MM<0x1d>, ISA_MIPS1_NOT_32R6_64R6; def CEIL_W_S_MM : MMRel, ABSS_FT<"ceil.w.s", FGR32Opnd, FGR32Opnd, II_CEIL>, ROUND_W_FM_MM<0, 0x6c>; diff --git a/lib/Target/Mips/MicroMipsInstrInfo.td b/lib/Target/Mips/MicroMipsInstrInfo.td index 9904bc6..87a3a3e 100644 --- a/lib/Target/Mips/MicroMipsInstrInfo.td +++ b/lib/Target/Mips/MicroMipsInstrInfo.td @@ -246,7 +246,6 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in { } def JR_MM : MMRel, IndirectBranch<"jr", GPR32Opnd>, JR_FM_MM<0x3c>; def JALR_MM : JumpLinkReg<"jalr", GPR32Opnd>, JALR_FM_MM<0x03c>; - def RET_MM : MMRel, RetBase<"ret", GPR32Opnd>, JR_FM_MM<0x3c>; /// Branch Instructions def BEQ_MM : MMRel, CBranch<"beq", brtarget_mm, seteq, GPR32Opnd>, diff --git a/lib/Target/Mips/Mips.td b/lib/Target/Mips/Mips.td index ea16331..dd3bc9b 100644 --- a/lib/Target/Mips/Mips.td +++ b/lib/Target/Mips/Mips.td @@ -61,6 +61,8 @@ 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", @@ -73,6 +75,9 @@ def FeatureN64 : SubtargetFeature<"n64", "MipsABI", "N64", "Enable n64 ABI">; def FeatureEABI : SubtargetFeature<"eabi", "MipsABI", "EABI", "Enable eabi ABI">; +def FeatureNoOddSPReg : SubtargetFeature<"nooddspreg", "UseOddSPReg", "false", + "Disable odd numbered single-precision " + "registers">; def FeatureVFPU : SubtargetFeature<"vfpu", "HasVFPU", "true", "Enable vector FPU instructions.">; def FeatureMips1 : SubtargetFeature<"mips1", "MipsArchVersion", "Mips1", diff --git a/lib/Target/Mips/Mips16FrameLowering.cpp b/lib/Target/Mips/Mips16FrameLowering.cpp index c01d03a..93706c2 100644 --- a/lib/Target/Mips/Mips16FrameLowering.cpp +++ b/lib/Target/Mips/Mips16FrameLowering.cpp @@ -16,6 +16,7 @@ #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" @@ -28,6 +29,9 @@ using namespace llvm; +Mips16FrameLowering::Mips16FrameLowering(const MipsSubtarget &STI) + : MipsFrameLowering(STI, STI.stackAlignment()) {} + void Mips16FrameLowering::emitPrologue(MachineFunction &MF) const { MachineBasicBlock &MBB = MF.front(); MachineFrameInfo *MFI = MF.getFrameInfo(); diff --git a/lib/Target/Mips/Mips16FrameLowering.h b/lib/Target/Mips/Mips16FrameLowering.h index 3f7829d..1fb7eda 100644 --- a/lib/Target/Mips/Mips16FrameLowering.h +++ b/lib/Target/Mips/Mips16FrameLowering.h @@ -19,8 +19,7 @@ namespace llvm { class Mips16FrameLowering : public MipsFrameLowering { public: - explicit Mips16FrameLowering(const MipsSubtarget &STI) - : MipsFrameLowering(STI, STI.stackAlignment()) {} + explicit Mips16FrameLowering(const MipsSubtarget &STI); /// emitProlog/emitEpilog - These methods insert prolog and epilog code into /// the function. diff --git a/lib/Target/Mips/Mips16ISelDAGToDAG.cpp b/lib/Target/Mips/Mips16ISelDAGToDAG.cpp index 4e86a27..6672aef 100644 --- a/lib/Target/Mips/Mips16ISelDAGToDAG.cpp +++ b/lib/Target/Mips/Mips16ISelDAGToDAG.cpp @@ -37,7 +37,7 @@ using namespace llvm; #define DEBUG_TYPE "mips-isel" bool Mips16DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { - if (!Subtarget.inMips16Mode()) + if (!Subtarget->inMips16Mode()) return false; return MipsDAGToDAGISel::runOnMachineFunction(MF); } @@ -226,9 +226,9 @@ bool Mips16DAGToDAGISel::selectAddr16( const LSBaseSDNode *LS = dyn_cast<LSBaseSDNode>(Parent); if (LS) { - if (LS->getMemoryVT() == MVT::f32 && Subtarget.hasMips4_32r2()) + if (LS->getMemoryVT() == MVT::f32 && Subtarget->hasMips4_32r2()) return false; - if (LS->getMemoryVT() == MVT::f64 && Subtarget.hasMips4_32r2()) + if (LS->getMemoryVT() == MVT::f64 && Subtarget->hasMips4_32r2()) return false; } } diff --git a/lib/Target/Mips/Mips16ISelLowering.cpp b/lib/Target/Mips/Mips16ISelLowering.cpp index 9102450..81a05df 100644 --- a/lib/Target/Mips/Mips16ISelLowering.cpp +++ b/lib/Target/Mips/Mips16ISelLowering.cpp @@ -120,13 +120,6 @@ static const Mips16IntrinsicHelperType Mips16IntrinsicHelper[] = { Mips16TargetLowering::Mips16TargetLowering(MipsTargetMachine &TM) : MipsTargetLowering(TM) { - // - // set up as if mips32 and then revert so we can test the mechanism - // for switching - addRegisterClass(MVT::i32, &Mips::GPR32RegClass); - addRegisterClass(MVT::f32, &Mips::FGR32RegClass); - computeRegisterProperties(); - clearRegisterClasses(); // Set up the register classes addRegisterClass(MVT::i32, &Mips::CPU16RegsRegClass); diff --git a/lib/Target/Mips/Mips16ISelLowering.h b/lib/Target/Mips/Mips16ISelLowering.h index df88333..2a5eec5 100644 --- a/lib/Target/Mips/Mips16ISelLowering.h +++ b/lib/Target/Mips/Mips16ISelLowering.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef Mips16ISELLOWERING_H -#define Mips16ISELLOWERING_H +#ifndef MIPS16ISELLOWERING_H +#define MIPS16ISELLOWERING_H #include "MipsISelLowering.h" diff --git a/lib/Target/Mips/Mips16InstrInfo.td b/lib/Target/Mips/Mips16InstrInfo.td index 11166c4..5e4eebb 100644 --- a/lib/Target/Mips/Mips16InstrInfo.td +++ b/lib/Target/Mips/Mips16InstrInfo.td @@ -1370,9 +1370,11 @@ def : Mips16Pat<(MipsJmpLink (i32 texternalsym:$dst)), (Jal16 texternalsym:$dst)>; // Indirect branch -def: Mips16Pat< - (brind CPU16Regs:$rs), - (JrcRx16 CPU16Regs:$rs)>; +def: Mips16Pat<(brind CPU16Regs:$rs), (JrcRx16 CPU16Regs:$rs)> { + // Ensure that the addition of MIPS32r6/MIPS64r6 support does not change + // MIPS16's behaviour. + let AddedComplexity = 1; +} // Jump and Link (Call) let isCall=1, hasDelaySlot=0 in diff --git a/lib/Target/Mips/Mips32r6InstrFormats.td b/lib/Target/Mips/Mips32r6InstrFormats.td index a3f9df5..e4ec96a 100644 --- a/lib/Target/Mips/Mips32r6InstrFormats.td +++ b/lib/Target/Mips/Mips32r6InstrFormats.td @@ -39,7 +39,10 @@ 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; @@ -48,6 +51,11 @@ 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; } @@ -59,6 +67,13 @@ 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; @@ -67,6 +82,22 @@ 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; @@ -77,22 +108,23 @@ def FIELD_FMT_D : FIELD_FMT<0b10001>; class FIELD_CMP_COND<bits<5> Val> { bits<5> Value = Val; } -def FIELD_CMP_COND_F : FIELD_CMP_COND<0b00000>; +// 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_OLT : FIELD_CMP_COND<0b00100>; +def FIELD_CMP_COND_LT : FIELD_CMP_COND<0b00100>; def FIELD_CMP_COND_ULT : FIELD_CMP_COND<0b00101>; -def FIELD_CMP_COND_OLE : FIELD_CMP_COND<0b00110>; +def FIELD_CMP_COND_LE : FIELD_CMP_COND<0b00110>; def FIELD_CMP_COND_ULE : FIELD_CMP_COND<0b00111>; -def FIELD_CMP_COND_SF : FIELD_CMP_COND<0b01000>; -def FIELD_CMP_COND_NGLE : FIELD_CMP_COND<0b01001>; +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_NGL : FIELD_CMP_COND<0b01011>; -def FIELD_CMP_COND_LT : FIELD_CMP_COND<0b01100>; -def FIELD_CMP_COND_NGE : FIELD_CMP_COND<0b01101>; -def FIELD_CMP_COND_LE : FIELD_CMP_COND<0b01110>; -def FIELD_CMP_COND_NGT : FIELD_CMP_COND<0b01111>; +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; @@ -139,6 +171,17 @@ 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; @@ -216,6 +259,18 @@ class PCREL19_FM<OPCODE2 Operation> : MipsR6Inst { 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; @@ -230,6 +285,36 @@ class SPECIAL3_2R_FM<OPCODE6 Operation> : MipsR6Inst { 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; @@ -245,6 +330,16 @@ class SPECIAL_3R_FM<bits<5> mulop, bits<6> funct> : MipsR6Inst { 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 { @@ -355,6 +450,40 @@ class SPECIAL3_DALIGN_FM<OPCODE6 Operation> : MipsR6Inst { 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; @@ -384,3 +513,31 @@ class COP1_CMP_CONDN_FM<FIELD_CMP_FORMAT Format, let Inst{4-0} = Cond.Value; } +class JR_HB_R6_FM<OPCODE6 Operation> : MipsR6Inst { + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_SPECIAL.Value; + let Inst{25-21} = rs; + let Inst{20-16} = 0; + let Inst{15-11} = 0; + let Inst{10} = 1; + let Inst{9-6} = 0; + let Inst{5-0} = Operation.Value; +} + +class COP2LDST_FM<OPCODE5 Operation> : MipsR6Inst { + bits<5> rt; + bits<21> addr; + bits<5> base = addr{20-16}; + bits<11> offset = addr{10-0}; + + bits<32> Inst; + + let Inst{31-26} = OPGROUP_COP2LDST.Value; + let Inst{25-21} = Operation.Value; + let Inst{20-16} = rt; + let Inst{15-11} = base; + let Inst{10-0} = offset; +} diff --git a/lib/Target/Mips/Mips32r6InstrInfo.td b/lib/Target/Mips/Mips32r6InstrInfo.td index ffaf965..d06e5ca 100644 --- a/lib/Target/Mips/Mips32r6InstrInfo.td +++ b/lib/Target/Mips/Mips32r6InstrInfo.td @@ -14,39 +14,8 @@ include "Mips32r6InstrFormats.td" // Notes about removals/changes from MIPS32r6: -// Unclear: ssnop -// Reencoded: cache, pref -// Reencoded: clo, clz // Reencoded: jr -> jalr // Reencoded: jr.hb -> jalr.hb -// Reencoded: ldc2 -// Reencoded: ll, sc -// Reencoded: lwc2 -// Reencoded: sdbbp -// Reencoded: sdc2 -// Reencoded: swc2 -// Removed: bc1any2, bc1any4 -// Removed: bc2[ft] -// Removed: bc2f, bc2t -// Removed: bgezal -// Removed: bltzal -// Removed: c.cond.fmt, bc1[ft] -// Removed: div, divu -// Removed: jalx -// Removed: ldxc1 -// Removed: luxc1 -// Removed: lwxc1 -// Removed: madd.[ds], nmadd.[ds], nmsub.[ds], sub.[ds] -// Removed: mfhi, mflo, mthi, mtlo, madd, maddu, msub, msubu, mul -// Removed: movf, movt -// Removed: movf.fmt, movt.fmt, movn.fmt, movz.fmt -// Removed: movn, movz -// Removed: mult, multu -// Removed: prefx -// Removed: sdxc1 -// Removed: suxc1 -// Removed: swxc1 -// Rencoded: [ls][wd]c2 def brtarget21 : Operand<OtherVT> { let EncoderMethod = "getBranchTarget21OpValue"; @@ -84,6 +53,7 @@ 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>, @@ -97,11 +67,20 @@ class BNEZALC_ENC : CMP_BRANCH_1R_RT_OFF16_FM<OPGROUP_DADDI>, 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>, @@ -110,7 +89,8 @@ 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>; +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>; @@ -120,9 +100,10 @@ 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>; +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>, @@ -170,12 +151,23 @@ 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 CMP_CONDN_DESC_BASE<string CondStr, string Typestr, RegisterOperand FGROpnd> { - dag OutOperandList = (outs FGROpnd:$fd); - dag InOperandList = (ins FGROpnd:$fs, FGROpnd:$ft); - string AsmString = !strconcat("cmp.", CondStr, ".", Typestr, "\t$fd, $fs, $ft"); - list<dag> Pattern = []; -} +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; //===----------------------------------------------------------------------===// // @@ -183,56 +175,65 @@ class CMP_CONDN_DESC_BASE<string CondStr, string Typestr, RegisterOperand FGROpn // //===----------------------------------------------------------------------===// +class CMP_CONDN_DESC_BASE<string CondStr, string Typestr, + RegisterOperand FGROpnd, + SDPatternOperator Op = null_frag> { + dag OutOperandList = (outs FGRCCOpnd:$fd); + dag InOperandList = (ins FGROpnd:$fs, FGROpnd:$ft); + string AsmString = !strconcat("cmp.", CondStr, ".", Typestr, "\t$fd, $fs, $ft"); + list<dag> Pattern = [(set FGRCCOpnd:$fd, (Op FGROpnd:$fs, FGROpnd:$ft))]; +} + multiclass CMP_CC_M <FIELD_CMP_FORMAT Format, string Typestr, RegisterOperand FGROpnd>{ - def CMP_F_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_F>, - CMP_CONDN_DESC_BASE<"f", Typestr, FGROpnd>, + def CMP_F_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_AF>, + CMP_CONDN_DESC_BASE<"af", Typestr, FGROpnd>, ISA_MIPS32R6; def CMP_UN_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_UN>, - CMP_CONDN_DESC_BASE<"un", Typestr, FGROpnd>, + CMP_CONDN_DESC_BASE<"un", Typestr, FGROpnd, setuo>, ISA_MIPS32R6; def CMP_EQ_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_EQ>, - CMP_CONDN_DESC_BASE<"eq", Typestr, FGROpnd>, + CMP_CONDN_DESC_BASE<"eq", Typestr, FGROpnd, setoeq>, ISA_MIPS32R6; def CMP_UEQ_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_UEQ>, - CMP_CONDN_DESC_BASE<"ueq", Typestr, FGROpnd>, - ISA_MIPS32R6; - def CMP_OLT_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_OLT>, - CMP_CONDN_DESC_BASE<"olt", Typestr, FGROpnd>, + CMP_CONDN_DESC_BASE<"ueq", Typestr, FGROpnd, setueq>, ISA_MIPS32R6; + def CMP_LT_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_LT>, + CMP_CONDN_DESC_BASE<"lt", Typestr, FGROpnd, setolt>, + ISA_MIPS32R6; def CMP_ULT_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_ULT>, - CMP_CONDN_DESC_BASE<"ult", Typestr, FGROpnd>, - ISA_MIPS32R6; - def CMP_OLE_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_OLE>, - CMP_CONDN_DESC_BASE<"ole", Typestr, FGROpnd>, + CMP_CONDN_DESC_BASE<"ult", Typestr, FGROpnd, setult>, ISA_MIPS32R6; + def CMP_LE_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_LE>, + CMP_CONDN_DESC_BASE<"le", Typestr, FGROpnd, setole>, + ISA_MIPS32R6; def CMP_ULE_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_ULE>, - CMP_CONDN_DESC_BASE<"ule", Typestr, FGROpnd>, + CMP_CONDN_DESC_BASE<"ule", Typestr, FGROpnd, setule>, + ISA_MIPS32R6; + def CMP_SAF_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SAF>, + CMP_CONDN_DESC_BASE<"saf", Typestr, FGROpnd>, + ISA_MIPS32R6; + def CMP_SUN_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SUN>, + CMP_CONDN_DESC_BASE<"sun", Typestr, FGROpnd>, ISA_MIPS32R6; - def CMP_SF_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SF>, - CMP_CONDN_DESC_BASE<"sf", Typestr, FGROpnd>, - ISA_MIPS32R6; - def CMP_NGLE_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_NGLE>, - CMP_CONDN_DESC_BASE<"ngle", Typestr, FGROpnd>, - ISA_MIPS32R6; def CMP_SEQ_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SEQ>, CMP_CONDN_DESC_BASE<"seq", Typestr, FGROpnd>, ISA_MIPS32R6; - def CMP_NGL_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_NGL>, - CMP_CONDN_DESC_BASE<"ngl", Typestr, FGROpnd>, - ISA_MIPS32R6; - def CMP_LT_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_LT>, - CMP_CONDN_DESC_BASE<"lt", Typestr, FGROpnd>, - ISA_MIPS32R6; - def CMP_NGE_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_NGE>, - CMP_CONDN_DESC_BASE<"nge", Typestr, FGROpnd>, + def CMP_SUEQ_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SUEQ>, + CMP_CONDN_DESC_BASE<"sueq", Typestr, FGROpnd>, + ISA_MIPS32R6; + def CMP_SLT_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SLT>, + CMP_CONDN_DESC_BASE<"slt", Typestr, FGROpnd>, ISA_MIPS32R6; - def CMP_LE_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_LE>, - CMP_CONDN_DESC_BASE<"le", Typestr, FGROpnd>, - ISA_MIPS32R6; - def CMP_NGT_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_NGT>, - CMP_CONDN_DESC_BASE<"ngt", Typestr, FGROpnd>, + def CMP_SULT_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SULT>, + CMP_CONDN_DESC_BASE<"sult", Typestr, FGROpnd>, + ISA_MIPS32R6; + def CMP_SLE_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SLE>, + CMP_CONDN_DESC_BASE<"sle", Typestr, FGROpnd>, ISA_MIPS32R6; + def CMP_SULE_#NAME : COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_SULE>, + CMP_CONDN_DESC_BASE<"sule", Typestr, FGROpnd>, + ISA_MIPS32R6; } //===----------------------------------------------------------------------===// @@ -241,16 +242,17 @@ multiclass CMP_CC_M <FIELD_CMP_FORMAT Format, string Typestr, // //===----------------------------------------------------------------------===// -class PCREL19_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { +class PCREL_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + Operand ImmOpnd> { dag OutOperandList = (outs GPROpnd:$rs); - dag InOperandList = (ins simm19_lsl2:$imm); + dag InOperandList = (ins ImmOpnd:$imm); string AsmString = !strconcat(instr_asm, "\t$rs, $imm"); list<dag> Pattern = []; } -class ADDIUPC_DESC : PCREL19_DESC_BASE<"addiupc", GPR32Opnd>; -class LWPC_DESC: PCREL19_DESC_BASE<"lwpc", GPR32Opnd>; -class LWUPC_DESC: PCREL19_DESC_BASE<"lwupc", GPR32Opnd>; +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> { @@ -318,15 +320,26 @@ class CMP_CBR_RT_Z_DESC_BASE<string instr_asm, DAGOperand opnd, 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>; @@ -380,6 +393,14 @@ class JIC_DESC : JMP_IDX_COMPACT_DESC_BASE<"jic", jmpoffset16, GPR32Opnd> { list<Register> Defs = [AT]; } +class JR_HB_R6_DESC : JR_HB_DESC_BASE<"jr.hb", GPR32Opnd> { + bit isBranch = 1; + bit isIndirectBranch = 1; + bit hasDelaySlot = 1; + bit isTerminator=1; + bit isBarrier=1; +} + class BITSWAP_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { dag OutOperandList = (outs GPROpnd:$rd); dag InOperandList = (ins GPROpnd:$rt); @@ -389,17 +410,22 @@ class BITSWAP_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { class BITSWAP_DESC : BITSWAP_DESC_BASE<"bitswap", GPR32Opnd>; -class DIVMOD_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { +class DIVMOD_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + SDPatternOperator Op=null_frag> { dag OutOperandList = (outs GPROpnd:$rd); dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt); string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt"); - list<dag> Pattern = []; + 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>; -class DIVU_DESC : DIVMOD_DESC_BASE<"divu", GPR32Opnd>; -class MOD_DESC : DIVMOD_DESC_BASE<"mod", GPR32Opnd>; -class MODU_DESC : DIVMOD_DESC_BASE<"modu", GPR32Opnd>; +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]; @@ -424,28 +450,35 @@ class BLTZALC_DESC : CMP_CBR_RT_Z_DESC_BASE<"bltzalc", brtarget, GPR32Opnd> { 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> { + +class MUL_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + SDPatternOperator Op=null_frag> { dag OutOperandList = (outs GPROpnd:$rd); dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt); string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt"); - list<dag> Pattern = []; + list<dag> Pattern = [(set GPROpnd:$rd, (Op GPROpnd:$rs, GPROpnd:$rt))]; } -class MUH_DESC : MUL_R6_DESC_BASE<"muh", GPR32Opnd>; -class MUHU_DESC : MUL_R6_DESC_BASE<"muhu", GPR32Opnd>; -class MUL_R6_DESC : MUL_R6_DESC_BASE<"mul", GPR32Opnd>; +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_4R_DESC_BASE<string instr_asm, RegisterOperand FGROpnd> { +class COP1_SEL_DESC_BASE<string instr_asm, RegisterOperand FGROpnd> { dag OutOperandList = (outs FGROpnd:$fd); - dag InOperandList = (ins FGROpnd:$fd_in, FGROpnd:$fs, FGROpnd:$ft); + dag InOperandList = (ins FGRCCOpnd:$fd_in, FGROpnd:$fs, FGROpnd:$ft); string AsmString = !strconcat(instr_asm, "\t$fd, $fs, $ft"); - list<dag> Pattern = []; + list<dag> Pattern = [(set FGROpnd:$fd, (select FGRCCOpnd:$fd_in, + FGROpnd:$ft, + FGROpnd:$fs))]; string Constraints = "$fd_in = $fd"; } -class SEL_D_DESC : COP1_4R_DESC_BASE<"sel.d", FGR64Opnd>; -class SEL_S_DESC : COP1_4R_DESC_BASE<"sel.s", FGR32Opnd>; +class SEL_D_DESC : COP1_SEL_DESC_BASE<"sel.d", FGR64Opnd> { + // We must insert a SUBREG_TO_REG around $fd_in + bit usesCustomInserter = 1; +} +class SEL_S_DESC : COP1_SEL_DESC_BASE<"sel.s", FGR32Opnd>; class SELEQNE_Z_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { dag OutOperandList = (outs GPROpnd:$rd); @@ -457,6 +490,14 @@ class SELEQNE_Z_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { 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>; @@ -503,6 +544,96 @@ class RINT_D_DESC : CLASS_RINT_DESC_BASE<"rint.d", FGR64Opnd>; class CLASS_S_DESC : CLASS_RINT_DESC_BASE<"class.s", FGR32Opnd>; class CLASS_D_DESC : CLASS_RINT_DESC_BASE<"class.d", FGR64Opnd>; +class CACHE_HINT_DESC<string instr_asm, Operand MemOpnd, + RegisterOperand GPROpnd> { + dag OutOperandList = (outs); + dag InOperandList = (ins MemOpnd:$addr, uimm5:$hint); + string AsmString = !strconcat(instr_asm, "\t$hint, $addr"); + list<dag> Pattern = []; +} + +class CACHE_DESC : CACHE_HINT_DESC<"cache", mem_simm9, GPR32Opnd>; +class PREF_DESC : CACHE_HINT_DESC<"pref", mem_simm9, GPR32Opnd>; + +class COP2LD_DESC_BASE<string instr_asm, RegisterOperand COPOpnd> { + dag OutOperandList = (outs COPOpnd:$rt); + dag InOperandList = (ins mem_simm11:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + bit mayLoad = 1; +} + +class LDC2_R6_DESC : COP2LD_DESC_BASE<"ldc2", COP2Opnd>; +class LWC2_R6_DESC : COP2LD_DESC_BASE<"lwc2", COP2Opnd>; + +class COP2ST_DESC_BASE<string instr_asm, RegisterOperand COPOpnd> { + dag OutOperandList = (outs); + dag InOperandList = (ins COPOpnd:$rt, mem_simm11:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + bit mayStore = 1; +} + +class SDC2_R6_DESC : COP2ST_DESC_BASE<"sdc2", COP2Opnd>; +class SWC2_R6_DESC : COP2ST_DESC_BASE<"swc2", COP2Opnd>; + +class LSA_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, + Operand ImmOpnd> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, ImmOpnd:$imm2); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt, $imm2"); + list<dag> Pattern = []; +} + +class LSA_R6_DESC : LSA_R6_DESC_BASE<"lsa", GPR32Opnd, uimm2>; + +class LL_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$rt); + dag InOperandList = (ins mem_simm9:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + bit mayLoad = 1; +} + +class LL_R6_DESC : LL_R6_DESC_BASE<"ll", GPR32Opnd>; + +class SC_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$dst); + dag InOperandList = (ins GPROpnd:$rt, mem_simm9:$addr); + string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); + list<dag> Pattern = []; + bit mayStore = 1; + string Constraints = "$rt = $dst"; +} + +class SC_R6_DESC : SC_R6_DESC_BASE<"sc", GPR32Opnd>; + +class CLO_CLZ_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs"); +} + +class CLO_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> : + CLO_CLZ_R6_DESC_BASE<instr_asm, GPROpnd> { + list<dag> Pattern = [(set GPROpnd:$rd, (ctlz (not GPROpnd:$rs)))]; +} + +class CLZ_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> : + CLO_CLZ_R6_DESC_BASE<instr_asm, GPROpnd> { + list<dag> Pattern = [(set GPROpnd:$rd, (ctlz GPROpnd:$rs))]; +} + +class CLO_R6_DESC : CLO_R6_DESC_BASE<"clo", GPR32Opnd>; +class CLZ_R6_DESC : CLZ_R6_DESC_BASE<"clz", GPR32Opnd>; + +class SDBBP_R6_DESC { + dag OutOperandList = (outs); + dag InOperandList = (ins uimm20:$code_); + string AsmString = "sdbbp\t$code_"; + list<dag> Pattern = []; +} + //===----------------------------------------------------------------------===// // // Instruction Definitions @@ -514,6 +645,7 @@ def ALIGN : ALIGN_ENC, ALIGN_DESC, ISA_MIPS32R6; def ALUIPC : ALUIPC_ENC, ALUIPC_DESC, ISA_MIPS32R6; def AUI : AUI_ENC, AUI_DESC, ISA_MIPS32R6; def AUIPC : AUIPC_ENC, AUIPC_DESC, ISA_MIPS32R6; +def BAL : BAL_ENC, BAL_DESC, ISA_MIPS32R6; def BALC : BALC_ENC, BALC_DESC, ISA_MIPS32R6; def BC1EQZ : BC1EQZ_ENC, BC1EQZ_DESC, ISA_MIPS32R6; def BC1NEZ : BC1NEZ_ENC, BC1NEZ_DESC, ISA_MIPS32R6; @@ -523,8 +655,8 @@ def BC : BC_ENC, BC_DESC, ISA_MIPS32R6; def BEQC : BEQC_ENC, BEQC_DESC, ISA_MIPS32R6; def BEQZALC : BEQZALC_ENC, BEQZALC_DESC, ISA_MIPS32R6; def BEQZC : BEQZC_ENC, BEQZC_DESC, ISA_MIPS32R6; -def BGEC; // Also aliased to blec with operands swapped -def BGEUC; // Also aliased to bleuc with operands swapped +def BGEC : BGEC_ENC, BGEC_DESC, ISA_MIPS32R6; +def BGEUC : BGEUC_ENC, BGEUC_DESC, ISA_MIPS32R6; def BGEZALC : BGEZALC_ENC, BGEZALC_DESC, ISA_MIPS32R6; def BGEZC : BGEZC_ENC, BGEZC_DESC, ISA_MIPS32R6; def BGTZALC : BGTZALC_ENC, BGTZALC_DESC, ISA_MIPS32R6; @@ -532,8 +664,8 @@ def BGTZC : BGTZC_ENC, BGTZC_DESC, ISA_MIPS32R6; def BITSWAP : BITSWAP_ENC, BITSWAP_DESC, ISA_MIPS32R6; def BLEZALC : BLEZALC_ENC, BLEZALC_DESC, ISA_MIPS32R6; def BLEZC : BLEZC_ENC, BLEZC_DESC, ISA_MIPS32R6; -def BLTC; // Also aliased to bgtc with operands swapped -def BLTUC; // Also aliased to bgtuc with operands swapped +def BLTC : BLTC_ENC, BLTC_DESC, ISA_MIPS32R6; +def BLTUC : BLTUC_ENC, BLTUC_DESC, ISA_MIPS32R6; def BLTZALC : BLTZALC_ENC, BLTZALC_DESC, ISA_MIPS32R6; def BLTZC : BLTZC_ENC, BLTZC_DESC, ISA_MIPS32R6; def BNEC : BNEC_ENC, BNEC_DESC, ISA_MIPS32R6; @@ -541,15 +673,22 @@ def BNEZALC : BNEZALC_ENC, BNEZALC_DESC, ISA_MIPS32R6; def BNEZC : BNEZC_ENC, BNEZC_DESC, ISA_MIPS32R6; def BNVC : BNVC_ENC, BNVC_DESC, ISA_MIPS32R6; def BOVC : BOVC_ENC, BOVC_DESC, ISA_MIPS32R6; +def CACHE_R6 : CACHE_ENC, CACHE_DESC, ISA_MIPS32R6; def CLASS_D : CLASS_D_ENC, CLASS_D_DESC, ISA_MIPS32R6; def CLASS_S : CLASS_S_ENC, CLASS_S_DESC, ISA_MIPS32R6; +def CLO_R6 : CLO_R6_ENC, CLO_R6_DESC, ISA_MIPS32R6; +def CLZ_R6 : CLZ_R6_ENC, CLZ_R6_DESC, ISA_MIPS32R6; defm S : CMP_CC_M<FIELD_CMP_FORMAT_S, "s", FGR32Opnd>; defm D : CMP_CC_M<FIELD_CMP_FORMAT_D, "d", FGR64Opnd>; def DIV : DIV_ENC, DIV_DESC, ISA_MIPS32R6; def DIVU : DIVU_ENC, DIVU_DESC, ISA_MIPS32R6; def JIALC : JIALC_ENC, JIALC_DESC, ISA_MIPS32R6; def JIC : JIC_ENC, JIC_DESC, ISA_MIPS32R6; -// def LSA; // See MSA +def JR_HB_R6 : JR_HB_R6_ENC, JR_HB_R6_DESC, ISA_MIPS32R6; +def LDC2_R6 : LDC2_R6_ENC, LDC2_R6_DESC, ISA_MIPS32R6; +def LL_R6 : LL_R6_ENC, LL_R6_DESC, ISA_MIPS32R6; +def LSA_R6 : LSA_R6_ENC, LSA_R6_DESC, ISA_MIPS32R6; +def LWC2_R6 : LWC2_R6_ENC, LWC2_R6_DESC, ISA_MIPS32R6; def LWPC : LWPC_ENC, LWPC_DESC, ISA_MIPS32R6; def LWUPC : LWUPC_ENC, LWUPC_DESC, ISA_MIPS32R6; def MADDF_S : MADDF_S_ENC, MADDF_S_DESC, ISA_MIPS32R6; @@ -571,13 +710,115 @@ def MUHU : MUHU_ENC, MUHU_DESC, ISA_MIPS32R6; def MUL_R6 : MUL_R6_ENC, MUL_R6_DESC, ISA_MIPS32R6; def MULU : MULU_ENC, MULU_DESC, ISA_MIPS32R6; def NAL; // BAL with rd=0 +def PREF_R6 : PREF_ENC, PREF_DESC, ISA_MIPS32R6; def RINT_D : RINT_D_ENC, RINT_D_DESC, ISA_MIPS32R6; def RINT_S : RINT_S_ENC, RINT_S_DESC, ISA_MIPS32R6; -def SELEQZ : SELEQZ_ENC, SELEQZ_DESC, ISA_MIPS32R6; +def SC_R6 : SC_R6_ENC, SC_R6_DESC, ISA_MIPS32R6; +def SDBBP_R6 : SDBBP_R6_ENC, SDBBP_R6_DESC, ISA_MIPS32R6; +def SDC2_R6 : SDC2_R6_ENC, SDC2_R6_DESC, ISA_MIPS32R6; +def SELEQZ : SELEQZ_ENC, SELEQZ_DESC, ISA_MIPS32R6, GPR_32; def SELEQZ_D : SELEQZ_D_ENC, SELEQZ_D_DESC, ISA_MIPS32R6; def SELEQZ_S : SELEQZ_S_ENC, SELEQZ_S_DESC, ISA_MIPS32R6; -def SELNEZ : SELNEZ_ENC, SELNEZ_DESC, ISA_MIPS32R6; +def SELNEZ : SELNEZ_ENC, SELNEZ_DESC, ISA_MIPS32R6, GPR_32; def SELNEZ_D : SELNEZ_D_ENC, SELNEZ_D_DESC, ISA_MIPS32R6; def SELNEZ_S : SELNEZ_S_ENC, SELNEZ_S_DESC, ISA_MIPS32R6; def SEL_D : SEL_D_ENC, SEL_D_DESC, ISA_MIPS32R6; def SEL_S : SEL_S_ENC, SEL_S_DESC, ISA_MIPS32R6; +def SWC2_R6 : SWC2_R6_ENC, SWC2_R6_DESC, ISA_MIPS32R6; + +//===----------------------------------------------------------------------===// +// +// Instruction Aliases +// +//===----------------------------------------------------------------------===// + +def : MipsInstAlias<"sdbbp", (SDBBP_R6 0)>, ISA_MIPS32R6; +def : MipsInstAlias<"jr $rs", (JALR ZERO, GPR32Opnd:$rs), 1>, ISA_MIPS32R6; + +//===----------------------------------------------------------------------===// +// +// Patterns and Pseudo Instructions +// +//===----------------------------------------------------------------------===// + +// f32 comparisons supported via another comparison +def : MipsPat<(setone f32:$lhs, f32:$rhs), + (NOR (CMP_UEQ_S f32:$lhs, f32:$rhs), ZERO)>, ISA_MIPS32R6; +def : MipsPat<(seto f32:$lhs, f32:$rhs), + (NOR (CMP_UN_S f32:$lhs, f32:$rhs), ZERO)>, ISA_MIPS32R6; +def : MipsPat<(setune f32:$lhs, f32:$rhs), + (NOR (CMP_EQ_S f32:$lhs, f32:$rhs), ZERO)>, ISA_MIPS32R6; +def : MipsPat<(seteq f32:$lhs, f32:$rhs), (CMP_EQ_S f32:$lhs, f32:$rhs)>, + ISA_MIPS32R6; +def : MipsPat<(setgt f32:$lhs, f32:$rhs), (CMP_LE_S f32:$rhs, f32:$lhs)>, + ISA_MIPS32R6; +def : MipsPat<(setge f32:$lhs, f32:$rhs), (CMP_LT_S f32:$rhs, f32:$lhs)>, + ISA_MIPS32R6; +def : MipsPat<(setlt f32:$lhs, f32:$rhs), (CMP_LT_S f32:$lhs, f32:$rhs)>, + ISA_MIPS32R6; +def : MipsPat<(setlt f32:$lhs, f32:$rhs), (CMP_LE_S f32:$lhs, f32:$rhs)>, + ISA_MIPS32R6; +def : MipsPat<(setne f32:$lhs, f32:$rhs), + (NOR (CMP_EQ_S f32:$lhs, f32:$rhs), ZERO)>, ISA_MIPS32R6; + +// f64 comparisons supported via another comparison +def : MipsPat<(setone f64:$lhs, f64:$rhs), + (NOR (CMP_UEQ_D f64:$lhs, f64:$rhs), ZERO)>, ISA_MIPS32R6; +def : MipsPat<(seto f64:$lhs, f64:$rhs), + (NOR (CMP_UN_D f64:$lhs, f64:$rhs), ZERO)>, ISA_MIPS32R6; +def : MipsPat<(setune f64:$lhs, f64:$rhs), + (NOR (CMP_EQ_D f64:$lhs, f64:$rhs), ZERO)>, ISA_MIPS32R6; +def : MipsPat<(seteq f64:$lhs, f64:$rhs), (CMP_EQ_D f64:$lhs, f64:$rhs)>, + ISA_MIPS32R6; +def : MipsPat<(setgt f64:$lhs, f64:$rhs), (CMP_LE_D f64:$rhs, f64:$lhs)>, + ISA_MIPS32R6; +def : MipsPat<(setge f64:$lhs, f64:$rhs), (CMP_LT_D f64:$rhs, f64:$lhs)>, + ISA_MIPS32R6; +def : MipsPat<(setlt f64:$lhs, f64:$rhs), (CMP_LT_D f64:$lhs, f64:$rhs)>, + ISA_MIPS32R6; +def : MipsPat<(setlt f64:$lhs, f64:$rhs), (CMP_LE_D f64:$lhs, f64:$rhs)>, + ISA_MIPS32R6; +def : MipsPat<(setne f64:$lhs, f64:$rhs), + (NOR (CMP_EQ_D f64:$lhs, f64:$rhs), ZERO)>, ISA_MIPS32R6; + +// i32 selects +def : MipsPat<(select i32:$cond, i32:$t, i32:$f), + (OR (SELNEZ i32:$t, i32:$cond), (SELEQZ i32:$f, i32:$cond))>, + ISA_MIPS32R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immz)), i32:$t, i32:$f), + (OR (SELEQZ i32:$t, i32:$cond), (SELNEZ i32:$f, i32:$cond))>, + ISA_MIPS32R6; +def : MipsPat<(select (i32 (setne i32:$cond, immz)), i32:$t, i32:$f), + (OR (SELNEZ i32:$t, i32:$cond), (SELEQZ i32:$f, i32:$cond))>, + ISA_MIPS32R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immZExt16:$imm)), i32:$t, i32:$f), + (OR (SELEQZ i32:$t, (XORi i32:$cond, immZExt16:$imm)), + (SELNEZ i32:$f, (XORi i32:$cond, immZExt16:$imm)))>, + ISA_MIPS32R6; +def : MipsPat<(select (i32 (setne i32:$cond, immZExt16:$imm)), i32:$t, i32:$f), + (OR (SELNEZ i32:$f, (XORi i32:$cond, immZExt16:$imm)), + (SELEQZ i32:$t, (XORi i32:$cond, immZExt16:$imm)))>, + ISA_MIPS32R6; +def : MipsPat<(select (i32 (setgt i32:$cond, immSExt16Plus1:$imm)), i32:$t, + i32:$f), + (OR (SELEQZ i32:$t, (SLTi i32:$cond, (Plus1 imm:$imm))), + (SELNEZ i32:$f, (SLTi i32:$cond, (Plus1 imm:$imm))))>, + ISA_MIPS32R6; +def : MipsPat<(select (i32 (setugt i32:$cond, immSExt16Plus1:$imm)), + i32:$t, i32:$f), + (OR (SELEQZ i32:$t, (SLTiu i32:$cond, (Plus1 imm:$imm))), + (SELNEZ i32:$f, (SLTiu i32:$cond, (Plus1 imm:$imm))))>, + ISA_MIPS32R6; + +def : MipsPat<(select i32:$cond, i32:$t, immz), + (SELNEZ i32:$t, i32:$cond)>, ISA_MIPS32R6; +def : MipsPat<(select (i32 (setne i32:$cond, immz)), i32:$t, immz), + (SELNEZ i32:$t, i32:$cond)>, ISA_MIPS32R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immz)), i32:$t, immz), + (SELEQZ i32:$t, i32:$cond)>, ISA_MIPS32R6; +def : MipsPat<(select i32:$cond, immz, i32:$f), + (SELEQZ i32:$f, i32:$cond)>, ISA_MIPS32R6; +def : MipsPat<(select (i32 (setne i32:$cond, immz)), immz, i32:$f), + (SELEQZ i32:$f, i32:$cond)>, ISA_MIPS32R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immz)), immz, i32:$f), + (SELNEZ i32:$f, i32:$cond)>, ISA_MIPS32R6; diff --git a/lib/Target/Mips/Mips64InstrInfo.td b/lib/Target/Mips/Mips64InstrInfo.td index 924b325..f0b6814 100644 --- a/lib/Target/Mips/Mips64InstrInfo.td +++ b/lib/Target/Mips/Mips64InstrInfo.td @@ -23,6 +23,8 @@ def uimm16_64 : Operand<i64> { // Signed Operand def simm10_64 : Operand<i64>; +def imm64: Operand<i64>; + // Transformation Function - get Imm - 32. def Subtract32 : SDNodeXForm<imm, [{ return getImm(N, (unsigned)N->getZExtValue() - 32); @@ -36,6 +38,9 @@ def immZExt6 : ImmLeaf<i32, [{return Imm == (Imm & 0x3f);}]>; def immSExt10_64 : PatLeaf<(i64 imm), [{ return isInt<10>(N->getSExtValue()); }]>; +def immZExt16_64 : PatLeaf<(i64 imm), + [{ return isInt<16>(N->getZExtValue()); }]>; + //===----------------------------------------------------------------------===// // Instructions specific format //===----------------------------------------------------------------------===// @@ -62,7 +67,7 @@ let isPseudo = 1, isCodeGenOnly = 1 in { let DecoderNamespace = "Mips64" in { /// Arithmetic Instructions (ALU Immediate) def DADDi : ArithLogicI<"daddi", simm16_64, GPR64Opnd>, ADDI_FM<0x18>, - ISA_MIPS3; + ISA_MIPS3_NOT_32R6_64R6; def DADDiu : ArithLogicI<"daddiu", simm16_64, GPR64Opnd, II_DADDIU, immSExt16, add>, ADDI_FM<0x19>, IsAsCheapAsAMove, ISA_MIPS3; @@ -164,49 +169,58 @@ 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; -def SCD : SCBase<"scd", GPR64Opnd>, LW_FM<0x3c>, ISA_MIPS3; +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 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; + 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; + MULT_FM<0, 0x1d>, ISA_MIPS3_NOT_32R6_64R6; def PseudoDMULT : MultDivPseudo<DMULT, ACC128, GPR64Opnd, MipsMult, - II_DMULT>; + II_DMULT>, ISA_MIPS3_NOT_32R6_64R6; def PseudoDMULTu : MultDivPseudo<DMULTu, ACC128, GPR64Opnd, MipsMultu, - II_DMULTU>; + II_DMULTU>, ISA_MIPS3_NOT_32R6_64R6; def DSDIV : Div<"ddiv", II_DDIV, GPR64Opnd, [HI0_64, LO0_64]>, - MULT_FM<0, 0x1e>, ISA_MIPS3; + 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; + MULT_FM<0, 0x1f>, ISA_MIPS3_NOT_32R6_64R6; def PseudoDSDIV : MultDivPseudo<DSDIV, ACC128, GPR64Opnd, MipsDivRem, - II_DDIV, 0, 1, 1>; + II_DDIV, 0, 1, 1>, ISA_MIPS3_NOT_32R6_64R6; def PseudoDUDIV : MultDivPseudo<DUDIV, ACC128, GPR64Opnd, MipsDivRemU, - II_DDIVU, 0, 1, 1>; + II_DDIVU, 0, 1, 1>, ISA_MIPS3_NOT_32R6_64R6; let isCodeGenOnly = 1 in { -def MTHI64 : MoveToLOHI<"mthi", GPR64Opnd, [HI0_64]>, MTLO_FM<0x11>; -def MTLO64 : MoveToLOHI<"mtlo", GPR64Opnd, [LO0_64]>, MTLO_FM<0x13>; -def MFHI64 : MoveFromLOHI<"mfhi", GPR64Opnd, AC0_64>, MFLO_FM<0x10>; -def MFLO64 : MoveFromLOHI<"mflo", GPR64Opnd, AC0_64>, MFLO_FM<0x12>; -def PseudoMFHI64 : PseudoMFLOHI<GPR64, ACC128, MipsMFHI>; -def PseudoMFLO64 : PseudoMFLOHI<GPR64, ACC128, MipsMFLO>; -def PseudoMTLOHI64 : PseudoMTLOHI<ACC128, GPR64>; +def MTHI64 : MoveToLOHI<"mthi", GPR64Opnd, [HI0_64]>, MTLO_FM<0x11>, + ISA_MIPS3_NOT_32R6_64R6; +def MTLO64 : MoveToLOHI<"mtlo", GPR64Opnd, [LO0_64]>, MTLO_FM<0x13>, + ISA_MIPS3_NOT_32R6_64R6; +def MFHI64 : MoveFromLOHI<"mfhi", GPR64Opnd, AC0_64>, MFLO_FM<0x10>, + ISA_MIPS3_NOT_32R6_64R6; +def MFLO64 : MoveFromLOHI<"mflo", GPR64Opnd, AC0_64>, MFLO_FM<0x12>, + ISA_MIPS3_NOT_32R6_64R6; +def PseudoMFHI64 : PseudoMFLOHI<GPR64, ACC128, MipsMFHI>, + ISA_MIPS3_NOT_32R6_64R6; +def PseudoMFLO64 : PseudoMFLOHI<GPR64, ACC128, MipsMFLO>, + ISA_MIPS3_NOT_32R6_64R6; +def PseudoMTLOHI64 : PseudoMTLOHI<ACC128, GPR64>, ISA_MIPS3_NOT_32R6_64R6; /// Sign Ext In Register Instructions. def SEB64 : SignExtInReg<"seb", i8, GPR64Opnd, II_SEB>, SEB_FM<0x10, 0x20>, @@ -216,8 +230,8 @@ def SEH64 : SignExtInReg<"seh", i16, GPR64Opnd, II_SEH>, SEB_FM<0x18, 0x20>, } /// Count Leading -def DCLZ : CountLeading0<"dclz", GPR64Opnd>, CLO_FM<0x24>, ISA_MIPS64; -def DCLO : CountLeading1<"dclo", GPR64Opnd>, CLO_FM<0x25>, ISA_MIPS64; +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; @@ -431,13 +445,13 @@ def : MipsInstAlias<"daddu $rs, $rt, $imm", 0>; def : MipsInstAlias<"dadd $rs, $rt, $imm", (DADDi GPR64Opnd:$rs, GPR64Opnd:$rt, simm16_64:$imm), - 0>; + 0>, ISA_MIPS3_NOT_32R6_64R6; def : MipsInstAlias<"daddu $rs, $imm", (DADDiu GPR64Opnd:$rs, GPR64Opnd:$rs, simm16_64:$imm), 0>; def : MipsInstAlias<"dadd $rs, $imm", (DADDi GPR64Opnd:$rs, GPR64Opnd:$rs, simm16_64:$imm), - 0>; + 0>, ISA_MIPS3_NOT_32R6_64R6; def : MipsInstAlias<"add $rs, $imm", (ADDi GPR32Opnd:$rs, GPR32Opnd:$rs, simm16:$imm), 0>; @@ -450,10 +464,22 @@ def : MipsInstAlias<"dsll $rd, $rt, $rs", def : MipsInstAlias<"dsubu $rt, $rs, $imm", (DADDiu GPR64Opnd:$rt, GPR64Opnd:$rs, InvertedImOperand64:$imm), 0>; +def : MipsInstAlias<"dsubi $rs, $rt, $imm", + (DADDi GPR64Opnd:$rs, GPR64Opnd:$rt, + InvertedImOperand64:$imm), + 0>, ISA_MIPS3_NOT_32R6_64R6; +def : MipsInstAlias<"dsubi $rs, $imm", + (DADDi GPR64Opnd:$rs, GPR64Opnd:$rs, + InvertedImOperand64:$imm), + 0>, ISA_MIPS3_NOT_32R6_64R6; +def : MipsInstAlias<"dsub $rs, $rt, $imm", + (DADDi GPR64Opnd:$rs, GPR64Opnd:$rt, + InvertedImOperand64:$imm), + 0>, ISA_MIPS3_NOT_32R6_64R6; def : MipsInstAlias<"dsub $rs, $imm", (DADDi GPR64Opnd:$rs, GPR64Opnd:$rs, InvertedImOperand64:$imm), - 0>; + 0>, ISA_MIPS3_NOT_32R6_64R6; def : MipsInstAlias<"dsubu $rs, $imm", (DADDiu GPR64Opnd:$rs, GPR64Opnd:$rs, InvertedImOperand64:$imm), @@ -465,6 +491,11 @@ def : MipsInstAlias<"dsrl $rd, $rt, $rs", (DSRLV GPR64Opnd:$rd, GPR64Opnd:$rt, GPR32Opnd:$rs), 0>, ISA_MIPS3; +class LoadImm64< string instr_asm, Operand Od, RegisterOperand RO> : + MipsAsmPseudoInst<(outs RO:$rt), (ins Od:$imm64), + !strconcat(instr_asm, "\t$rt, $imm64")> ; +def LoadImm64Reg : LoadImm64<"dli", imm64, GPR64Opnd>; + /// Move between CPU and coprocessor registers let DecoderNamespace = "Mips64", Predicates = [HasMips64] in { def DMFC0 : MFC3OP<"dmfc0", GPR64Opnd>, MFC3OP_FM<0x10, 1>; diff --git a/lib/Target/Mips/Mips64r6InstrInfo.td b/lib/Target/Mips/Mips64r6InstrInfo.td index f971218..63cf60b 100644 --- a/lib/Target/Mips/Mips64r6InstrInfo.td +++ b/lib/Target/Mips/Mips64r6InstrInfo.td @@ -13,10 +13,6 @@ // Notes about removals/changes from MIPS32r6: // Reencoded: dclo, dclz -// Reencoded: lld, scd -// Removed: daddi -// Removed: ddiv, ddivu, dmult, dmultu -// Removed: div, divu //===----------------------------------------------------------------------===// // @@ -29,14 +25,20 @@ 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, 0b111000>; -class DMUHU_ENC : SPECIAL_3R_FM<0b00011, 0b111001>; -class DMUL_R6_ENC : SPECIAL_3R_FM<0b00010, 0b111000>; -class DMULU_ENC : SPECIAL_3R_FM<0b00010, 0b111001>; +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>; //===----------------------------------------------------------------------===// // @@ -56,14 +58,22 @@ 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 DDIV_DESC : DIVMOD_DESC_BASE<"ddiv", GPR64Opnd>; -class DDIVU_DESC : DIVMOD_DESC_BASE<"ddivu", GPR64Opnd>; -class DMOD_DESC : DIVMOD_DESC_BASE<"dmod", GPR64Opnd>; -class DMODU_DESC : DIVMOD_DESC_BASE<"dmodu", GPR64Opnd>; -class DMUH_DESC : MUL_R6_DESC_BASE<"dmuh", GPR64Opnd>; -class DMUHU_DESC : MUL_R6_DESC_BASE<"dmuhu", GPR64Opnd>; -class DMUL_R6_DESC : MUL_R6_DESC_BASE<"dmul", GPR64Opnd>; +class DCLO_R6_DESC : CLO_R6_DESC_BASE<"dclo", GPR64Opnd>; +class DCLZ_R6_DESC : CLZ_R6_DESC_BASE<"dclz", GPR64Opnd>; +class DDIV_DESC : DIVMOD_DESC_BASE<"ddiv", GPR64Opnd, sdiv>; +class DDIVU_DESC : DIVMOD_DESC_BASE<"ddivu", GPR64Opnd, udiv>; +class DLSA_R6_DESC : LSA_R6_DESC_BASE<"dlsa", GPR64Opnd, uimm2>; +class DMOD_DESC : DIVMOD_DESC_BASE<"dmod", GPR64Opnd, srem>; +class DMODU_DESC : DIVMOD_DESC_BASE<"dmodu", GPR64Opnd, urem>; +class DMUH_DESC : MUL_R6_DESC_BASE<"dmuh", GPR64Opnd, mulhs>; +class DMUHU_DESC : MUL_R6_DESC_BASE<"dmuhu", GPR64Opnd, mulhu>; +class DMUL_R6_DESC : MUL_R6_DESC_BASE<"dmul", GPR64Opnd, mul>; class DMULU_DESC : MUL_R6_DESC_BASE<"dmulu", GPR64Opnd>; +class LDPC_DESC : PCREL_DESC_BASE<"ldpc", GPR64Opnd, simm18_lsl3>; +class LLD_R6_DESC : LL_R6_DESC_BASE<"lld", GPR64Opnd>; +class SCD_R6_DESC : SC_R6_DESC_BASE<"scd", GPR64Opnd>; +class SELEQZ64_DESC : SELEQNE_Z_DESC_BASE<"seleqz", GPR64Opnd>; +class SELNEZ64_DESC : SELEQNE_Z_DESC_BASE<"selnez", GPR64Opnd>; //===----------------------------------------------------------------------===// // @@ -76,13 +86,132 @@ def DALIGN : DALIGN_ENC, DALIGN_DESC, ISA_MIPS64R6; def DATI : DATI_ENC, DATI_DESC, ISA_MIPS64R6; def DAUI : DAUI_ENC, DAUI_DESC, ISA_MIPS64R6; def DBITSWAP : DBITSWAP_ENC, DBITSWAP_DESC, ISA_MIPS64R6; +def DCLO_R6 : DCLO_R6_ENC, DCLO_R6_DESC, ISA_MIPS64R6; +def DCLZ_R6 : DCLZ_R6_ENC, DCLZ_R6_DESC, ISA_MIPS64R6; def DDIV : DDIV_ENC, DDIV_DESC, ISA_MIPS64R6; def DDIVU : DDIVU_ENC, DDIVU_DESC, ISA_MIPS64R6; -// def DLSA; // See MSA +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; +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:$f, (SLL64_32 (XORi i32:$cond, + immZExt16:$imm))), + (SELEQZ64 i64:$t, (SLL64_32 (XORi i32:$cond, + immZExt16:$imm))))>, + ISA_MIPS64R6; + +def : MipsPat<(select i32:$cond, i64:$t, immz), + (SELNEZ64 i64:$t, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (setne i32:$cond, immz)), i64:$t, immz), + (SELNEZ64 i64:$t, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immz)), i64:$t, immz), + (SELEQZ64 i64:$t, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select i32:$cond, immz, i64:$f), + (SELEQZ64 i64:$f, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (setne i32:$cond, immz)), immz, i64:$f), + (SELEQZ64 i64:$f, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; +def : MipsPat<(select (i32 (seteq i32:$cond, immz)), immz, i64:$f), + (SELNEZ64 i64:$f, (SLL64_32 i32:$cond))>, + ISA_MIPS64R6; diff --git a/lib/Target/Mips/MipsAsmPrinter.cpp b/lib/Target/Mips/MipsAsmPrinter.cpp index 6df90aa..1fb75a2 100644 --- a/lib/Target/Mips/MipsAsmPrinter.cpp +++ b/lib/Target/Mips/MipsAsmPrinter.cpp @@ -91,7 +91,46 @@ bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) { #include "MipsGenMCPseudoLowering.inc" +// Lower PseudoReturn/PseudoIndirectBranch/PseudoIndirectBranch64 to JR, JR_MM, +// JALR, or JALR64 as appropriate for the target +void MipsAsmPrinter::emitPseudoIndirectBranch(MCStreamer &OutStreamer, + const MachineInstr *MI) { + bool HasLinkReg = false; + MCInst TmpInst0; + + if (Subtarget->hasMips64r6()) { + // MIPS64r6 should use (JALR64 ZERO_64, $rs) + TmpInst0.setOpcode(Mips::JALR64); + HasLinkReg = true; + } else if (Subtarget->hasMips32r6()) { + // MIPS32r6 should use (JALR ZERO, $rs) + TmpInst0.setOpcode(Mips::JALR); + HasLinkReg = true; + } else if (Subtarget->inMicroMipsMode()) + // microMIPS should use (JR_MM $rs) + TmpInst0.setOpcode(Mips::JR_MM); + else { + // Everything else should use (JR $rs) + TmpInst0.setOpcode(Mips::JR); + } + + MCOperand MCOp; + + if (HasLinkReg) { + unsigned ZeroReg = Subtarget->isGP64bit() ? Mips::ZERO_64 : Mips::ZERO; + TmpInst0.addOperand(MCOperand::CreateReg(ZeroReg)); + } + + lowerOperand(MI->getOperand(0), MCOp); + TmpInst0.addOperand(MCOp); + + EmitToStreamer(OutStreamer, TmpInst0); +} + void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { + MipsTargetStreamer &TS = getTargetStreamer(); + TS.setCanHaveModuleDir(false); + if (MI->isDebugValue()) { SmallString<128> Str; raw_svector_ostream OS(Str); @@ -141,6 +180,14 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { if (emitPseudoExpansionLowering(OutStreamer, &*I)) continue; + if (I->getOpcode() == Mips::PseudoReturn || + I->getOpcode() == Mips::PseudoReturn64 || + I->getOpcode() == Mips::PseudoIndirectBranch || + I->getOpcode() == Mips::PseudoIndirectBranch64) { + emitPseudoIndirectBranch(OutStreamer, &*I); + continue; + } + // The inMips16Mode() test is not permanent. // Some instructions are marked as pseudo right now which // would make the test fail for the wrong reason but @@ -657,6 +704,13 @@ void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) { OutContext.getELFSection(".gcc_compiled_long64", ELF::SHT_PROGBITS, 0, SectionKind::getDataRel())); } + + getTargetStreamer().updateABIInfo(*Subtarget); + getTargetStreamer().emitDirectiveModuleFP(); + + if (Subtarget->isABI_O32()) + getTargetStreamer().emitDirectiveModuleOddSPReg(Subtarget->useOddSPReg(), + Subtarget->isABI_O32()); } void MipsAsmPrinter::EmitJal(MCSymbol *Symbol) { @@ -852,7 +906,7 @@ void MipsAsmPrinter::EmitFPCallStub( TS.emitDirectiveSetNoMicroMips(); // // .ent __call_stub_fp_xxxx - // .type __call_stub_fp_xxxx,@function + // .type __call_stub_fp_xxxx,@function // __call_stub_fp_xxxx: // std::string x = "__call_stub_fp_" + std::string(Symbol); diff --git a/lib/Target/Mips/MipsAsmPrinter.h b/lib/Target/Mips/MipsAsmPrinter.h index e82b145..967aa0b 100644 --- a/lib/Target/Mips/MipsAsmPrinter.h +++ b/lib/Target/Mips/MipsAsmPrinter.h @@ -40,6 +40,12 @@ private: bool emitPseudoExpansionLowering(MCStreamer &OutStreamer, const MachineInstr *MI); + // Emit PseudoReturn, PseudoReturn64, PseudoIndirectBranch, + // and PseudoIndirectBranch64 as a JR, JR_MM, JALR, or JALR64 as appropriate + // for the target. + void emitPseudoIndirectBranch(MCStreamer &OutStreamer, + const MachineInstr *MI); + // lowerOperand - Convert a MachineOperand into the equivalent MCOperand. bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp); diff --git a/lib/Target/Mips/MipsCallingConv.td b/lib/Target/Mips/MipsCallingConv.td index c83d880..007213c 100644 --- a/lib/Target/Mips/MipsCallingConv.td +++ b/lib/Target/Mips/MipsCallingConv.td @@ -239,6 +239,11 @@ def RetCC_Mips : CallingConv<[ def CSR_SingleFloatOnly : CalleeSavedRegs<(add (sequence "F%u", 31, 20), RA, FP, (sequence "S%u", 7, 0))>; +def CSR_O32_FPXX : CalleeSavedRegs<(add (sequence "D%u", 15, 10), RA, FP, + (sequence "S%u", 7, 0))> { + let OtherPreserved = (add (decimate (sequence "F%u", 30, 20), 2)); +} + def CSR_O32 : CalleeSavedRegs<(add (sequence "D%u", 15, 10), RA, FP, (sequence "S%u", 7, 0))>; diff --git a/lib/Target/Mips/MipsCodeEmitter.cpp b/lib/Target/Mips/MipsCodeEmitter.cpp index 13fa546..151ef13 100644 --- a/lib/Target/Mips/MipsCodeEmitter.cpp +++ b/lib/Target/Mips/MipsCodeEmitter.cpp @@ -124,6 +124,7 @@ private: unsigned getSizeInsEncoding(const MachineInstr &MI, unsigned OpNo) const; unsigned getLSAImmEncoding(const MachineInstr &MI, unsigned OpNo) const; unsigned getSimm19Lsl2Encoding(const MachineInstr &MI, unsigned OpNo) const; + unsigned getSimm18Lsl3Encoding(const MachineInstr &MI, unsigned OpNo) const; /// Expand pseudo instructions with accumulator register operands. void expandACCInstr(MachineBasicBlock::instr_iterator MI, @@ -273,6 +274,12 @@ unsigned MipsCodeEmitter::getLSAImmEncoding(const MachineInstr &MI, return 0; } +unsigned MipsCodeEmitter::getSimm18Lsl3Encoding(const MachineInstr &MI, + unsigned OpNo) const { + llvm_unreachable("Unimplemented function."); + return 0; +} + unsigned MipsCodeEmitter::getSimm19Lsl2Encoding(const MachineInstr &MI, unsigned OpNo) const { llvm_unreachable("Unimplemented function."); diff --git a/lib/Target/Mips/MipsCondMov.td b/lib/Target/Mips/MipsCondMov.td index 7177f65..690f626 100644 --- a/lib/Target/Mips/MipsCondMov.td +++ b/lib/Target/Mips/MipsCondMov.td @@ -104,136 +104,162 @@ multiclass MovnPats<RegisterClass CRC, RegisterClass DRC, Instruction MOVNInst, // Instantiation of instructions. def MOVZ_I_I : MMRel, CMov_I_I_FT<"movz", GPR32Opnd, GPR32Opnd, II_MOVZ>, - ADD_FM<0, 0xa>, INSN_MIPS4_32; + 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>; + 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>; + 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>; + 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; + 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>; + 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>; + 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>; + 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; + 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>, AdditionalRequires<[HasMips64]>; + 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; + 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>, AdditionalRequires<[IsGP64bit]>; + 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, FGR_32; + 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, FGR_32; + 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, FGR_64; + 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, FGR_64; + 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>, FGR_64; - def MOVN_I64_D64 : CMov_I_F_FT<"movn.d", GPR64Opnd, FGR64Opnd, - II_MOVN_D>, CMov_I_F_FM<19, 17>, FGR_64; + 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; + 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>, AdditionalRequires<[IsGP64bit]>; + 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; + 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>, AdditionalRequires<[IsGP64bit]>; + 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; + 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; + 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, FGR_32; + 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, FGR_32; + 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, FGR_64; + 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, FGR_64; + CMov_F_F_FM<17, 0>, INSN_MIPS4_32_NOT_32R6_64R6, FGR_64; } // Instantiation of conditional move patterns. -defm : MovzPats0<GPR32, GPR32, MOVZ_I_I, SLT, SLTu, SLTi, SLTiu>; -defm : MovzPats1<GPR32, GPR32, MOVZ_I_I, XOR>; -defm : MovzPats2<GPR32, GPR32, MOVZ_I_I, XORi>; +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>, GPR_64; +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>, - GPR_64; + 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 : MovzPats1<GPR32, GPR64, MOVZ_I_I64, XOR>, GPR_64; -defm : MovzPats1<GPR64, GPR32, MOVZ_I64_I, XOR64>, GPR_64; -defm : MovzPats1<GPR64, GPR64, MOVZ_I64_I64, XOR64>, GPR_64; -defm : MovzPats2<GPR32, GPR64, MOVZ_I_I64, XORi>, GPR_64; -defm : MovzPats2<GPR64, GPR32, MOVZ_I64_I, XORi64>, GPR_64; -defm : MovzPats2<GPR64, GPR64, MOVZ_I64_I64, XORi64>, GPR_64; - -defm : MovnPats<GPR32, GPR32, MOVN_I_I, XOR>; - -defm : MovnPats<GPR32, GPR64, MOVN_I_I64, XOR>, GPR_64; -defm : MovnPats<GPR64, GPR32, MOVN_I64_I, XOR64>, GPR_64; -defm : MovnPats<GPR64, GPR64, MOVN_I64_I64, XOR64>, GPR_64; -defm : MovzPats0<GPR32, FGR32, MOVZ_I_S, SLT, SLTu, SLTi, SLTiu>; -defm : MovzPats1<GPR32, FGR32, MOVZ_I_S, XOR>; -defm : MovnPats<GPR32, FGR32, MOVN_I_S, XOR>; +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 : MovzPats1<GPR64, FGR32, MOVZ_I64_S, XOR64>, GPR_64; -defm : MovnPats<GPR64, FGR32, MOVN_I64_S, XOR64>, GPR_64; -defm : MovzPats0<GPR32, AFGR64, MOVZ_I_D32, SLT, SLTu, SLTi, SLTiu>, FGR_32; -defm : MovzPats1<GPR32, AFGR64, MOVZ_I_D32, XOR>, FGR_32; -defm : MovnPats<GPR32, AFGR64, MOVN_I_D32, XOR>, FGR_32; +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>, FGR_64; +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; -defm : MovzPats1<GPR32, FGR64, MOVZ_I_D64, XOR>, FGR_64; -defm : MovzPats1<GPR64, FGR64, MOVZ_I64_D64, XOR64>, FGR_64; -defm : MovnPats<GPR32, FGR64, MOVN_I_D64, XOR>, FGR_64; -defm : MovnPats<GPR64, FGR64, MOVN_I64_D64, XOR64>, FGR_64; diff --git a/lib/Target/Mips/MipsDSPInstrFormats.td b/lib/Target/Mips/MipsDSPInstrFormats.td index cf09113..b5d52ce 100644 --- a/lib/Target/Mips/MipsDSPInstrFormats.td +++ b/lib/Target/Mips/MipsDSPInstrFormats.td @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// -def HasDSP : Predicate<"Subtarget.hasDSP()">, +def HasDSP : Predicate<"Subtarget->hasDSP()">, AssemblerPredicate<"FeatureDSP">; -def HasDSPR2 : Predicate<"Subtarget.hasDSPR2()">, +def HasDSPR2 : Predicate<"Subtarget->hasDSPR2()">, AssemblerPredicate<"FeatureDSPR2">; // Fields. diff --git a/lib/Target/Mips/MipsDelaySlotFiller.cpp b/lib/Target/Mips/MipsDelaySlotFiller.cpp index d6c7cac..bcfbc12 100644 --- a/lib/Target/Mips/MipsDelaySlotFiller.cpp +++ b/lib/Target/Mips/MipsDelaySlotFiller.cpp @@ -23,6 +23,7 @@ #include "llvm/CodeGen/MachineBranchProbabilityInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/Support/CommandLine.h" #include "llvm/Target/TargetInstrInfo.h" @@ -177,6 +178,13 @@ namespace { 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; } diff --git a/lib/Target/Mips/MipsFastISel.cpp b/lib/Target/Mips/MipsFastISel.cpp index 268a0ed..617801b 100644 --- a/lib/Target/Mips/MipsFastISel.cpp +++ b/lib/Target/Mips/MipsFastISel.cpp @@ -12,6 +12,7 @@ #include "MipsISelLowering.h" #include "MipsMachineFunction.h" #include "MipsSubtarget.h" +#include "MipsTargetMachine.h" using namespace llvm; @@ -36,11 +37,11 @@ class MipsFastISel final : public FastISel { /// Subtarget - Keep a pointer to the MipsSubtarget around so that we can /// make the right decision when generating code for different targets. - const MipsSubtarget *Subtarget; Module &M; const TargetMachine &TM; const TargetInstrInfo &TII; const TargetLowering &TLI; + const MipsSubtarget *Subtarget; MipsFunctionInfo *MFI; // Convenience variables to avoid some queries. @@ -54,8 +55,8 @@ public: : FastISel(funcInfo, libInfo), M(const_cast<Module &>(*funcInfo.Fn->getParent())), TM(funcInfo.MF->getTarget()), TII(*TM.getInstrInfo()), - TLI(*TM.getTargetLowering()) { - Subtarget = &TM.getSubtarget<MipsSubtarget>(); + TLI(*TM.getTargetLowering()), + Subtarget(&TM.getSubtarget<MipsSubtarget>()) { MFI = funcInfo.MF->getInfo<MipsFunctionInfo>(); Context = &funcInfo.Fn->getContext(); TargetSupported = ((Subtarget->getRelocationModel() == Reloc::PIC_) && @@ -68,8 +69,11 @@ public: bool ComputeAddress(const Value *Obj, Address &Addr); private: + bool EmitLoad(MVT VT, unsigned &ResultReg, Address &Addr, + unsigned Alignment = 0); bool EmitStore(MVT VT, unsigned SrcReg, Address &Addr, unsigned Alignment = 0); + bool SelectLoad(const Instruction *I); bool SelectRet(const Instruction *I); bool SelectStore(const Instruction *I); @@ -80,6 +84,36 @@ private: unsigned MaterializeGV(const GlobalValue *GV, MVT VT); unsigned MaterializeInt(const Constant *C, MVT VT); unsigned Materialize32BitInt(int64_t Imm, const TargetRegisterClass *RC); + + // for some reason, this default is not generated by tablegen + // so we explicitly generate it here. + // + unsigned FastEmitInst_riir(uint64_t inst, const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill, uint64_t imm1, + uint64_t imm2, unsigned Op3, bool Op3IsKill) { + return 0; + } + + MachineInstrBuilder EmitInst(unsigned Opc) { + return BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)); + } + + MachineInstrBuilder EmitInst(unsigned Opc, unsigned DstReg) { + return BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), + DstReg); + } + + MachineInstrBuilder EmitInstStore(unsigned Opc, unsigned SrcReg, + unsigned MemReg, int64_t MemOffset) { + return EmitInst(Opc).addReg(SrcReg).addReg(MemReg).addImm(MemOffset); + } + + MachineInstrBuilder EmitInstLoad(unsigned Opc, unsigned DstReg, + unsigned MemReg, int64_t MemOffset) { + return EmitInst(Opc, DstReg).addReg(MemReg).addImm(MemOffset); + } + +#include "MipsGenFastISel.inc" }; bool MipsFastISel::isTypeLegal(Type *Ty, MVT &VT) { @@ -100,6 +134,8 @@ bool MipsFastISel::isLoadTypeLegal(Type *Ty, MVT &VT) { // 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; } @@ -116,6 +152,45 @@ bool MipsFastISel::ComputeAddress(const Value *Obj, Address &Addr) { return Addr.Base.Reg != 0; } +bool MipsFastISel::EmitLoad(MVT VT, unsigned &ResultReg, Address &Addr, + unsigned Alignment) { + // + // more cases will be handled here in following patches. + // + unsigned Opc; + switch (VT.SimpleTy) { + case MVT::i32: { + ResultReg = createResultReg(&Mips::GPR32RegClass); + Opc = Mips::LW; + break; + } + case MVT::i16: { + ResultReg = createResultReg(&Mips::GPR32RegClass); + Opc = Mips::LHu; + break; + } + case MVT::i8: { + ResultReg = createResultReg(&Mips::GPR32RegClass); + Opc = Mips::LBu; + break; + } + case MVT::f32: { + ResultReg = createResultReg(&Mips::FGR32RegClass); + Opc = Mips::LWC1; + break; + } + case MVT::f64: { + ResultReg = createResultReg(&Mips::AFGR64RegClass); + Opc = Mips::LDC1; + break; + } + default: + return false; + } + EmitInstLoad(Opc, ResultReg, Addr.Base.Reg, Addr.Offset); + return true; +} + // Materialize a constant into a register, and return the register // number (or zero if we failed to handle it). unsigned MipsFastISel::TargetMaterializeConstant(const Constant *C) { @@ -141,12 +216,49 @@ bool MipsFastISel::EmitStore(MVT VT, unsigned SrcReg, Address &Addr, // // more cases will be handled here in following patches. // - if (VT != MVT::i32) + unsigned Opc; + switch (VT.SimpleTy) { + case MVT::i8: + Opc = Mips::SB; + break; + case MVT::i16: + Opc = Mips::SH; + break; + case MVT::i32: + Opc = Mips::SW; + break; + case MVT::f32: + Opc = Mips::SWC1; + break; + case MVT::f64: + Opc = Mips::SDC1; + break; + default: return false; - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::SW)) - .addReg(SrcReg) - .addReg(Addr.Base.Reg) - .addImm(Addr.Offset); + } + EmitInstStore(Opc, SrcReg, Addr.Base.Reg, Addr.Offset); + return true; +} + +bool MipsFastISel::SelectLoad(const Instruction *I) { + // Atomic loads need special handling. + if (cast<LoadInst>(I)->isAtomic()) + return false; + + // Verify we have a legal type before going any further. + MVT VT; + if (!isLoadTypeLegal(I->getType(), VT)) + return false; + + // See if we can handle this address. + Address Addr; + if (!ComputeAddress(I->getOperand(0), Addr)) + return false; + + unsigned ResultReg; + if (!EmitLoad(VT, ResultReg, Addr, cast<LoadInst>(I)->getAlignment())) + return false; + UpdateValueMap(I, ResultReg); return true; } @@ -186,8 +298,7 @@ bool MipsFastISel::SelectRet(const Instruction *I) { if (Ret->getNumOperands() > 0) { return false; } - unsigned RetOpc = Mips::RetRA; - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(RetOpc)); + EmitInst(Mips::RetRA); return true; } @@ -197,6 +308,8 @@ bool MipsFastISel::TargetSelectInstruction(const Instruction *I) { switch (I->getOpcode()) { default: break; + case Instruction::Load: + return SelectLoad(I); case Instruction::Store: return SelectStore(I); case Instruction::Ret: @@ -207,6 +320,22 @@ bool MipsFastISel::TargetSelectInstruction(const Instruction *I) { } unsigned MipsFastISel::MaterializeFP(const ConstantFP *CFP, MVT VT) { + int64_t Imm = CFP->getValueAPF().bitcastToAPInt().getZExtValue(); + if (VT == MVT::f32) { + const TargetRegisterClass *RC = &Mips::FGR32RegClass; + unsigned DestReg = createResultReg(RC); + unsigned TempReg = Materialize32BitInt(Imm, &Mips::GPR32RegClass); + EmitInst(Mips::MTC1, DestReg).addReg(TempReg); + return DestReg; + } else if (VT == MVT::f64) { + const TargetRegisterClass *RC = &Mips::AFGR64RegClass; + unsigned DestReg = createResultReg(RC); + unsigned TempReg1 = Materialize32BitInt(Imm >> 32, &Mips::GPR32RegClass); + unsigned TempReg2 = + Materialize32BitInt(Imm & 0xFFFFFFFF, &Mips::GPR32RegClass); + EmitInst(Mips::BuildPairF64, DestReg).addReg(TempReg2).addReg(TempReg1); + return DestReg; + } return 0; } @@ -221,9 +350,8 @@ unsigned MipsFastISel::MaterializeGV(const GlobalValue *GV, MVT VT) { // TLS not supported at this time. if (IsThreadLocal) return 0; - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::LW), DestReg) - .addReg(MFI->getGlobalBaseReg()) - .addGlobalAddress(GV, 0, MipsII::MO_GOT); + EmitInst(Mips::LW, DestReg).addReg(MFI->getGlobalBaseReg()).addGlobalAddress( + GV, 0, MipsII::MO_GOT); return DestReg; } unsigned MipsFastISel::MaterializeInt(const Constant *C, MVT VT) { @@ -245,15 +373,10 @@ unsigned MipsFastISel::Materialize32BitInt(int64_t Imm, if (isInt<16>(Imm)) { unsigned Opc = Mips::ADDiu; - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) - .addReg(Mips::ZERO) - .addImm(Imm); + EmitInst(Opc, ResultReg).addReg(Mips::ZERO).addImm(Imm); return ResultReg; } else if (isUInt<16>(Imm)) { - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::ORi), - ResultReg) - .addReg(Mips::ZERO) - .addImm(Imm); + EmitInst(Mips::ORi, ResultReg).addReg(Mips::ZERO).addImm(Imm); return ResultReg; } unsigned Lo = Imm & 0xFFFF; @@ -261,16 +384,10 @@ unsigned MipsFastISel::Materialize32BitInt(int64_t Imm, if (Lo) { // Both Lo and Hi have nonzero bits. unsigned TmpReg = createResultReg(RC); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::LUi), - TmpReg).addImm(Hi); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::ORi), - ResultReg) - .addReg(TmpReg) - .addImm(Lo); - + EmitInst(Mips::LUi, TmpReg).addImm(Hi); + EmitInst(Mips::ORi, ResultReg).addReg(TmpReg).addImm(Lo); } else { - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::LUi), - ResultReg).addImm(Hi); + EmitInst(Mips::LUi, ResultReg).addImm(Hi); } return ResultReg; } diff --git a/lib/Target/Mips/MipsFrameLowering.h b/lib/Target/Mips/MipsFrameLowering.h index e10a3a5..8e9196c 100644 --- a/lib/Target/Mips/MipsFrameLowering.h +++ b/lib/Target/Mips/MipsFrameLowering.h @@ -15,7 +15,6 @@ #define MIPS_FRAMEINFO_H #include "Mips.h" -#include "MipsSubtarget.h" #include "llvm/Target/TargetFrameLowering.h" namespace llvm { diff --git a/lib/Target/Mips/MipsISelDAGToDAG.cpp b/lib/Target/Mips/MipsISelDAGToDAG.cpp index 90cff63..0bdabf3 100644 --- a/lib/Target/Mips/MipsISelDAGToDAG.cpp +++ b/lib/Target/Mips/MipsISelDAGToDAG.cpp @@ -47,6 +47,7 @@ using namespace llvm; //===----------------------------------------------------------------------===// bool MipsDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &TM.getSubtarget<MipsSubtarget>(); bool Ret = SelectionDAGISel::runOnMachineFunction(MF); processFunctionAfterISel(MF); @@ -202,7 +203,7 @@ SDNode* MipsDAGToDAGISel::Select(SDNode *Node) { #ifndef NDEBUG case ISD::LOAD: case ISD::STORE: - assert((Subtarget.systemSupportsUnalignedAccess() || + assert((Subtarget->systemSupportsUnalignedAccess() || cast<MemSDNode>(Node)->getMemoryVT().getSizeInBits() / 8 <= cast<MemSDNode>(Node)->getAlignment()) && "Unexpected unaligned loads/stores."); diff --git a/lib/Target/Mips/MipsISelDAGToDAG.h b/lib/Target/Mips/MipsISelDAGToDAG.h index 13becb6..2a6c875 100644 --- a/lib/Target/Mips/MipsISelDAGToDAG.h +++ b/lib/Target/Mips/MipsISelDAGToDAG.h @@ -32,7 +32,7 @@ namespace llvm { class MipsDAGToDAGISel : public SelectionDAGISel { public: explicit MipsDAGToDAGISel(MipsTargetMachine &TM) - : SelectionDAGISel(TM), Subtarget(TM.getSubtarget<MipsSubtarget>()) {} + : SelectionDAGISel(TM), Subtarget(&TM.getSubtarget<MipsSubtarget>()) {} // Pass Name const char *getPassName() const override { @@ -46,7 +46,7 @@ protected: /// Keep a pointer to the MipsSubtarget around so that we can make the right /// decision when generating code for different targets. - const MipsSubtarget &Subtarget; + const MipsSubtarget *Subtarget; private: // Include the pieces autogenerated from the target description. diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index bfe5ea1..b7af2d4 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -215,6 +215,11 @@ MipsTargetLowering::MipsTargetLowering(MipsTargetMachine &TM) // setcc operations results (slt, sgt, ...). setBooleanContents(ZeroOrOneBooleanContent); setBooleanVectorContents(ZeroOrNegativeOneBooleanContent); + // The cmp.cond.fmt instruction in MIPS32r6/MIPS64r6 uses 0 and -1 like MSA + // does. Integer booleans still use 0 and 1. + if (Subtarget->hasMips32r6()) + setBooleanContents(ZeroOrOneBooleanContent, + ZeroOrNegativeOneBooleanContent); // Load extented operations for i1 types must be promoted setLoadExtAction(ISD::EXTLOAD, MVT::i1, Promote); @@ -251,7 +256,7 @@ MipsTargetLowering::MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::FCOPYSIGN, MVT::f64, Custom); setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); - if (isGP64bit()) { + if (Subtarget->isGP64bit()) { setOperationAction(ISD::GlobalAddress, MVT::i64, Custom); setOperationAction(ISD::BlockAddress, MVT::i64, Custom); setOperationAction(ISD::GlobalTLSAddress, MVT::i64, Custom); @@ -263,14 +268,14 @@ MipsTargetLowering::MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::FP_TO_SINT, MVT::i64, Custom); } - if (!isGP64bit()) { + 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 (isGP64bit()) + if (Subtarget->isGP64bit()) setOperationAction(ISD::ADD, MVT::i64, Custom); setOperationAction(ISD::SDIV, MVT::i32, Expand); @@ -287,7 +292,8 @@ MipsTargetLowering::MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::BR_CC, MVT::f64, Expand); setOperationAction(ISD::BR_CC, MVT::i32, Expand); setOperationAction(ISD::BR_CC, MVT::i64, Expand); - setOperationAction(ISD::SELECT_CC, MVT::Other, Expand); + setOperationAction(ISD::SELECT_CC, MVT::i32, Expand); + setOperationAction(ISD::SELECT_CC, MVT::i64, Expand); setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand); setOperationAction(ISD::UINT_TO_FP, MVT::i64, Expand); setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand); @@ -368,7 +374,7 @@ MipsTargetLowering::MipsTargetLowering(MipsTargetMachine &TM) if (!Subtarget->hasMips64r2()) setOperationAction(ISD::BSWAP, MVT::i64, Expand); - if (isGP64bit()) { + if (Subtarget->isGP64bit()) { setLoadExtAction(ISD::SEXTLOAD, MVT::i32, Custom); setLoadExtAction(ISD::ZEXTLOAD, MVT::i32, Custom); setLoadExtAction(ISD::EXTLOAD, MVT::i32, Custom); @@ -384,12 +390,13 @@ MipsTargetLowering::MipsTargetLowering(MipsTargetMachine &TM) setTargetDAGCombine(ISD::OR); setTargetDAGCombine(ISD::ADD); - setMinFunctionAlignment(isGP64bit() ? 3 : 2); + setMinFunctionAlignment(Subtarget->isGP64bit() ? 3 : 2); - setStackPointerRegisterToSaveRestore(isN64() ? Mips::SP_64 : Mips::SP); + setStackPointerRegisterToSaveRestore(Subtarget->isABI_N64() ? Mips::SP_64 + : Mips::SP); - setExceptionPointerRegister(isN64() ? Mips::A0_64 : Mips::A0); - setExceptionSelectorRegister(isN64() ? Mips::A1_64 : Mips::A1); + setExceptionPointerRegister(Subtarget->isABI_N64() ? Mips::A0_64 : Mips::A0); + setExceptionSelectorRegister(Subtarget->isABI_N64() ? Mips::A1_64 : Mips::A1); MaxStoresPerMemcpy = 16; @@ -815,10 +822,10 @@ addLiveIn(MachineFunction &MF, unsigned PReg, const TargetRegisterClass *RC) return VReg; } -static MachineBasicBlock *expandPseudoDIV(MachineInstr *MI, - MachineBasicBlock &MBB, - const TargetInstrInfo &TII, - bool Is64Bit) { +static MachineBasicBlock *insertDivByZeroTrap(MachineInstr *MI, + MachineBasicBlock &MBB, + const TargetInstrInfo &TII, + bool Is64Bit) { if (NoZeroDivCheck) return &MBB; @@ -836,6 +843,10 @@ static MachineBasicBlock *expandPseudoDIV(MachineInstr *MI, // Clear Divisor's kill flag. Divisor.setIsKill(false); + + // We would normally delete the original instruction here but in this case + // we only needed to inject an additional instruction rather than replace it. + return &MBB; } @@ -918,10 +929,22 @@ MipsTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, return emitAtomicCmpSwap(MI, BB, 8); case Mips::PseudoSDIV: case Mips::PseudoUDIV: - return expandPseudoDIV(MI, *BB, *getTargetMachine().getInstrInfo(), false); + case Mips::DIV: + case Mips::DIVU: + case Mips::MOD: + case Mips::MODU: + return insertDivByZeroTrap(MI, *BB, *getTargetMachine().getInstrInfo(), + false); case Mips::PseudoDSDIV: case Mips::PseudoDUDIV: - return expandPseudoDIV(MI, *BB, *getTargetMachine().getInstrInfo(), true); + case Mips::DDIV: + case Mips::DDIVU: + case Mips::DMOD: + case Mips::DMODU: + return insertDivByZeroTrap(MI, *BB, *getTargetMachine().getInstrInfo(), + true); + case Mips::SEL_D: + return emitSEL_D(MI, BB); } } @@ -941,16 +964,20 @@ MipsTargetLowering::emitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB, unsigned LL, SC, AND, NOR, ZERO, BEQ; if (Size == 4) { - LL = isMicroMips ? Mips::LL_MM : Mips::LL; - SC = isMicroMips ? Mips::SC_MM : Mips::SC; + if (isMicroMips) { + LL = Mips::LL_MM; + SC = Mips::SC_MM; + } else { + LL = Subtarget->hasMips32r6() ? Mips::LL : Mips::LL_R6; + SC = Subtarget->hasMips32r6() ? Mips::SC : Mips::SC_R6; + } AND = Mips::AND; NOR = Mips::NOR; ZERO = Mips::ZERO; BEQ = Mips::BEQ; - } - else { - LL = Mips::LLD; - SC = Mips::SCD; + } else { + LL = Subtarget->hasMips64r6() ? Mips::LLD : Mips::LLD_R6; + SC = Subtarget->hasMips64r6() ? Mips::SCD : Mips::SCD_R6; AND = Mips::AND64; NOR = Mips::NOR64; ZERO = Mips::ZERO_64; @@ -1012,11 +1039,39 @@ MipsTargetLowering::emitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB, return exitMBB; } -MachineBasicBlock * -MipsTargetLowering::emitAtomicBinaryPartword(MachineInstr *MI, - MachineBasicBlock *BB, - unsigned Size, unsigned BinOpcode, - bool Nand) const { +MachineBasicBlock *MipsTargetLowering::emitSignExtendToI32InReg( + MachineInstr *MI, MachineBasicBlock *BB, unsigned Size, unsigned DstReg, + unsigned SrcReg) const { + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + DebugLoc DL = MI->getDebugLoc(); + + if (Subtarget->hasMips32r2() && Size == 1) { + BuildMI(BB, DL, TII->get(Mips::SEB), DstReg).addReg(SrcReg); + return BB; + } + + if (Subtarget->hasMips32r2() && Size == 2) { + BuildMI(BB, DL, TII->get(Mips::SEH), DstReg).addReg(SrcReg); + return BB; + } + + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + unsigned ScrReg = RegInfo.createVirtualRegister(RC); + + assert(Size < 32); + int64_t ShiftImm = 32 - (Size * 8); + + BuildMI(BB, DL, TII->get(Mips::SLL), ScrReg).addReg(SrcReg).addImm(ShiftImm); + BuildMI(BB, DL, TII->get(Mips::SRA), DstReg).addReg(ScrReg).addImm(ShiftImm); + + return BB; +} + +MachineBasicBlock *MipsTargetLowering::emitAtomicBinaryPartword( + MachineInstr *MI, MachineBasicBlock *BB, unsigned Size, unsigned BinOpcode, + bool Nand) const { assert((Size == 1 || Size == 2) && "Unsupported size for EmitAtomicBinaryPartial."); @@ -1046,7 +1101,6 @@ MipsTargetLowering::emitAtomicBinaryPartword(MachineInstr *MI, unsigned StoreVal = RegInfo.createVirtualRegister(RC); unsigned MaskedOldVal1 = RegInfo.createVirtualRegister(RC); unsigned SrlRes = RegInfo.createVirtualRegister(RC); - unsigned SllRes = RegInfo.createVirtualRegister(RC); unsigned Success = RegInfo.createVirtualRegister(RC); // insert new blocks after the current block @@ -1152,19 +1206,14 @@ MipsTargetLowering::emitAtomicBinaryPartword(MachineInstr *MI, // sinkMBB: // and maskedoldval1,oldval,mask // srl srlres,maskedoldval1,shiftamt - // sll sllres,srlres,24 - // sra dest,sllres,24 + // sign_extend dest,srlres BB = sinkMBB; - int64_t ShiftImm = (Size == 1) ? 24 : 16; BuildMI(BB, DL, TII->get(Mips::AND), MaskedOldVal1) .addReg(OldVal).addReg(Mask); BuildMI(BB, DL, TII->get(Mips::SRLV), SrlRes) .addReg(MaskedOldVal1).addReg(ShiftAmt); - BuildMI(BB, DL, TII->get(Mips::SLL), SllRes) - .addReg(SrlRes).addImm(ShiftImm); - BuildMI(BB, DL, TII->get(Mips::SRA), Dest) - .addReg(SllRes).addImm(ShiftImm); + BB = emitSignExtendToI32InReg(MI, BB, Size, Dest, SrlRes); MI->eraseFromParent(); // The instruction is gone now. @@ -1285,7 +1334,6 @@ MipsTargetLowering::emitAtomicCmpSwapPartword(MachineInstr *MI, unsigned MaskedOldVal1 = RegInfo.createVirtualRegister(RC); unsigned StoreVal = RegInfo.createVirtualRegister(RC); unsigned SrlRes = RegInfo.createVirtualRegister(RC); - unsigned SllRes = RegInfo.createVirtualRegister(RC); unsigned Success = RegInfo.createVirtualRegister(RC); // insert new blocks after the current block @@ -1382,23 +1430,44 @@ MipsTargetLowering::emitAtomicCmpSwapPartword(MachineInstr *MI, // sinkMBB: // srl srlres,maskedoldval0,shiftamt - // sll sllres,srlres,24 - // sra dest,sllres,24 + // sign_extend dest,srlres BB = sinkMBB; - int64_t ShiftImm = (Size == 1) ? 24 : 16; BuildMI(BB, DL, TII->get(Mips::SRLV), SrlRes) .addReg(MaskedOldVal0).addReg(ShiftAmt); - BuildMI(BB, DL, TII->get(Mips::SLL), SllRes) - .addReg(SrlRes).addImm(ShiftImm); - BuildMI(BB, DL, TII->get(Mips::SRA), Dest) - .addReg(SllRes).addImm(ShiftImm); + BB = emitSignExtendToI32InReg(MI, BB, Size, Dest, SrlRes); MI->eraseFromParent(); // The instruction is gone now. return exitMBB; } +MachineBasicBlock *MipsTargetLowering::emitSEL_D(MachineInstr *MI, + MachineBasicBlock *BB) const { + MachineFunction *MF = BB->getParent(); + const TargetRegisterInfo *TRI = getTargetMachine().getRegisterInfo(); + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + DebugLoc DL = MI->getDebugLoc(); + MachineBasicBlock::iterator II(MI); + + unsigned Fc = MI->getOperand(1).getReg(); + const auto &FGR64RegClass = TRI->getRegClass(Mips::FGR64RegClassID); + + unsigned Fc2 = RegInfo.createVirtualRegister(FGR64RegClass); + + BuildMI(*BB, II, DL, TII->get(Mips::SUBREG_TO_REG), Fc2) + .addImm(0) + .addReg(Fc) + .addImm(Mips::sub_lo); + + // We don't erase the original instruction, we just replace the condition + // register with the 64-bit super-register. + MI->getOperand(1).setReg(Fc2); + + return BB; +} + //===----------------------------------------------------------------------===// // Misc Lower Operation implementation //===----------------------------------------------------------------------===// @@ -1421,7 +1490,8 @@ SDValue MipsTargetLowering::lowerBR_JT(SDValue Op, SelectionDAG &DAG) const { 0); Chain = Addr.getValue(1); - if ((getTargetMachine().getRelocationModel() == Reloc::PIC_) || isN64()) { + if ((getTargetMachine().getRelocationModel() == Reloc::PIC_) || + Subtarget->isABI_N64()) { // For PIC, the sequence is: // BRIND(load(Jumptable + index) + RelocBase) // RelocBase can be JumpTable, GOT or some sort of global base. @@ -1439,6 +1509,7 @@ SDValue MipsTargetLowering::lowerBRCOND(SDValue Op, SelectionDAG &DAG) const { SDValue Dest = Op.getOperand(2); SDLoc DL(Op); + assert(!Subtarget->hasMips32r6() && !Subtarget->hasMips64r6()); SDValue CondRes = createFPCmp(DAG, Op.getOperand(1)); // Return if flag is not set by a floating point comparison. @@ -1458,6 +1529,7 @@ SDValue MipsTargetLowering::lowerBRCOND(SDValue Op, SelectionDAG &DAG) const { SDValue MipsTargetLowering:: lowerSELECT(SDValue Op, SelectionDAG &DAG) const { + assert(!Subtarget->hasMips32r6() && !Subtarget->hasMips64r6()); SDValue Cond = createFPCmp(DAG, Op.getOperand(0)); // Return if flag is not set by a floating point comparison. @@ -1483,6 +1555,7 @@ lowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const } SDValue MipsTargetLowering::lowerSETCC(SDValue Op, SelectionDAG &DAG) const { + assert(!Subtarget->hasMips32r6() && !Subtarget->hasMips64r6()); SDValue Cond = createFPCmp(DAG, Op); assert(Cond.getOpcode() == MipsISD::FPCmp && @@ -1502,7 +1575,8 @@ SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op, GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op); const GlobalValue *GV = N->getGlobal(); - if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !isN64()) { + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && + !Subtarget->isABI_N64()) { const MipsTargetObjectFile &TLOF = (const MipsTargetObjectFile&)getObjFileLowering(); @@ -1521,15 +1595,18 @@ SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op, } if (GV->hasInternalLinkage() || (GV->hasLocalLinkage() && !isa<Function>(GV))) - return getAddrLocal(N, Ty, DAG, isN32() || isN64()); + return getAddrLocal(N, Ty, DAG, + Subtarget->isABI_N32() || Subtarget->isABI_N64()); if (LargeGOT) return getAddrGlobalLargeGOT(N, Ty, DAG, MipsII::MO_GOT_HI16, MipsII::MO_GOT_LO16, DAG.getEntryNode(), MachinePointerInfo::getGOT()); - return getAddrGlobal(N, Ty, DAG, (isN32() || isN64()) ? MipsII::MO_GOT_DISP - : MipsII::MO_GOT16, + return getAddrGlobal(N, Ty, DAG, + (Subtarget->isABI_N32() || Subtarget->isABI_N64()) + ? MipsII::MO_GOT_DISP + : MipsII::MO_GOT16, DAG.getEntryNode(), MachinePointerInfo::getGOT()); } @@ -1538,10 +1615,12 @@ SDValue MipsTargetLowering::lowerBlockAddress(SDValue Op, BlockAddressSDNode *N = cast<BlockAddressSDNode>(Op); EVT Ty = Op.getValueType(); - if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !isN64()) + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && + !Subtarget->isABI_N64()) return getAddrNonPIC(N, Ty, DAG); - return getAddrLocal(N, Ty, DAG, isN32() || isN64()); + return getAddrLocal(N, Ty, DAG, + Subtarget->isABI_N32() || Subtarget->isABI_N64()); } SDValue MipsTargetLowering:: @@ -1579,7 +1658,7 @@ lowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(DL).setChain(DAG.getEntryNode()) - .setCallee(CallingConv::C, PtrTy, TlsGetAddr, &Args, 0); + .setCallee(CallingConv::C, PtrTy, TlsGetAddr, std::move(Args), 0); std::pair<SDValue, SDValue> CallResult = LowerCallTo(CLI); SDValue Ret = CallResult.first; @@ -1629,10 +1708,12 @@ lowerJumpTable(SDValue Op, SelectionDAG &DAG) const JumpTableSDNode *N = cast<JumpTableSDNode>(Op); EVT Ty = Op.getValueType(); - if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !isN64()) + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && + !Subtarget->isABI_N64()) return getAddrNonPIC(N, Ty, DAG); - return getAddrLocal(N, Ty, DAG, isN32() || isN64()); + return getAddrLocal(N, Ty, DAG, + Subtarget->isABI_N32() || Subtarget->isABI_N64()); } SDValue MipsTargetLowering:: @@ -1650,10 +1731,12 @@ lowerConstantPool(SDValue Op, SelectionDAG &DAG) const ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); EVT Ty = Op.getValueType(); - if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !isN64()) + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && + !Subtarget->isABI_N64()) return getAddrNonPIC(N, Ty, DAG); - return getAddrLocal(N, Ty, DAG, isN32() || isN64()); + return getAddrLocal(N, Ty, DAG, + Subtarget->isABI_N32() || Subtarget->isABI_N64()); } SDValue MipsTargetLowering::lowerVASTART(SDValue Op, SelectionDAG &DAG) const { @@ -1784,8 +1867,9 @@ lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { MFI->setFrameAddressIsTaken(true); EVT VT = Op.getValueType(); SDLoc DL(Op); - SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, - isN64() ? Mips::FP_64 : Mips::FP, VT); + SDValue FrameAddr = + DAG.getCopyFromReg(DAG.getEntryNode(), DL, + Subtarget->isABI_N64() ? Mips::FP_64 : Mips::FP, VT); return FrameAddr; } @@ -1801,7 +1885,7 @@ SDValue MipsTargetLowering::lowerRETURNADDR(SDValue Op, MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo *MFI = MF.getFrameInfo(); MVT VT = Op.getSimpleValueType(); - unsigned RA = isN64() ? Mips::RA_64 : Mips::RA; + unsigned RA = Subtarget->isABI_N64() ? Mips::RA_64 : Mips::RA; MFI->setReturnAddressIsTaken(true); // Return RA, which contains the return address. Mark it an implicit live-in. @@ -1823,12 +1907,12 @@ SDValue MipsTargetLowering::lowerEH_RETURN(SDValue Op, SelectionDAG &DAG) SDValue Offset = Op.getOperand(1); SDValue Handler = Op.getOperand(2); SDLoc DL(Op); - EVT Ty = isN64() ? MVT::i64 : MVT::i32; + EVT Ty = Subtarget->isABI_N64() ? MVT::i64 : MVT::i32; // Store stack offset in V1, store jump target in V0. Glue CopyToReg and // EH_RETURN nodes, so that instructions are emitted back-to-back. - unsigned OffsetReg = isN64() ? Mips::V1_64 : Mips::V1; - unsigned AddrReg = isN64() ? Mips::V0_64 : Mips::V0; + unsigned OffsetReg = Subtarget->isABI_N64() ? Mips::V1_64 : Mips::V1; + unsigned AddrReg = Subtarget->isABI_N64() ? Mips::V0_64 : Mips::V0; Chain = DAG.getCopyToReg(Chain, DL, OffsetReg, Offset, SDValue()); Chain = DAG.getCopyToReg(Chain, DL, AddrReg, Handler, Chain.getValue(1)); return DAG.getNode(MipsISD::EH_RETURN, DL, MVT::Other, Chain, @@ -2256,8 +2340,8 @@ getOpndList(SmallVectorImpl<SDValue> &Ops, // in PIC mode) allow symbols to be resolved via lazy binding. // The lazy binding stub requires GP to point to the GOT. if (IsPICCall && !InternalLinkage) { - unsigned GPReg = isN64() ? Mips::GP_64 : Mips::GP; - EVT Ty = isN64() ? MVT::i64 : MVT::i32; + unsigned GPReg = Subtarget->isABI_N64() ? Mips::GP_64 : Mips::GP; + EVT Ty = Subtarget->isABI_N64() ? MVT::i64 : MVT::i32; RegsToPass.push_back(std::make_pair(GPReg, getGlobalReg(CLI.DAG, Ty))); } @@ -2326,8 +2410,8 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, getTargetMachine(), ArgLocs, *DAG.getContext()); MipsCC::SpecialCallingConvType SpecialCallingConv = getSpecialCallingConv(Callee); - MipsCC MipsCCInfo(CallConv, isO32(), Subtarget->isFP64bit(), CCInfo, - SpecialCallingConv); + MipsCC MipsCCInfo(CallConv, Subtarget->isABI_O32(), Subtarget->isFP64bit(), + CCInfo, SpecialCallingConv); MipsCCInfo.analyzeCallOperands(Outs, IsVarArg, Subtarget->mipsSEUsesSoftFloat(), @@ -2360,7 +2444,8 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, Chain = DAG.getCALLSEQ_START(Chain, NextStackOffsetVal, DL); SDValue StackPtr = DAG.getCopyFromReg( - Chain, DL, isN64() ? Mips::SP_64 : Mips::SP, getPointerTy()); + Chain, DL, Subtarget->isABI_N64() ? Mips::SP_64 : Mips::SP, + getPointerTy()); // With EABI is it possible to have 16 args on registers. std::deque< std::pair<unsigned, SDValue> > RegsToPass; @@ -2446,8 +2531,9 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, // If the callee is a GlobalAddress/ExternalSymbol node (quite common, every // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol // node so that legalize doesn't hack it. - bool IsPICCall = (isN64() || IsPIC); // true if calls are translated to - // jalr $25 + bool IsPICCall = + (Subtarget->isABI_N64() || IsPIC); // true if calls are translated to + // jalr $25 bool GlobalOrExternal = false, InternalLinkage = false; SDValue CalleeLo; EVT Ty = Callee.getValueType(); @@ -2458,7 +2544,8 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, InternalLinkage = Val->hasInternalLinkage(); if (InternalLinkage) - Callee = getAddrLocal(G, Ty, DAG, isN32() || isN64()); + Callee = getAddrLocal(G, Ty, DAG, + Subtarget->isABI_N32() || Subtarget->isABI_N64()); else if (LargeGOT) Callee = getAddrGlobalLargeGOT(G, Ty, DAG, MipsII::MO_CALL_HI16, MipsII::MO_CALL_LO16, Chain, @@ -2474,7 +2561,7 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) { const char *Sym = S->getSymbol(); - if (!isN64() && !IsPIC) // !N64 && static + if (!Subtarget->isABI_N64() && !IsPIC) // !N64 && static Callee = DAG.getTargetExternalSymbol(Sym, getPointerTy(), MipsII::MO_NO_FLAG); else if (LargeGOT) @@ -2525,7 +2612,8 @@ MipsTargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag, SmallVector<CCValAssign, 16> RVLocs; CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), getTargetMachine(), RVLocs, *DAG.getContext()); - MipsCC MipsCCInfo(CallConv, isO32(), Subtarget->isFP64bit(), CCInfo); + MipsCC MipsCCInfo(CallConv, Subtarget->isABI_O32(), Subtarget->isFP64bit(), + CCInfo); MipsCCInfo.analyzeCallResult(Ins, Subtarget->mipsSEUsesSoftFloat(), CallNode, RetTy); @@ -2572,7 +2660,8 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, SmallVector<CCValAssign, 16> ArgLocs; CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), getTargetMachine(), ArgLocs, *DAG.getContext()); - MipsCC MipsCCInfo(CallConv, isO32(), Subtarget->isFP64bit(), CCInfo); + MipsCC MipsCCInfo(CallConv, Subtarget->isABI_O32(), Subtarget->isFP64bit(), + CCInfo); Function::const_arg_iterator FuncArg = DAG.getMachineFunction().getFunction()->arg_begin(); bool UseSoftFloat = Subtarget->mipsSEUsesSoftFloat(); @@ -2634,7 +2723,8 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, (RegVT == MVT::i64 && ValVT == MVT::f64) || (RegVT == MVT::f64 && ValVT == MVT::i64)) ArgValue = DAG.getNode(ISD::BITCAST, DL, ValVT, ArgValue); - else if (isO32() && RegVT == MVT::i32 && ValVT == MVT::f64) { + else if (Subtarget->isABI_O32() && RegVT == MVT::i32 && + ValVT == MVT::f64) { unsigned Reg2 = addLiveIn(DAG.getMachineFunction(), getNextIntArgReg(ArgReg), RC); SDValue ArgValue2 = DAG.getCopyFromReg(Chain, DL, Reg2, RegVT); @@ -2672,7 +2762,7 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, unsigned Reg = MipsFI->getSRetReturnReg(); if (!Reg) { Reg = MF.getRegInfo().createVirtualRegister( - getRegClassFor(isN64() ? MVT::i64 : MVT::i32)); + getRegClassFor(Subtarget->isABI_N64() ? MVT::i64 : MVT::i32)); MipsFI->setSRetReturnReg(Reg); } SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), DL, Reg, InVals[i]); @@ -2723,7 +2813,8 @@ MipsTargetLowering::LowerReturn(SDValue Chain, // CCState - Info about the registers and stack slot. CCState CCInfo(CallConv, IsVarArg, MF, getTargetMachine(), RVLocs, *DAG.getContext()); - MipsCC MipsCCInfo(CallConv, isO32(), Subtarget->isFP64bit(), CCInfo); + MipsCC MipsCCInfo(CallConv, Subtarget->isABI_O32(), Subtarget->isFP64bit(), + CCInfo); // Analyze return values. MipsCCInfo.analyzeReturn(Outs, Subtarget->mipsSEUsesSoftFloat(), @@ -2759,7 +2850,7 @@ MipsTargetLowering::LowerReturn(SDValue Chain, if (!Reg) llvm_unreachable("sret virtual register not created in the entry block"); SDValue Val = DAG.getCopyFromReg(Chain, DL, Reg, getPointerTy()); - unsigned V0 = isN64() ? Mips::V0_64 : Mips::V0; + unsigned V0 = Subtarget->isABI_N64() ? Mips::V0_64 : Mips::V0; Chain = DAG.getCopyToReg(Chain, DL, V0, Val, Flag); Flag = Chain.getValue(1); @@ -2980,9 +3071,9 @@ getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const return std::make_pair(0U, &Mips::CPU16RegsRegClass); return std::make_pair(0U, &Mips::GPR32RegClass); } - if (VT == MVT::i64 && !isGP64bit()) + if (VT == MVT::i64 && !Subtarget->isGP64bit()) return std::make_pair(0U, &Mips::GPR32RegClass); - if (VT == MVT::i64 && isGP64bit()) + 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); @@ -3169,7 +3260,7 @@ bool MipsTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const { } unsigned MipsTargetLowering::getJumpTableEncoding() const { - if (isN64()) + if (Subtarget->isABI_N64()) return MachineJumpTableInfo::EK_GPRel64BlockAddress; return TargetLowering::getJumpTableEncoding(); diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h index 4ac33bf..4701bc4 100644 --- a/lib/Target/Mips/MipsISelLowering.h +++ b/lib/Target/Mips/MipsISelLowering.h @@ -17,7 +17,6 @@ #include "MCTargetDesc/MipsBaseInfo.h" #include "Mips.h" -#include "MipsSubtarget.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/IR/Function.h" @@ -210,6 +209,7 @@ namespace llvm { // TargetLowering Implementation //===--------------------------------------------------------------------===// class MipsFunctionInfo; + class MipsSubtarget; class MipsTargetLowering : public TargetLowering { bool isMicroMips; @@ -438,12 +438,6 @@ namespace llvm { // Subtarget Info const MipsSubtarget *Subtarget; - bool hasMips64() const { return Subtarget->hasMips64(); } - bool isGP64bit() const { return Subtarget->isGP64bit(); } - bool isO32() const { return Subtarget->isABI_O32(); } - bool isN32() const { return Subtarget->isABI_N32(); } - bool isN64() const { return Subtarget->isABI_N64(); } - private: // Create a TargetGlobalAddress node. SDValue getTargetNode(GlobalAddressSDNode *N, EVT Ty, SelectionDAG &DAG, @@ -598,6 +592,12 @@ namespace llvm { unsigned getJumpTableEncoding() 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, @@ -607,6 +607,7 @@ namespace llvm { MachineBasicBlock *BB, unsigned Size) const; MachineBasicBlock *emitAtomicCmpSwapPartword(MachineInstr *MI, MachineBasicBlock *BB, unsigned Size) const; + MachineBasicBlock *emitSEL_D(MachineInstr *MI, MachineBasicBlock *BB) const; }; /// Create MipsTargetLowering objects. diff --git a/lib/Target/Mips/MipsInstrFPU.td b/lib/Target/Mips/MipsInstrFPU.td index 32cda3b..2260d53 100644 --- a/lib/Target/Mips/MipsInstrFPU.td +++ b/lib/Target/Mips/MipsInstrFPU.td @@ -57,13 +57,13 @@ let PrintMethod = "printFCCOperand", DecoderMethod = "DecodeCondCode" in // Feature predicates. //===----------------------------------------------------------------------===// -def IsFP64bit : Predicate<"Subtarget.isFP64bit()">, +def IsFP64bit : Predicate<"Subtarget->isFP64bit()">, AssemblerPredicate<"FeatureFP64Bit">; -def NotFP64bit : Predicate<"!Subtarget.isFP64bit()">, +def NotFP64bit : Predicate<"!Subtarget->isFP64bit()">, AssemblerPredicate<"!FeatureFP64Bit">; -def IsSingleFloat : Predicate<"Subtarget.isSingleFloat()">, +def IsSingleFloat : Predicate<"Subtarget->isSingleFloat()">, AssemblerPredicate<"FeatureSingleFloat">; -def IsNotSingleFloat : Predicate<"!Subtarget.isSingleFloat()">, +def IsNotSingleFloat : Predicate<"!Subtarget->isSingleFloat()">, AssemblerPredicate<"!FeatureSingleFloat">; //===----------------------------------------------------------------------===// @@ -153,6 +153,15 @@ class MTC1_FT<string opstr, RegisterOperand DstRC, RegisterOperand SrcRC, InstSE<(outs DstRC:$fs), (ins SrcRC:$rt), !strconcat(opstr, "\t$rt, $fs"), [(set DstRC:$fs, (OpNode SrcRC:$rt))], Itin, FrmFR, opstr>; +class MTC1_64_FT<string opstr, RegisterOperand DstRC, RegisterOperand SrcRC, + InstrItinClass Itin> : + InstSE<(outs DstRC:$fs), (ins DstRC:$fs_in, SrcRC:$rt), + !strconcat(opstr, "\t$rt, $fs"), [], Itin, FrmFR, opstr> { + // $fs_in is part of a white lie to work around a widespread bug in the FPU + // implementation. See expandBuildPairF64 for details. + let Constraints = "$fs = $fs_in"; +} + class LW_FT<string opstr, RegisterOperand RC, InstrItinClass Itin, SDPatternOperator OpNode= null_frag> : InstSE<(outs RC:$rt), (ins mem:$addr), !strconcat(opstr, "\t$rt, $addr"), @@ -249,11 +258,11 @@ multiclass C_COND_M<string TypeStr, RegisterOperand RC, bits<5> fmt, def C_NGT_#NAME : C_COND_FT<"ngt", TypeStr, RC, itin>, C_COND_FM<fmt, 15>; } -defm S : C_COND_M<"s", FGR32Opnd, 16, II_C_CC_S>; -defm D32 : C_COND_M<"d", AFGR64Opnd, 17, II_C_CC_D>, +defm S : C_COND_M<"s", FGR32Opnd, 16, II_C_CC_S>, ISA_MIPS1_NOT_32R6_64R6; +defm D32 : C_COND_M<"d", AFGR64Opnd, 17, II_C_CC_D>, ISA_MIPS1_NOT_32R6_64R6, AdditionalRequires<[NotFP64bit]>; let DecoderNamespace = "Mips64" in -defm D64 : C_COND_M<"d", FGR64Opnd, 17, II_C_CC_D>, +defm D64 : C_COND_M<"d", FGR64Opnd, 17, II_C_CC_D>, ISA_MIPS1_NOT_32R6_64R6, AdditionalRequires<[IsFP64bit]>; //===----------------------------------------------------------------------===// @@ -355,8 +364,12 @@ def MTC1 : MMRel, MTC1_FT<"mtc1", FGR32Opnd, GPR32Opnd, II_MTC1, bitconvert>, MFC1_FM<4>; def MFHC1 : MMRel, MFC1_FT<"mfhc1", GPR32Opnd, FGRH32Opnd, II_MFHC1>, MFC1_FM<3>, ISA_MIPS32R2; -def MTHC1 : MMRel, MTC1_FT<"mthc1", FGRH32Opnd, GPR32Opnd, II_MTHC1>, - MFC1_FM<7>, ISA_MIPS32R2; +def MTHC1_D32 : MMRel, MTC1_64_FT<"mthc1", FGR64Opnd, GPR32Opnd, II_MTHC1>, + MFC1_FM<7>, ISA_MIPS32R2, AdditionalRequires<[NotFP64bit]>; +def MTHC1_D64 : MTC1_64_FT<"mthc1", AFGR64Opnd, GPR32Opnd, II_MTHC1>, + MFC1_FM<7>, ISA_MIPS32R2, AdditionalRequires<[IsFP64bit]> { + let DecoderNamespace = "Mips64"; +} def DMFC1 : MFC1_FT<"dmfc1", GPR64Opnd, FGR64Opnd, II_DMFC1, bitconvert>, MFC1_FM<1>, ISA_MIPS3; def DMTC1 : MTC1_FT<"dmtc1", FGR64Opnd, GPR64Opnd, II_DMTC1, @@ -390,56 +403,64 @@ def SDC1 : MMRel, SW_FT<"sdc1", AFGR64Opnd, II_SDC1, store>, LW_FM<0x3d>, // Cop2 Memory Instructions // FIXME: These aren't really FPU instructions and as such don't belong in this // file -def LWC2 : LW_FT<"lwc2", COP2Opnd, NoItinerary, load>, LW_FM<0x32>; -def SWC2 : SW_FT<"swc2", COP2Opnd, NoItinerary, store>, LW_FM<0x3a>; -def LDC2 : LW_FT<"ldc2", COP2Opnd, NoItinerary, load>, LW_FM<0x36>, ISA_MIPS2; -def SDC2 : SW_FT<"sdc2", COP2Opnd, NoItinerary, store>, LW_FM<0x3e>, ISA_MIPS2; +def LWC2 : LW_FT<"lwc2", COP2Opnd, NoItinerary, load>, LW_FM<0x32>, + ISA_MIPS1_NOT_32R6_64R6; +def SWC2 : SW_FT<"swc2", COP2Opnd, NoItinerary, store>, LW_FM<0x3a>, + ISA_MIPS1_NOT_32R6_64R6; +def LDC2 : LW_FT<"ldc2", COP2Opnd, NoItinerary, load>, LW_FM<0x36>, + ISA_MIPS2_NOT_32R6_64R6; +def SDC2 : SW_FT<"sdc2", COP2Opnd, NoItinerary, store>, LW_FM<0x3e>, + ISA_MIPS2_NOT_32R6_64R6; // Cop3 Memory Instructions // FIXME: These aren't really FPU instructions and as such don't belong in this // file -def LWC3 : LW_FT<"lwc3", COP3Opnd, NoItinerary, load>, LW_FM<0x33>; -def SWC3 : SW_FT<"swc3", COP3Opnd, NoItinerary, store>, LW_FM<0x3b>; -def LDC3 : LW_FT<"ldc3", COP3Opnd, NoItinerary, load>, LW_FM<0x37>, ISA_MIPS2; -def SDC3 : SW_FT<"sdc3", COP3Opnd, NoItinerary, store>, LW_FM<0x3f>, ISA_MIPS2; +let DecoderNamespace = "COP3_" in { + def LWC3 : LW_FT<"lwc3", COP3Opnd, NoItinerary, load>, LW_FM<0x33>; + def SWC3 : SW_FT<"swc3", COP3Opnd, NoItinerary, store>, LW_FM<0x3b>; + def LDC3 : LW_FT<"ldc3", COP3Opnd, NoItinerary, load>, LW_FM<0x37>, + ISA_MIPS2; + def SDC3 : SW_FT<"sdc3", COP3Opnd, NoItinerary, store>, LW_FM<0x3f>, + ISA_MIPS2; +} // Indexed loads and stores. // 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; + INSN_MIPS4_32R2_NOT_32R6_64R6; def SWXC1 : MMRel, SWXC1_FT<"swxc1", FGR32Opnd, II_SWXC1, store>, SWXC1_FM<8>, - INSN_MIPS4_32R2; + 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, FGR_32; + INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_32; def SDXC1 : SWXC1_FT<"sdxc1", AFGR64Opnd, II_SDXC1, store>, SWXC1_FM<9>, - INSN_MIPS4_32R2, FGR_32; + 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, FGR_64; + INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_64; def SDXC164 : SWXC1_FT<"sdxc1", FGR64Opnd, II_SDXC1, store>, SWXC1_FM<9>, - INSN_MIPS4_32R2, FGR_64; + 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, FGR_32; + INSN_MIPS5_32R2_NOT_32R6_64R6, FGR_32; def SUXC1 : MMRel, SWXC1_FT<"suxc1", AFGR64Opnd, II_SUXC1>, SWXC1_FM<0xd>, - INSN_MIPS5_32R2, FGR_32; + 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, FGR_64; + INSN_MIPS5_32R2_NOT_32R6_64R6, FGR_64; def SUXC164 : SWXC1_FT<"suxc1", FGR64Opnd, II_SUXC1>, SWXC1_FM<0xd>, - INSN_MIPS5_32R2, FGR_64; + INSN_MIPS5_32R2_NOT_32R6_64R6, FGR_64; } /// Floating-point Aritmetic @@ -457,42 +478,42 @@ def FSUB_S : MMRel, ADDS_FT<"sub.s", FGR32Opnd, II_SUB_S, 0, fsub>, 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>, ISA_MIPS32R2; + MADDS_FM<4, 0>, ISA_MIPS32R2_NOT_32R6_64R6; def MSUB_S : MMRel, MADDS_FT<"msub.s", FGR32Opnd, II_MSUB_S, fsub>, - MADDS_FM<5, 0>, ISA_MIPS32R2; + MADDS_FM<5, 0>, ISA_MIPS32R2_NOT_32R6_64R6; let AdditionalPredicates = [NoNaNsFPMath] in { def NMADD_S : MMRel, NMADDS_FT<"nmadd.s", FGR32Opnd, II_NMADD_S, fadd>, - MADDS_FM<6, 0>, ISA_MIPS32R2; + MADDS_FM<6, 0>, ISA_MIPS32R2_NOT_32R6_64R6; def NMSUB_S : MMRel, NMADDS_FT<"nmsub.s", FGR32Opnd, II_NMSUB_S, fsub>, - MADDS_FM<7, 0>, ISA_MIPS32R2; + MADDS_FM<7, 0>, ISA_MIPS32R2_NOT_32R6_64R6; } def MADD_D32 : MMRel, MADDS_FT<"madd.d", AFGR64Opnd, II_MADD_D, fadd>, - MADDS_FM<4, 1>, ISA_MIPS32R2, FGR_32; + MADDS_FM<4, 1>, ISA_MIPS32R2_NOT_32R6_64R6, FGR_32; def MSUB_D32 : MMRel, MADDS_FT<"msub.d", AFGR64Opnd, II_MSUB_D, fsub>, - MADDS_FM<5, 1>, ISA_MIPS32R2, FGR_32; + MADDS_FM<5, 1>, ISA_MIPS32R2_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>, ISA_MIPS32R2, FGR_32; + MADDS_FM<6, 1>, ISA_MIPS32R2_NOT_32R6_64R6, FGR_32; def NMSUB_D32 : MMRel, NMADDS_FT<"nmsub.d", AFGR64Opnd, II_NMSUB_D, fsub>, - MADDS_FM<7, 1>, ISA_MIPS32R2, FGR_32; + MADDS_FM<7, 1>, ISA_MIPS32R2_NOT_32R6_64R6, FGR_32; } let isCodeGenOnly=1 in { def MADD_D64 : MADDS_FT<"madd.d", FGR64Opnd, II_MADD_D, fadd>, - MADDS_FM<4, 1>, ISA_MIPS32R2, FGR_64; + MADDS_FM<4, 1>, ISA_MIPS32R2_NOT_32R6_64R6, FGR_64; def MSUB_D64 : MADDS_FT<"msub.d", FGR64Opnd, II_MSUB_D, fsub>, - MADDS_FM<5, 1>, ISA_MIPS32R2, FGR_64; + MADDS_FM<5, 1>, ISA_MIPS32R2_NOT_32R6_64R6, FGR_64; } let AdditionalPredicates = [NoNaNsFPMath], isCodeGenOnly=1 in { def NMADD_D64 : NMADDS_FT<"nmadd.d", FGR64Opnd, II_NMADD_D, fadd>, - MADDS_FM<6, 1>, ISA_MIPS32R2, FGR_64; + MADDS_FM<6, 1>, ISA_MIPS32R2_NOT_32R6_64R6, FGR_64; def NMSUB_D64 : NMADDS_FT<"nmsub.d", FGR64Opnd, II_NMSUB_D, fsub>, - MADDS_FM<7, 1>, ISA_MIPS32R2, FGR_64; + MADDS_FM<7, 1>, ISA_MIPS32R2_NOT_32R6_64R6, FGR_64; } //===----------------------------------------------------------------------===// @@ -504,9 +525,9 @@ def MIPS_BRANCH_F : PatLeaf<(i32 0)>; def MIPS_BRANCH_T : PatLeaf<(i32 1)>; def BC1F : MMRel, BC1F_FT<"bc1f", brtarget, IIBranch, MIPS_BRANCH_F>, - BC1F_FM<0, 0>; + BC1F_FM<0, 0>, ISA_MIPS1_NOT_32R6_64R6; def BC1T : MMRel, BC1F_FT<"bc1t", brtarget, IIBranch, MIPS_BRANCH_T>, - BC1F_FM<0, 1>; + BC1F_FM<0, 1>, ISA_MIPS1_NOT_32R6_64R6; //===----------------------------------------------------------------------===// // Floating Point Flag Conditions @@ -531,12 +552,13 @@ def MIPS_FCOND_LE : PatLeaf<(i32 14)>; def MIPS_FCOND_NGT : PatLeaf<(i32 15)>; /// Floating Point Compare -def FCMP_S32 : MMRel, CEQS_FT<"s", FGR32, II_C_CC_S, MipsFPCmp>, CEQS_FM<16>; +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>, - AdditionalRequires<[NotFP64bit]>; + ISA_MIPS1_NOT_32R6_64R6, AdditionalRequires<[NotFP64bit]>; let DecoderNamespace = "Mips64" in def FCMP_D64 : CEQS_FT<"d", FGR64, II_C_CC_D, MipsFPCmp>, CEQS_FM<17>, - AdditionalRequires<[IsFP64bit]>; + ISA_MIPS1_NOT_32R6_64R6, AdditionalRequires<[IsFP64bit]>; //===----------------------------------------------------------------------===// // Floating Point Pseudo-Instructions @@ -569,8 +591,10 @@ def ExtractElementF64_64 : ExtractElementF64Base<FGR64Opnd>, //===----------------------------------------------------------------------===// // InstAliases. //===----------------------------------------------------------------------===// -def : MipsInstAlias<"bc1t $offset", (BC1T FCC0, brtarget:$offset)>; -def : MipsInstAlias<"bc1f $offset", (BC1F FCC0, brtarget:$offset)>; +def : MipsInstAlias<"bc1t $offset", (BC1T FCC0, brtarget:$offset)>, + ISA_MIPS1_NOT_32R6_64R6; +def : MipsInstAlias<"bc1f $offset", (BC1F FCC0, brtarget:$offset)>, + ISA_MIPS1_NOT_32R6_64R6; //===----------------------------------------------------------------------===// // Floating Point Patterns diff --git a/lib/Target/Mips/MipsInstrFormats.td b/lib/Target/Mips/MipsInstrFormats.td index 0377eab..6a01ae5 100644 --- a/lib/Target/Mips/MipsInstrFormats.td +++ b/lib/Target/Mips/MipsInstrFormats.td @@ -844,6 +844,44 @@ class BARRIER_FM<bits<5> op> : StdArch { 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; @@ -852,3 +890,17 @@ class COP0_TLB_FM<bits<6> op> : StdArch { let Inst{24-6} = 0; let Inst{5-0} = op; // Operation } + +class CACHEOP_FM<bits<6> op> : StdArch { + bits<21> addr; + bits<5> hint; + bits<5> base = addr{20-16}; + bits<16> offset = addr{15-0}; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = base; + let Inst{20-16} = hint; + let Inst{15-0} = offset; +} diff --git a/lib/Target/Mips/MipsInstrInfo.td b/lib/Target/Mips/MipsInstrInfo.td index 0d3cb75..8e9472c 100644 --- a/lib/Target/Mips/MipsInstrInfo.td +++ b/lib/Target/Mips/MipsInstrInfo.td @@ -146,61 +146,61 @@ def MipsSDR : SDNode<"MipsISD::SDR", SDTStore, //===----------------------------------------------------------------------===// // Mips Instruction Predicate Definitions. //===----------------------------------------------------------------------===// -def HasMips2 : Predicate<"Subtarget.hasMips2()">, +def HasMips2 : Predicate<"Subtarget->hasMips2()">, AssemblerPredicate<"FeatureMips2">; -def HasMips3_32 : Predicate<"Subtarget.hasMips3_32()">, +def HasMips3_32 : Predicate<"Subtarget->hasMips3_32()">, AssemblerPredicate<"FeatureMips3_32">; -def HasMips3_32r2 : Predicate<"Subtarget.hasMips3_32r2()">, +def HasMips3_32r2 : Predicate<"Subtarget->hasMips3_32r2()">, AssemblerPredicate<"FeatureMips3_32r2">; -def HasMips3 : Predicate<"Subtarget.hasMips3()">, +def HasMips3 : Predicate<"Subtarget->hasMips3()">, AssemblerPredicate<"FeatureMips3">; -def HasMips4_32 : Predicate<"Subtarget.hasMips4_32()">, +def HasMips4_32 : Predicate<"Subtarget->hasMips4_32()">, AssemblerPredicate<"FeatureMips4_32">; -def HasMips4_32r2 : Predicate<"Subtarget.hasMips4_32r2()">, +def HasMips4_32r2 : Predicate<"Subtarget->hasMips4_32r2()">, AssemblerPredicate<"FeatureMips4_32r2">; -def HasMips5_32r2 : Predicate<"Subtarget.hasMips5_32r2()">, +def HasMips5_32r2 : Predicate<"Subtarget->hasMips5_32r2()">, AssemblerPredicate<"FeatureMips5_32r2">; -def HasMips32 : Predicate<"Subtarget.hasMips32()">, +def HasMips32 : Predicate<"Subtarget->hasMips32()">, AssemblerPredicate<"FeatureMips32">; -def HasMips32r2 : Predicate<"Subtarget.hasMips32r2()">, +def HasMips32r2 : Predicate<"Subtarget->hasMips32r2()">, AssemblerPredicate<"FeatureMips32r2">; -def HasMips32r6 : Predicate<"Subtarget.hasMips32r6()">, +def HasMips32r6 : Predicate<"Subtarget->hasMips32r6()">, AssemblerPredicate<"FeatureMips32r6">; -def NotMips32r6 : Predicate<"!Subtarget.hasMips32r6()">, +def NotMips32r6 : Predicate<"!Subtarget->hasMips32r6()">, AssemblerPredicate<"!FeatureMips32r6">; -def IsGP64bit : Predicate<"Subtarget.isGP64bit()">, +def IsGP64bit : Predicate<"Subtarget->isGP64bit()">, AssemblerPredicate<"FeatureGP64Bit">; -def IsGP32bit : Predicate<"!Subtarget.isGP64bit()">, +def IsGP32bit : Predicate<"!Subtarget->isGP64bit()">, AssemblerPredicate<"!FeatureGP64Bit">; -def HasMips64 : Predicate<"Subtarget.hasMips64()">, +def HasMips64 : Predicate<"Subtarget->hasMips64()">, AssemblerPredicate<"FeatureMips64">; -def HasMips64r2 : Predicate<"Subtarget.hasMips64r2()">, +def HasMips64r2 : Predicate<"Subtarget->hasMips64r2()">, AssemblerPredicate<"FeatureMips64r2">; -def HasMips64r6 : Predicate<"Subtarget.hasMips64r6()">, +def HasMips64r6 : Predicate<"Subtarget->hasMips64r6()">, AssemblerPredicate<"FeatureMips64r6">; -def NotMips64r6 : Predicate<"!Subtarget.hasMips64r6()">, +def NotMips64r6 : Predicate<"!Subtarget->hasMips64r6()">, AssemblerPredicate<"!FeatureMips64r6">; -def IsN64 : Predicate<"Subtarget.isABI_N64()">, +def IsN64 : Predicate<"Subtarget->isABI_N64()">, AssemblerPredicate<"FeatureN64">; -def InMips16Mode : Predicate<"Subtarget.inMips16Mode()">, +def InMips16Mode : Predicate<"Subtarget->inMips16Mode()">, AssemblerPredicate<"FeatureMips16">; -def HasCnMips : Predicate<"Subtarget.hasCnMips()">, +def HasCnMips : Predicate<"Subtarget->hasCnMips()">, AssemblerPredicate<"FeatureCnMips">; def RelocStatic : Predicate<"TM.getRelocationModel() == Reloc::Static">, AssemblerPredicate<"FeatureMips32">; def RelocPIC : Predicate<"TM.getRelocationModel() == Reloc::PIC_">, AssemblerPredicate<"FeatureMips32">; def NoNaNsFPMath : Predicate<"TM.Options.NoNaNsFPMath">; -def HasStdEnc : Predicate<"Subtarget.hasStandardEncoding()">, +def HasStdEnc : Predicate<"Subtarget->hasStandardEncoding()">, AssemblerPredicate<"!FeatureMips16">; -def NotDSP : Predicate<"!Subtarget.hasDSP()">; -def InMicroMips : Predicate<"Subtarget.inMicroMipsMode()">, +def NotDSP : Predicate<"!Subtarget->hasDSP()">; +def InMicroMips : Predicate<"Subtarget->inMicroMipsMode()">, AssemblerPredicate<"FeatureMicroMips">; -def NotInMicroMips : Predicate<"!Subtarget.inMicroMipsMode()">, +def NotInMicroMips : Predicate<"!Subtarget->inMicroMipsMode()">, AssemblerPredicate<"!FeatureMicroMips">; -def IsLE : Predicate<"Subtarget.isLittle()">; -def IsBE : Predicate<"!Subtarget.isLittle()">; -def IsNotNaCl : Predicate<"!Subtarget.isTargetNaCl()">; +def IsLE : Predicate<"Subtarget->isLittle()">; +def IsBE : Predicate<"!Subtarget->isLittle()">; +def IsNotNaCl : Predicate<"!Subtarget->isTargetNaCl()">; //===----------------------------------------------------------------------===// // Mips GPR size adjectives. @@ -232,8 +232,17 @@ class ISA_MIPS3_NOT_32R6_64R6 { list<Predicate> InsnPredicates = [HasMips3, NotMips32r6, NotMips64r6]; } class ISA_MIPS32 { list<Predicate> InsnPredicates = [HasMips32]; } +class ISA_MIPS32_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips32, NotMips32r6, NotMips64r6]; +} class ISA_MIPS32R2 { list<Predicate> InsnPredicates = [HasMips32r2]; } +class ISA_MIPS32R2_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips32r2, NotMips32r6, NotMips64r6]; +} class ISA_MIPS64 { list<Predicate> InsnPredicates = [HasMips64]; } +class ISA_MIPS64_NOT_64R6 { + list<Predicate> InsnPredicates = [HasMips64, NotMips64r6]; +} class ISA_MIPS64R2 { list<Predicate> InsnPredicates = [HasMips64r2]; } class ISA_MIPS32R6 { list<Predicate> InsnPredicates = [HasMips32r6]; } class ISA_MIPS64R6 { list<Predicate> InsnPredicates = [HasMips64r6]; } @@ -241,17 +250,32 @@ class ISA_MIPS64R6 { list<Predicate> InsnPredicates = [HasMips64r6]; } // The portions of MIPS-III that were also added to MIPS32 class INSN_MIPS3_32 { list<Predicate> InsnPredicates = [HasMips3_32]; } +// The portions of MIPS-III that were also added to MIPS32 but were removed in +// MIPS32r6 and MIPS64r6. +class INSN_MIPS3_32_NOT_32R6_64R6 { + list<Predicate> InsnPredicates = [HasMips3_32, NotMips32r6, NotMips64r6]; +} + // The portions of MIPS-III that were also added to MIPS32 class INSN_MIPS3_32R2 { list<Predicate> InsnPredicates = [HasMips3_32r2]; } -// The portions of MIPS-IV that were also added to MIPS32 -class INSN_MIPS4_32 { list<Predicate> InsnPredicates = [HasMips4_32]; } +// 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 -class INSN_MIPS4_32R2 { list<Predicate> InsnPredicates = [HasMips4_32r2]; } +// 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 -class INSN_MIPS5_32R2 { list<Predicate> InsnPredicates = [HasMips5_32r2]; } +// 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]; +} //===----------------------------------------------------------------------===// @@ -328,7 +352,9 @@ def calltarget : Operand<iPTR> { let ParserMatchClass = MipsJumpTargetAsmOperand; } +def simm9 : Operand<i32>; def simm10 : Operand<i32>; +def simm11 : Operand<i32>; def simm16 : Operand<i32> { let DecoderMethod= "DecodeSimm16"; @@ -337,6 +363,13 @@ def simm16 : Operand<i32> { 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> { @@ -386,6 +419,15 @@ def MipsMemAsmOperand : AsmOperandClass { let ParserMethod = "parseMemOperand"; } +def MipsMemSimm11AsmOperand : AsmOperandClass { + let Name = "MemOffsetSimm11"; + let SuperClasses = [MipsMemAsmOperand]; + let RenderMethod = "addMemOperands"; + let ParserMethod = "parseMemOperand"; + let PredicateMethod = "isMemWithSimmOffset<11>"; + //let DiagnosticType = "Simm11"; +} + def MipsInvertedImmoperand : AsmOperandClass { let Name = "InvNum"; let RenderMethod = "addImmOperands"; @@ -417,6 +459,17 @@ def mem_msa : mem_generic { let EncoderMethod = "getMSAMemEncoding"; } +def mem_simm9 : mem_generic { + let MIOperandInfo = (ops ptr_rc, simm9); + let EncoderMethod = "getMemEncoding"; +} + +def mem_simm11 : mem_generic { + let MIOperandInfo = (ops ptr_rc, simm11); + let EncoderMethod = "getMemEncoding"; + let ParserMatchClass = MipsMemSimm11AsmOperand; +} + def mem_ea : Operand<iPTR> { let PrintMethod = "printMemOperandEA"; let MIOperandInfo = (ops ptr_rc, simm16); @@ -690,20 +743,11 @@ class JumpFR<string opstr, RegisterOperand RO, FrmR, opstr>; // Indirect branch -class IndirectBranch<string opstr, RegisterOperand RO> : - JumpFR<opstr, RO, brind> { +class IndirectBranch<string opstr, RegisterOperand RO> : JumpFR<opstr, RO> { let isBranch = 1; let isIndirectBranch = 1; } -// Return instruction -class RetBase<string opstr, RegisterOperand RO>: JumpFR<opstr, RO> { - let isReturn = 1; - let isCodeGenOnly = 1; - let hasCtrlDep = 1; - let hasExtraSrcRegAllocReq = 1; -} - // Jump and Link (Call) let isCall=1, hasDelaySlot=1, Defs = [RA] in { class JumpLink<string opstr, DAGOperand opnd> : @@ -1042,7 +1086,7 @@ 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; + ADD_FM<0x1c, 2>, ISA_MIPS32_NOT_32R6_64R6; def ADD : MMRel, ArithLogicR<"add", GPR32Opnd>, ADD_FM<0, 0x20>; def SUB : MMRel, ArithLogicR<"sub", GPR32Opnd>, ADD_FM<0, 0x22>; def SLT : MMRel, SetCC_R<"slt", setlt, GPR32Opnd>, ADD_FM<0, 0x2a>; @@ -1103,7 +1147,7 @@ def SWR : StoreLeftRight<"swr", MipsSWR, GPR32Opnd, II_SWR>, LW_FM<0x2e>, ISA_MIPS1_NOT_32R6_64R6; } -def SYNC : MMRel, SYNC_FT<"sync">, SYNC_FM; +def SYNC : MMRel, SYNC_FT<"sync">, SYNC_FM, ISA_MIPS32; def TEQ : MMRel, TEQ_FT<"teq", GPR32Opnd>, TEQ_FM<0x34>; def TGE : MMRel, TEQ_FT<"tge", GPR32Opnd>, TEQ_FM<0x30>; def TGEU : MMRel, TEQ_FT<"tgeu", GPR32Opnd>, TEQ_FM<0x31>; @@ -1127,6 +1171,7 @@ def TNEI : MMRel, TEQI_FT<"tnei", GPR32Opnd>, TEQI_FM<0xe>, def BREAK : MMRel, BRK_FT<"break">, BRK_FM<0xd>; def SYSCALL : MMRel, SYS_FT<"syscall">, SYS_FM<0xc>; def TRAP : TrapBase<BREAK>; +def SDBBP : SYS_FT<"sdbbp">, SDBBP_FM, ISA_MIPS32_NOT_32R6_64R6; def ERET : MMRel, ER_FT<"eret">, ER_FM<0x18>, INSN_MIPS3_32; def DERET : MMRel, ER_FT<"deret">, ER_FM<0x1f>, ISA_MIPS32; @@ -1139,8 +1184,8 @@ let EncodingPredicates = []<Predicate>, // FIXME: Lack of HasStdEnc is probably def WAIT : WAIT_FT<"wait">, WAIT_FM; /// Load-linked, Store-conditional -def LL : LLBase<"ll", GPR32Opnd>, LW_FM<0x30>, ISA_MIPS2; -def SC : SCBase<"sc", GPR32Opnd>, LW_FM<0x38>, ISA_MIPS2; +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 @@ -1161,17 +1206,49 @@ 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 JALR : JumpLinkReg<"jalr", GPR32Opnd>, JALR_FM; + def JALRPseudo : JumpLinkRegPseudo<GPR32Opnd, JALR, RA>; } -def JALX : JumpLink<"jalx", calltarget>, FJ<0x1D>; -def BGEZAL : MMRel, BGEZAL_FT<"bgezal", brtarget, GPR32Opnd>, BGEZAL_FM<0x11>; -def BLTZAL : MMRel, BGEZAL_FT<"bltzal", brtarget, GPR32Opnd>, BGEZAL_FM<0x10>; + +// FIXME: JALX really requires either MIPS16 or microMIPS in addition to MIPS32. +def JALX : JumpLink<"jalx", calltarget>, FJ<0x1D>, ISA_MIPS32_NOT_32R6_64R6; +def BGEZAL : MMRel, BGEZAL_FT<"bgezal", brtarget, GPR32Opnd>, BGEZAL_FM<0x11>, + ISA_MIPS1_NOT_32R6_64R6; +def BLTZAL : MMRel, BGEZAL_FT<"bltzal", brtarget, GPR32Opnd>, BGEZAL_FM<0x10>, + ISA_MIPS1_NOT_32R6_64R6; def BAL_BR : BAL_BR_Pseudo<BGEZAL>; def TAILCALL : TailCall<J>; def TAILCALL_R : TailCallReg<GPR32Opnd, JR>; -def RET : MMRel, RetBase<"ret", GPR32Opnd>, MTLO_FM<8>; +// Indirect branches are matched as PseudoIndirectBranch/PseudoIndirectBranch64 +// then are expanded to JR, JR64, JALR, or JALR64 depending on the ISA. +class PseudoIndirectBranchBase<RegisterOperand RO> : + MipsPseudo<(outs), (ins RO:$rs), [(brind RO:$rs)], IIBranch> { + let isTerminator=1; + let isBarrier=1; + let hasDelaySlot = 1; + let isBranch = 1; + let isIndirectBranch = 1; +} + +def PseudoIndirectBranch : PseudoIndirectBranchBase<GPR32Opnd>; + +// Return instructions are matched as a RetRA instruction, then ar expanded +// into PseudoReturn/PseudoReturn64 after register allocation. Finally, +// MipsAsmPrinter expands this into JR, JR64, JALR, or JALR64 depending on the +// ISA. +class PseudoReturnBase<RegisterOperand RO> : MipsPseudo<(outs), (ins RO:$rs), + [], IIBranch> { + let isTerminator = 1; + let isBarrier = 1; + let hasDelaySlot = 1; + let isReturn = 1; + let isCodeGenOnly = 1; + let hasCtrlDep = 1; + let hasExtraSrcRegAllocReq = 1; +} + +def PseudoReturn : PseudoReturnBase<GPR32Opnd>; // Exception handling related node and instructions. // The conversion sequence is: @@ -1196,20 +1273,24 @@ let Uses = [V0, V1], isTerminator = 1, isReturn = 1, isBarrier = 1 in { /// Multiply and Divide Instructions. def MULT : MMRel, Mult<"mult", II_MULT, GPR32Opnd, [HI0, LO0]>, - MULT_FM<0, 0x18>; + MULT_FM<0, 0x18>, ISA_MIPS1_NOT_32R6_64R6; def MULTu : MMRel, Mult<"multu", II_MULTU, GPR32Opnd, [HI0, LO0]>, - MULT_FM<0, 0x19>; + MULT_FM<0, 0x19>, ISA_MIPS1_NOT_32R6_64R6; def SDIV : MMRel, Div<"div", II_DIV, GPR32Opnd, [HI0, LO0]>, - MULT_FM<0, 0x1a>; + MULT_FM<0, 0x1a>, ISA_MIPS1_NOT_32R6_64R6; def UDIV : MMRel, Div<"divu", II_DIVU, GPR32Opnd, [HI0, LO0]>, - MULT_FM<0, 0x1b>; + MULT_FM<0, 0x1b>, ISA_MIPS1_NOT_32R6_64R6; -def MTHI : MMRel, MoveToLOHI<"mthi", GPR32Opnd, [HI0]>, MTLO_FM<0x11>; -def MTLO : MMRel, MoveToLOHI<"mtlo", GPR32Opnd, [LO0]>, MTLO_FM<0x13>; +def 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>; -def MFLO : MMRel, MoveFromLOHI<"mflo", GPR32Opnd, AC0>, MFLO_FM<0x12>; +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. @@ -1219,8 +1300,10 @@ def SEH : MMRel, SignExtInReg<"seh", i16, GPR32Opnd, II_SEH>, SEB_FM<0x18, 0x20>, ISA_MIPS32R2; /// Count Leading -def CLZ : MMRel, CountLeading0<"clz", GPR32Opnd>, CLO_FM<0x20>, ISA_MIPS32; -def CLO : MMRel, CountLeading1<"clo", GPR32Opnd>, CLO_FM<0x21>, ISA_MIPS32; +def CLZ : MMRel, CountLeading0<"clz", GPR32Opnd>, CLO_FM<0x20>, + ISA_MIPS32_NOT_32R6_64R6; +def CLO : MMRel, CountLeading1<"clo", GPR32Opnd>, CLO_FM<0x21>, + ISA_MIPS32_NOT_32R6_64R6; /// Word Swap Bytes Within Halfwords def WSBH : MMRel, SubwordSwap<"wsbh", GPR32Opnd>, SEB_FM<2, 0x20>, ISA_MIPS32R2; @@ -1235,27 +1318,37 @@ def NOP : PseudoSE<(outs), (ins), []>, PseudoInstExpansion<(SLL ZERO, ZERO, 0)>; 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; -def MADDU : MMRel, MArithR<"maddu", II_MADDU, 1>, MULT_FM<0x1c, 1>, ISA_MIPS32; -def MSUB : MMRel, MArithR<"msub", II_MSUB>, MULT_FM<0x1c, 4>, ISA_MIPS32; -def MSUBU : MMRel, MArithR<"msubu", II_MSUBU>, MULT_FM<0x1c, 5>, ISA_MIPS32; +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>; -def PseudoMULTu : MultDivPseudo<MULTu, ACC64, GPR32Opnd, MipsMultu, II_MULTU>; -def PseudoMFHI : PseudoMFLOHI<GPR32, ACC64, MipsMFHI>; -def PseudoMFLO : PseudoMFLOHI<GPR32, ACC64, MipsMFLO>; -def PseudoMTLOHI : PseudoMTLOHI<ACC64, GPR32>; -def PseudoMADD : MAddSubPseudo<MADD, MipsMAdd, II_MADD>; -def PseudoMADDU : MAddSubPseudo<MADDU, MipsMAddu, II_MADDU>; -def PseudoMSUB : MAddSubPseudo<MSUB, MipsMSub, II_MSUB>; -def PseudoMSUBU : MAddSubPseudo<MSUBU, MipsMSubu, II_MSUBU>; +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>; + 0, 1, 1>, ISA_MIPS1_NOT_32R6_64R6; def PseudoUDIV : MultDivPseudo<UDIV, ACC64, GPR32Opnd, MipsDivRemU, II_DIVU, - 0, 1, 1>; + 0, 1, 1>, ISA_MIPS1_NOT_32R6_64R6; def RDHWR : ReadHardware<GPR32Opnd, HWRegsOpnd>, RDHWR_FM; @@ -1274,6 +1367,46 @@ def SSNOP : Barrier<"ssnop">, BARRIER_FM<1>; def EHB : Barrier<"ehb">, BARRIER_FM<3>; def PAUSE : Barrier<"pause">, BARRIER_FM<5>, ISA_MIPS32R2; +// JR_HB and JALR_HB are defined here using the new style naming +// scheme because some of this code is shared with Mips32r6InstrInfo.td +// and because of that it doesn't follow the naming convention of the +// rest of the file. To avoid a mixture of old vs new style, the new +// style was chosen. +class JR_HB_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs); + dag InOperandList = (ins GPROpnd:$rs); + string AsmString = !strconcat(instr_asm, "\t$rs"); + list<dag> Pattern = []; +} + +class JALR_HB_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs"); + list<dag> Pattern = []; +} + +class JR_HB_DESC : InstSE<(outs), (ins), "", [], NoItinerary, FrmJ>, + JR_HB_DESC_BASE<"jr.hb", GPR32Opnd> { + let isBranch=1; + let isIndirectBranch=1; + let hasDelaySlot=1; + let isTerminator=1; + let isBarrier=1; +} + +class JALR_HB_DESC : InstSE<(outs), (ins), "", [], NoItinerary, FrmJ>, + JALR_HB_DESC_BASE<"jalr.hb", GPR32Opnd> { + let isIndirectBranch=1; + let hasDelaySlot=1; +} + +class JR_HB_ENC : JR_HB_FM<8>; +class JALR_HB_ENC : JALR_HB_FM<9>; + +def JR_HB : JR_HB_DESC, JR_HB_ENC, ISA_MIPS32_NOT_32R6_64R6; +def JALR_HB : JALR_HB_DESC, JALR_HB_ENC, ISA_MIPS32; + class TLB<string asmstr> : InstSE<(outs), (ins), asmstr, [], NoItinerary, FrmOther>; def TLBP : TLB<"tlbp">, COP0_TLB_FM<0x08>; @@ -1281,6 +1414,15 @@ def TLBR : TLB<"tlbr">, COP0_TLB_FM<0x01>; def TLBWI : TLB<"tlbwi">, COP0_TLB_FM<0x02>; def TLBWR : TLB<"tlbwr">, COP0_TLB_FM<0x06>; +class CacheOp<string instr_asm, Operand MemOpnd, RegisterOperand GPROpnd> : + InstSE<(outs), (ins MemOpnd:$addr, uimm5:$hint), + !strconcat(instr_asm, "\t$hint, $addr"), [], NoItinerary, FrmOther>; + +def CACHE : CacheOp<"cache", mem, GPR32Opnd>, CACHEOP_FM<0b101111>, + INSN_MIPS3_32_NOT_32R6_64R6; +def PREF : CacheOp<"pref", mem, GPR32Opnd>, CACHEOP_FM<0b110011>, + INSN_MIPS3_32_NOT_32R6_64R6; + //===----------------------------------------------------------------------===// // Instruction aliases //===----------------------------------------------------------------------===// @@ -1289,19 +1431,23 @@ def : MipsInstAlias<"move $dst, $src", GPR_32 { let AdditionalPredicates = [NotInMicroMips]; } -def : MipsInstAlias<"bal $offset", (BGEZAL ZERO, brtarget:$offset), 0>; +def : MipsInstAlias<"bal $offset", (BGEZAL ZERO, brtarget:$offset), 0>, + ISA_MIPS1_NOT_32R6_64R6; def : MipsInstAlias<"addu $rs, $rt, $imm", (ADDiu GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), 0>; def : MipsInstAlias<"add $rs, $rt, $imm", (ADDi GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), 0>; def : MipsInstAlias<"and $rs, $rt, $imm", (ANDi GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), 0>; +def : MipsInstAlias<"and $rs, $imm", + (ANDi GPR32Opnd:$rs, GPR32Opnd:$rs, simm16:$imm), 0>; def : MipsInstAlias<"j $rs", (JR GPR32Opnd:$rs), 0>; let Predicates = [NotInMicroMips] in { def : MipsInstAlias<"jalr $rs", (JALR RA, GPR32Opnd:$rs), 0>; } def : MipsInstAlias<"jal $rs", (JALR RA, GPR32Opnd:$rs), 0>; def : MipsInstAlias<"jal $rd,$rs", (JALR GPR32Opnd:$rd, GPR32Opnd:$rs), 0>; +def : MipsInstAlias<"jalr.hb $rs", (JALR_HB RA, GPR32Opnd:$rs), 1>, ISA_MIPS32; def : MipsInstAlias<"not $rt, $rs", (NOR GPR32Opnd:$rt, GPR32Opnd:$rs, ZERO), 0>; def : MipsInstAlias<"neg $rt, $rs", @@ -1318,6 +1464,8 @@ def : MipsInstAlias<"xor $rs, $rt, $imm", (XORi GPR32Opnd:$rs, GPR32Opnd:$rt, uimm16:$imm), 0>; def : MipsInstAlias<"or $rs, $rt, $imm", (ORi GPR32Opnd:$rs, GPR32Opnd:$rt, uimm16:$imm), 0>; +def : MipsInstAlias<"or $rs, $imm", + (ORi GPR32Opnd:$rs, GPR32Opnd:$rs, uimm16:$imm), 0>; def : MipsInstAlias<"nop", (SLL ZERO, ZERO, 0), 1>; def : MipsInstAlias<"mfc0 $rt, $rd", (MFC0 GPR32Opnd:$rt, GPR32Opnd:$rd, 0), 0>; def : MipsInstAlias<"mtc0 $rt, $rd", (MTC0 GPR32Opnd:$rt, GPR32Opnd:$rd, 0), 0>; @@ -1360,6 +1508,9 @@ 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 //===----------------------------------------------------------------------===// @@ -1412,6 +1563,10 @@ let AdditionalPredicates = [NotDSP] in { (ADDiu GPR32:$src, imm:$imm)>; } +// SYNC +def : MipsPat<(MipsSync (i32 immz)), + (SYNC 0)>, ISA_MIPS2; + // Call def : MipsPat<(MipsJmpLink (i32 tglobaladdr:$dst)), (JAL tglobaladdr:$dst)>; diff --git a/lib/Target/Mips/MipsLongBranch.cpp b/lib/Target/Mips/MipsLongBranch.cpp index acfe76e..c6838a3 100644 --- a/lib/Target/Mips/MipsLongBranch.cpp +++ b/lib/Target/Mips/MipsLongBranch.cpp @@ -15,6 +15,7 @@ #include "Mips.h" #include "MCTargetDesc/MipsBaseInfo.h" +#include "MCTargetDesc/MipsMCNaCl.h" #include "MipsTargetMachine.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/MachineFunctionPass.h" @@ -64,7 +65,8 @@ namespace { : MachineFunctionPass(ID), TM(tm), IsPIC(TM.getRelocationModel() == Reloc::PIC_), ABI(TM.getSubtarget<MipsSubtarget>().getTargetABI()), - LongBranchSeqSize(!IsPIC ? 2 : (ABI == MipsSubtarget::N64 ? 10 : 9)) {} + LongBranchSeqSize(!IsPIC ? 2 : (ABI == MipsSubtarget::N64 ? 10 : + (!TM.getSubtarget<MipsSubtarget>().isTargetNaCl() ? 9 : 10))) {} const char *getPassName() const override { return "Mips Long Branch"; @@ -264,6 +266,13 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) { 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). + + const MipsSubtarget &Subtarget = TM.getSubtarget<MipsSubtarget>(); + unsigned BalOp = Subtarget.hasMips32r6() ? Mips::BAL : Mips::BAL_BR; + if (ABI != MipsSubtarget::N64) { // $longbr: // addiu $sp, $sp, -8 @@ -305,9 +314,11 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) { BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_LUi), Mips::AT) .addMBB(TgtMBB).addMBB(BalTgtMBB); MIBundleBuilder(*LongBrMBB, Pos) - .append(BuildMI(*MF, DL, TII->get(Mips::BAL_BR)).addMBB(BalTgtMBB)) - .append(BuildMI(*MF, DL, TII->get(Mips::LONG_BRANCH_ADDiu), Mips::AT) - .addReg(Mips::AT).addMBB(TgtMBB).addMBB(BalTgtMBB)); + .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(); @@ -316,10 +327,23 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) { BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::LW), Mips::RA) .addReg(Mips::SP).addImm(0); - MIBundleBuilder(*BalTgtMBB, Pos) - .append(BuildMI(*MF, DL, TII->get(Mips::JR)).addReg(Mips::AT)) - .append(BuildMI(*MF, DL, TII->get(Mips::ADDiu), Mips::SP) - .addReg(Mips::SP).addImm(8)); + if (!TM.getSubtarget<MipsSubtarget>().isTargetNaCl()) { + MIBundleBuilder(*BalTgtMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(Mips::JR)).addReg(Mips::AT)) + .append(BuildMI(*MF, DL, TII->get(Mips::ADDiu), Mips::SP) + .addReg(Mips::SP).addImm(8)); + } else { + // In NaCl, modifying the sp is not allowed in branch delay slot. + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::SP) + .addReg(Mips::SP).addImm(8); + + MIBundleBuilder(*BalTgtMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(Mips::JR)).addReg(Mips::AT)) + .append(BuildMI(*MF, DL, TII->get(Mips::NOP))); + + // Bundle-align the target of indirect branch JR. + TgtMBB->setAlignment(MIPS_NACL_BUNDLE_ALIGN); + } } else { // $longbr: // daddiu $sp, $sp, -16 @@ -364,11 +388,12 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) { .addReg(Mips::AT_64).addImm(16); MIBundleBuilder(*LongBrMBB, Pos) - .append(BuildMI(*MF, DL, TII->get(Mips::BAL_BR)).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)); + .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(); @@ -450,9 +475,18 @@ bool MipsLongBranch::runOnMachineFunction(MachineFunction &F) { continue; int ShVal = TM.getSubtarget<MipsSubtarget>().inMicroMipsMode() ? 2 : 4; + int64_t Offset = computeOffset(I->Br) / ShVal; + + if (TM.getSubtarget<MipsSubtarget>().isTargetNaCl()) { + // The offset calculation does not include sandboxing instructions + // that will be added later in the MC layer. Since at this point we + // don't know the exact amount of code that "sandboxing" will add, we + // conservatively estimate that code will not grow more than 100%. + Offset *= 2; + } // Check if offset fits into 16-bit immediate field of branches. - if (!ForceLongBranch && isInt<16>(computeOffset(I->Br) / ShVal)) + if (!ForceLongBranch && isInt<16>(Offset)) continue; I->HasLongBranch = true; diff --git a/lib/Target/Mips/MipsMSAInstrFormats.td b/lib/Target/Mips/MipsMSAInstrFormats.td index 6bd0366..bff2d0f 100644 --- a/lib/Target/Mips/MipsMSAInstrFormats.td +++ b/lib/Target/Mips/MipsMSAInstrFormats.td @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -def HasMSA : Predicate<"Subtarget.hasMSA()">, +def HasMSA : Predicate<"Subtarget->hasMSA()">, AssemblerPredicate<"FeatureMSA">; class MSAInst : MipsInst<(outs), (ins), "", [], NoItinerary, FrmOther> { diff --git a/lib/Target/Mips/MipsMachineFunction.h b/lib/Target/Mips/MipsMachineFunction.h index e9101cc..8c16f82 100644 --- a/lib/Target/Mips/MipsMachineFunction.h +++ b/lib/Target/Mips/MipsMachineFunction.h @@ -15,7 +15,6 @@ #define MIPS_MACHINE_FUNCTION_INFO_H #include "Mips16HardFloatInfo.h" -#include "MipsSubtarget.h" #include "llvm/ADT/StringMap.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" diff --git a/lib/Target/Mips/MipsRegisterInfo.cpp b/lib/Target/Mips/MipsRegisterInfo.cpp index 83d25ab..084449b 100644 --- a/lib/Target/Mips/MipsRegisterInfo.cpp +++ b/lib/Target/Mips/MipsRegisterInfo.cpp @@ -93,6 +93,9 @@ MipsRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { if (Subtarget.isFP64bit()) return CSR_O32_FP64_SaveList; + if (Subtarget.isFPXX()) + return CSR_O32_FPXX_SaveList; + return CSR_O32_SaveList; } @@ -110,6 +113,9 @@ MipsRegisterInfo::getCallPreservedMask(CallingConv::ID) const { if (Subtarget.isFP64bit()) return CSR_O32_FP64_RegMask; + if (Subtarget.isFPXX()) + return CSR_O32_FPXX_RegMask; + return CSR_O32_RegMask; } @@ -201,6 +207,11 @@ getReservedRegs(const MachineFunction &MF) const { Reserved.set(Mips::GP_64); } + if (Subtarget.isABI_O32() && !Subtarget.useOddSPReg()) { + for (const auto &Reg : Mips::OddSPRegClass) + Reserved.set(Reg); + } + return Reserved; } diff --git a/lib/Target/Mips/MipsRegisterInfo.td b/lib/Target/Mips/MipsRegisterInfo.td index 875a596..6323da3 100644 --- a/lib/Target/Mips/MipsRegisterInfo.td +++ b/lib/Target/Mips/MipsRegisterInfo.td @@ -340,6 +340,12 @@ def AFGR64 : RegisterClass<"Mips", [f64], 64, (add def FGR64 : RegisterClass<"Mips", [f64], 64, (sequence "D%u_64", 0, 31)>; +// Used to reserve odd registers when given -mattr=+nooddspreg +def OddSP : RegisterClass<"Mips", [f32], 32, + (add (decimate (sequence "F%u", 1, 31), 2), + (decimate (sequence "F_HI%u", 1, 31), 2))>, + Unallocatable; + // FP control registers. def CCR : RegisterClass<"Mips", [i32], 32, (sequence "FCR%u", 0, 31)>, Unallocatable; @@ -348,6 +354,10 @@ def CCR : RegisterClass<"Mips", [i32], 32, (sequence "FCR%u", 0, 31)>, def FCC : RegisterClass<"Mips", [i32], 32, (sequence "FCC%u", 0, 7)>, Unallocatable; +// MIPS32r6/MIPS64r6 store FPU condition codes in normal FGR registers. +// This class allows us to represent this in codegen patterns. +def FGRCC : RegisterClass<"Mips", [i32], 32, (sequence "F%u", 0, 31)>; + def MSA128B: RegisterClass<"Mips", [v16i8], 128, (sequence "W%u", 0, 31)>; def MSA128H: RegisterClass<"Mips", [v8i16, v8f16], 128, @@ -512,6 +522,12 @@ def FGR32Opnd : RegisterOperand<FGR32> { let ParserMatchClass = FGR32AsmOperand; } +def FGRCCOpnd : RegisterOperand<FGRCC> { + // The assembler doesn't use register classes so we can re-use + // FGR32AsmOperand. + let ParserMatchClass = FGR32AsmOperand; +} + def FGRH32Opnd : RegisterOperand<FGRH32> { let ParserMatchClass = FGRH32AsmOperand; } diff --git a/lib/Target/Mips/MipsSEFrameLowering.cpp b/lib/Target/Mips/MipsSEFrameLowering.cpp index 6ad5821..6573070 100644 --- a/lib/Target/Mips/MipsSEFrameLowering.cpp +++ b/lib/Target/Mips/MipsSEFrameLowering.cpp @@ -16,6 +16,7 @@ #include "MipsAnalyzeImmediate.h" #include "MipsMachineFunction.h" #include "MipsSEInstrInfo.h" +#include "MipsSubtarget.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" @@ -257,6 +258,9 @@ bool ExpandPseudo::expandCopyACC(MachineBasicBlock &MBB, Iter I, return true; } +MipsSEFrameLowering::MipsSEFrameLowering(const MipsSubtarget &STI) + : MipsFrameLowering(STI, STI.stackAlignment()) {} + unsigned MipsSEFrameLowering::ehDataReg(unsigned I) const { static const unsigned EhDataReg[] = { Mips::A0, Mips::A1, Mips::A2, Mips::A3 diff --git a/lib/Target/Mips/MipsSEFrameLowering.h b/lib/Target/Mips/MipsSEFrameLowering.h index 5d2801f..e832848 100644 --- a/lib/Target/Mips/MipsSEFrameLowering.h +++ b/lib/Target/Mips/MipsSEFrameLowering.h @@ -20,8 +20,7 @@ namespace llvm { class MipsSEFrameLowering : public MipsFrameLowering { public: - explicit MipsSEFrameLowering(const MipsSubtarget &STI) - : MipsFrameLowering(STI, STI.stackAlignment()) {} + explicit MipsSEFrameLowering(const MipsSubtarget &STI); /// emitProlog/emitEpilog - These methods insert prolog and epilog code into /// the function. diff --git a/lib/Target/Mips/MipsSEISelDAGToDAG.cpp b/lib/Target/Mips/MipsSEISelDAGToDAG.cpp index d5385be..6f35947 100644 --- a/lib/Target/Mips/MipsSEISelDAGToDAG.cpp +++ b/lib/Target/Mips/MipsSEISelDAGToDAG.cpp @@ -37,7 +37,7 @@ using namespace llvm; #define DEBUG_TYPE "mips-isel" bool MipsSEDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { - if (Subtarget.inMips16Mode()) + if (Subtarget->inMips16Mode()) return false; return MipsDAGToDAGISel::runOnMachineFunction(MF); } @@ -134,7 +134,7 @@ void MipsSEDAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) { unsigned V0, V1, GlobalBaseReg = MipsFI->getGlobalBaseReg(); const TargetRegisterClass *RC; - if (Subtarget.isABI_N64()) + if (Subtarget->isABI_N64()) RC = (const TargetRegisterClass*)&Mips::GPR64RegClass; else RC = (const TargetRegisterClass*)&Mips::GPR32RegClass; @@ -142,7 +142,7 @@ void MipsSEDAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) { V0 = RegInfo.createVirtualRegister(RC); V1 = RegInfo.createVirtualRegister(RC); - if (Subtarget.isABI_N64()) { + if (Subtarget->isABI_N64()) { MF.getRegInfo().addLiveIn(Mips::T9_64); MBB.addLiveIn(Mips::T9_64); @@ -174,7 +174,7 @@ void MipsSEDAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) { MF.getRegInfo().addLiveIn(Mips::T9); MBB.addLiveIn(Mips::T9); - if (Subtarget.isABI_N32()) { + if (Subtarget->isABI_N32()) { // lui $v0, %hi(%neg(%gp_rel(fname))) // addu $v1, $v0, $t9 // addiu $globalbasereg, $v1, %lo(%neg(%gp_rel(fname))) @@ -187,7 +187,7 @@ void MipsSEDAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) { return; } - assert(Subtarget.isABI_O32()); + assert(Subtarget->isABI_O32()); // For O32 ABI, the following instruction sequence is emitted to initialize // the global base register: @@ -408,7 +408,7 @@ bool MipsSEDAGToDAGISel::selectIntAddrMSA(SDValue Addr, SDValue &Base, // * MSA is enabled // * N is a ISD::BUILD_VECTOR representing a constant splat bool MipsSEDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm) const { - if (!Subtarget.hasMSA()) + if (!Subtarget->hasMSA()) return false; BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N); @@ -422,7 +422,7 @@ bool MipsSEDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm) const { if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs, 8, - !Subtarget.isLittle())) + !Subtarget->isLittle())) return false; Imm = SplatValue; @@ -648,7 +648,7 @@ std::pair<bool, SDNode*> MipsSEDAGToDAGISel::selectNode(SDNode *Node) { } case ISD::ADDE: { - if (Subtarget.hasDSP()) // Select DSP instructions, ADDSC and ADDWC. + if (Subtarget->hasDSP()) // Select DSP instructions, ADDSC and ADDWC. break; SDValue InFlag = Node->getOperand(2); Result = selectAddESubE(Mips::ADDu, InFlag, InFlag.getValue(0), DL, Node); @@ -658,11 +658,11 @@ std::pair<bool, SDNode*> MipsSEDAGToDAGISel::selectNode(SDNode *Node) { case ISD::ConstantFP: { ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(Node); if (Node->getValueType(0) == MVT::f64 && CN->isExactlyValue(+0.0)) { - if (Subtarget.isGP64bit()) { + if (Subtarget->isGP64bit()) { SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, Mips::ZERO_64, MVT::i64); Result = CurDAG->getMachineNode(Mips::DMTC1, DL, MVT::f64, Zero); - } else if (Subtarget.isFP64bit()) { + } else if (Subtarget->isFP64bit()) { SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, Mips::ZERO, MVT::i32); Result = CurDAG->getMachineNode(Mips::BuildPairF64_64, DL, MVT::f64, @@ -813,12 +813,12 @@ std::pair<bool, SDNode*> MipsSEDAGToDAGISel::selectNode(SDNode *Node) { EVT ResVecTy = BVN->getValueType(0); EVT ViaVecTy; - if (!Subtarget.hasMSA() || !BVN->getValueType(0).is128BitVector()) + if (!Subtarget->hasMSA() || !BVN->getValueType(0).is128BitVector()) return std::make_pair(false, nullptr); if (!BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs, 8, - !Subtarget.isLittle())) + !Subtarget->isLittle())) return std::make_pair(false, nullptr); switch (SplatBitSize) { diff --git a/lib/Target/Mips/MipsSEISelLowering.cpp b/lib/Target/Mips/MipsSEISelLowering.cpp index 969d730..be4ca86 100644 --- a/lib/Target/Mips/MipsSEISelLowering.cpp +++ b/lib/Target/Mips/MipsSEISelLowering.cpp @@ -39,7 +39,7 @@ MipsSETargetLowering::MipsSETargetLowering(MipsTargetMachine &TM) // Set up the register classes addRegisterClass(MVT::i32, &Mips::GPR32RegClass); - if (isGP64bit()) + if (Subtarget->isGP64bit()) addRegisterClass(MVT::i64, &Mips::GPR64RegClass); if (Subtarget->hasDSP() || Subtarget->hasMSA()) { @@ -120,10 +120,10 @@ MipsSETargetLowering::MipsSETargetLowering(MipsTargetMachine &TM) if (Subtarget->hasCnMips()) setOperationAction(ISD::MUL, MVT::i64, Legal); - else if (isGP64bit()) + else if (Subtarget->isGP64bit()) setOperationAction(ISD::MUL, MVT::i64, Custom); - if (isGP64bit()) { + if (Subtarget->isGP64bit()) { setOperationAction(ISD::MULHS, MVT::i64, Custom); setOperationAction(ISD::MULHU, MVT::i64, Custom); } @@ -152,6 +152,76 @@ MipsSETargetLowering::MipsSETargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::STORE, MVT::f64, Custom); } + if (Subtarget->hasMips32r6()) { + // MIPS32r6 replaces the accumulator-based multiplies with a three register + // instruction + setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::MUL, MVT::i32, Legal); + setOperationAction(ISD::MULHS, MVT::i32, Legal); + setOperationAction(ISD::MULHU, MVT::i32, Legal); + + // MIPS32r6 replaces the accumulator-based division/remainder with separate + // three register division and remainder instructions. + setOperationAction(ISD::SDIVREM, MVT::i32, Expand); + setOperationAction(ISD::UDIVREM, MVT::i32, Expand); + setOperationAction(ISD::SDIV, MVT::i32, Legal); + setOperationAction(ISD::UDIV, MVT::i32, Legal); + setOperationAction(ISD::SREM, MVT::i32, Legal); + setOperationAction(ISD::UREM, MVT::i32, Legal); + + // MIPS32r6 replaces conditional moves with an equivalent that removes the + // need for three GPR read ports. + setOperationAction(ISD::SETCC, MVT::i32, Legal); + setOperationAction(ISD::SELECT, MVT::i32, Legal); + setOperationAction(ISD::SELECT_CC, MVT::i32, Expand); + + setOperationAction(ISD::SETCC, MVT::f32, Legal); + setOperationAction(ISD::SELECT, MVT::f32, Legal); + setOperationAction(ISD::SELECT_CC, MVT::f32, Expand); + + assert(Subtarget->isFP64bit() && "FR=1 is required for MIPS32r6"); + setOperationAction(ISD::SETCC, MVT::f64, Legal); + setOperationAction(ISD::SELECT, MVT::f64, Legal); + setOperationAction(ISD::SELECT_CC, MVT::f64, Expand); + + setOperationAction(ISD::BRCOND, MVT::Other, Legal); + + // Floating point > and >= are supported via < and <= + setCondCodeAction(ISD::SETOGE, MVT::f32, Expand); + setCondCodeAction(ISD::SETOGT, MVT::f32, Expand); + setCondCodeAction(ISD::SETUGE, MVT::f32, Expand); + setCondCodeAction(ISD::SETUGT, MVT::f32, Expand); + + setCondCodeAction(ISD::SETOGE, MVT::f64, Expand); + setCondCodeAction(ISD::SETOGT, MVT::f64, Expand); + setCondCodeAction(ISD::SETUGE, MVT::f64, Expand); + setCondCodeAction(ISD::SETUGT, MVT::f64, Expand); + } + + if (Subtarget->hasMips64r6()) { + // MIPS64r6 replaces the accumulator-based multiplies with a three register + // instruction + setOperationAction(ISD::MUL, MVT::i64, Legal); + setOperationAction(ISD::MULHS, MVT::i64, Legal); + setOperationAction(ISD::MULHU, MVT::i64, Legal); + + // MIPS32r6 replaces the accumulator-based division/remainder with separate + // three register division and remainder instructions. + setOperationAction(ISD::SDIVREM, MVT::i64, Expand); + setOperationAction(ISD::UDIVREM, MVT::i64, Expand); + setOperationAction(ISD::SDIV, MVT::i64, Legal); + setOperationAction(ISD::UDIV, MVT::i64, Legal); + setOperationAction(ISD::SREM, MVT::i64, Legal); + setOperationAction(ISD::UREM, MVT::i64, Legal); + + // MIPS64r6 replaces conditional moves with an equivalent that removes the + // need for three GPR read ports. + setOperationAction(ISD::SETCC, MVT::i64, Legal); + setOperationAction(ISD::SELECT, MVT::i64, Legal); + setOperationAction(ISD::SELECT_CC, MVT::i64, Expand); + } + computeRegisterProperties(); } @@ -160,6 +230,14 @@ llvm::createMipsSETargetLowering(MipsTargetMachine &TM) { return new MipsSETargetLowering(TM); } +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) { @@ -449,8 +527,8 @@ static SDValue performADDECombine(SDNode *N, SelectionDAG &DAG, if (DCI.isBeforeLegalize()) return SDValue(); - if (Subtarget->hasMips32() && N->getValueType(0) == MVT::i32 && - selectMADD(N, &DAG)) + if (Subtarget->hasMips32() && !Subtarget->hasMips32r6() && + N->getValueType(0) == MVT::i32 && selectMADD(N, &DAG)) return SDValue(N, 0); return SDValue(); @@ -1178,6 +1256,9 @@ SDValue MipsSETargetLowering::lowerSTORE(SDValue Op, SelectionDAG &DAG) const { SDValue MipsSETargetLowering::lowerMulDiv(SDValue Op, unsigned NewOpc, bool HasLo, bool HasHi, SelectionDAG &DAG) const { + // MIPS32r6/MIPS64r6 removed accumulator based multiplies. + assert(!Subtarget->hasMips32r6()); + EVT Ty = Op.getOperand(0).getValueType(); SDLoc DL(Op); SDValue Mult = DAG.getNode(NewOpc, DL, MVT::Untyped, @@ -1651,7 +1732,7 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, case Intrinsic::mips_copy_s_w: return lowerMSACopyIntr(Op, DAG, MipsISD::VEXTRACT_SEXT_ELT); case Intrinsic::mips_copy_s_d: - if (hasMips64()) + if (Subtarget->hasMips64()) // Lower directly into VEXTRACT_SEXT_ELT since i64 is legal on Mips64. return lowerMSACopyIntr(Op, DAG, MipsISD::VEXTRACT_SEXT_ELT); else { @@ -1666,7 +1747,7 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, case Intrinsic::mips_copy_u_w: return lowerMSACopyIntr(Op, DAG, MipsISD::VEXTRACT_ZEXT_ELT); case Intrinsic::mips_copy_u_d: - if (hasMips64()) + if (Subtarget->hasMips64()) // Lower directly into VEXTRACT_ZEXT_ELT since i64 is legal on Mips64. return lowerMSACopyIntr(Op, DAG, MipsISD::VEXTRACT_ZEXT_ELT); else { @@ -2943,8 +3024,8 @@ MipsSETargetLowering::emitINSERT_DF_VIDX(MachineInstr *MI, unsigned SrcValReg = MI->getOperand(3).getReg(); const TargetRegisterClass *VecRC = nullptr; - const TargetRegisterClass *GPRRC = isGP64bit() ? &Mips::GPR64RegClass - : &Mips::GPR32RegClass; + const TargetRegisterClass *GPRRC = + Subtarget->isGP64bit() ? &Mips::GPR64RegClass : &Mips::GPR32RegClass; unsigned EltLog2Size; unsigned InsertOp = 0; unsigned InsveOp = 0; diff --git a/lib/Target/Mips/MipsSEISelLowering.h b/lib/Target/Mips/MipsSEISelLowering.h index 03a20ef..13ef6fc 100644 --- a/lib/Target/Mips/MipsSEISelLowering.h +++ b/lib/Target/Mips/MipsSEISelLowering.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef MipsSEISELLOWERING_H -#define MipsSEISELLOWERING_H +#ifndef MIPSSEISELLOWERING_H +#define MIPSSEISELLOWERING_H #include "MipsISelLowering.h" #include "MipsRegisterInfo.h" @@ -46,13 +46,7 @@ namespace llvm { return false; } - const TargetRegisterClass *getRepRegClassFor(MVT VT) const override { - if (VT == MVT::Untyped) - return Subtarget->hasDSP() ? &Mips::ACC64DSPRegClass : - &Mips::ACC64RegClass; - - return TargetLowering::getRepRegClassFor(VT); - } + const TargetRegisterClass *getRepRegClassFor(MVT VT) const override; private: bool isEligibleForTailCallOptimization(const MipsCC &MipsCCInfo, diff --git a/lib/Target/Mips/MipsSEInstrInfo.cpp b/lib/Target/Mips/MipsSEInstrInfo.cpp index f6f364f..32da749 100644 --- a/lib/Target/Mips/MipsSEInstrInfo.cpp +++ b/lib/Target/Mips/MipsSEInstrInfo.cpp @@ -272,7 +272,7 @@ bool MipsSEInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { default: return false; case Mips::RetRA: - expandRetRA(MBB, MI, Mips::RET); + expandRetRA(MBB, MI); break; case Mips::PseudoMFHI: Opc = isMicroMips ? Mips::MFHI16_MM : Mips::MFHI; @@ -428,9 +428,14 @@ unsigned MipsSEInstrInfo::getAnalyzableBrOpc(unsigned Opc) const { } void MipsSEInstrInfo::expandRetRA(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, - unsigned Opc) const { - BuildMI(MBB, I, I->getDebugLoc(), get(Opc)).addReg(Mips::RA); + MachineBasicBlock::iterator I) const { + const auto &Subtarget = TM.getSubtarget<MipsSubtarget>(); + + if (Subtarget.isGP64bit()) + BuildMI(MBB, I, I->getDebugLoc(), get(Mips::PseudoReturn64)) + .addReg(Mips::RA_64); + else + BuildMI(MBB, I, I->getDebugLoc(), get(Mips::PseudoReturn)).addReg(Mips::RA); } std::pair<bool, bool> @@ -542,20 +547,31 @@ void MipsSEInstrInfo::expandBuildPairF64(MachineBasicBlock &MBB, const MCInstrDesc& Mtc1Tdd = get(Mips::MTC1); DebugLoc dl = I->getDebugLoc(); const TargetRegisterInfo &TRI = getRegisterInfo(); + bool HasMTHC1 = TM.getSubtarget<MipsSubtarget>().hasMips32r2() || + TM.getSubtarget<MipsSubtarget>().hasMips32r6(); - // For FP32 mode: - // mtc1 Lo, $fp - // mtc1 Hi, $fp + 1 - // For FP64 mode: + // When mthc1 is available, use: // mtc1 Lo, $fp // mthc1 Hi, $fp + // + // Otherwise, for FP64: + // spill + reload via ldc1 + // This has not been implemented since FP64 on MIPS32 and earlier is not + // supported. + // + // Otherwise, for FP32: + // mtc1 Lo, $fp + // mtc1 Hi, $fp + 1 BuildMI(MBB, I, dl, Mtc1Tdd, TRI.getSubReg(DstReg, Mips::sub_lo)) .addReg(LoReg); - if (FP64) { - // FIXME: The .addReg(DstReg, RegState::Implicit) is a white lie used to - // temporarily work around a widespread bug in the -mfp64 support. + if (HasMTHC1 || FP64) { + assert(TM.getSubtarget<MipsSubtarget>().hasMips32r2() && + "MTHC1 requires MIPS32r2"); + + // 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 @@ -565,9 +581,9 @@ void MipsSEInstrInfo::expandBuildPairF64(MachineBasicBlock &MBB, // We therefore pretend that it reads the bottom 32-bits to // artificially create a dependency and prevent the scheduler // changing the behaviour of the code. - BuildMI(MBB, I, dl, get(Mips::MTHC1), TRI.getSubReg(DstReg, Mips::sub_hi)) - .addReg(HiReg) - .addReg(DstReg, RegState::Implicit); + BuildMI(MBB, I, dl, get(FP64 ? Mips::MTHC1_D64 : Mips::MTHC1_D32), DstReg) + .addReg(DstReg) + .addReg(HiReg); } else BuildMI(MBB, I, dl, Mtc1Tdd, TRI.getSubReg(DstReg, Mips::sub_hi)) .addReg(HiReg); @@ -580,17 +596,16 @@ void MipsSEInstrInfo::expandEhReturn(MachineBasicBlock &MBB, // indirect jump to TargetReg const MipsSubtarget &STI = TM.getSubtarget<MipsSubtarget>(); unsigned ADDU = STI.isABI_N64() ? Mips::DADDu : Mips::ADDu; - unsigned JR = STI.isABI_N64() ? Mips::JR64 : Mips::JR; - unsigned SP = STI.isABI_N64() ? Mips::SP_64 : Mips::SP; - unsigned RA = STI.isABI_N64() ? Mips::RA_64 : Mips::RA; - unsigned T9 = STI.isABI_N64() ? Mips::T9_64 : Mips::T9; - unsigned ZERO = STI.isABI_N64() ? Mips::ZERO_64 : Mips::ZERO; + unsigned SP = STI.isGP64bit() ? Mips::SP_64 : Mips::SP; + unsigned RA = STI.isGP64bit() ? Mips::RA_64 : Mips::RA; + unsigned T9 = STI.isGP64bit() ? Mips::T9_64 : Mips::T9; + unsigned ZERO = STI.isGP64bit() ? Mips::ZERO_64 : Mips::ZERO; unsigned OffsetReg = I->getOperand(0).getReg(); unsigned TargetReg = I->getOperand(1).getReg(); // addu $ra, $v0, $zero // addu $sp, $sp, $v1 - // jr $ra + // jr $ra (via RetRA) if (TM.getRelocationModel() == Reloc::PIC_) BuildMI(MBB, I, I->getDebugLoc(), TM.getInstrInfo()->get(ADDU), T9) .addReg(TargetReg).addReg(ZERO); @@ -598,7 +613,7 @@ void MipsSEInstrInfo::expandEhReturn(MachineBasicBlock &MBB, .addReg(TargetReg).addReg(ZERO); BuildMI(MBB, I, I->getDebugLoc(), TM.getInstrInfo()->get(ADDU), SP) .addReg(SP).addReg(OffsetReg); - BuildMI(MBB, I, I->getDebugLoc(), TM.getInstrInfo()->get(JR)).addReg(RA); + expandRetRA(MBB, I); } const MipsInstrInfo *llvm::createMipsSEInstrInfo(MipsTargetMachine &TM) { diff --git a/lib/Target/Mips/MipsSEInstrInfo.h b/lib/Target/Mips/MipsSEInstrInfo.h index aa68552..9ac94ce 100644 --- a/lib/Target/Mips/MipsSEInstrInfo.h +++ b/lib/Target/Mips/MipsSEInstrInfo.h @@ -81,8 +81,7 @@ public: private: unsigned getAnalyzableBrOpc(unsigned Opc) const override; - void expandRetRA(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, - unsigned Opc) const; + void expandRetRA(MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; std::pair<bool, bool> compareOpndSize(unsigned Opc, const MachineFunction &MF) const; diff --git a/lib/Target/Mips/MipsSelectionDAGInfo.cpp b/lib/Target/Mips/MipsSelectionDAGInfo.cpp index 0d4398e..edd8f67 100644 --- a/lib/Target/Mips/MipsSelectionDAGInfo.cpp +++ b/lib/Target/Mips/MipsSelectionDAGInfo.cpp @@ -16,9 +16,8 @@ using namespace llvm; #define DEBUG_TYPE "mips-selectiondag-info" -MipsSelectionDAGInfo::MipsSelectionDAGInfo(const MipsTargetMachine &TM) - : TargetSelectionDAGInfo(TM) { -} +MipsSelectionDAGInfo::MipsSelectionDAGInfo(const DataLayout &DL) + : TargetSelectionDAGInfo(&DL) {} MipsSelectionDAGInfo::~MipsSelectionDAGInfo() { } diff --git a/lib/Target/Mips/MipsSelectionDAGInfo.h b/lib/Target/Mips/MipsSelectionDAGInfo.h index 6cafb55..2b3d527 100644 --- a/lib/Target/Mips/MipsSelectionDAGInfo.h +++ b/lib/Target/Mips/MipsSelectionDAGInfo.h @@ -22,7 +22,7 @@ class MipsTargetMachine; class MipsSelectionDAGInfo : public TargetSelectionDAGInfo { public: - explicit MipsSelectionDAGInfo(const MipsTargetMachine &TM); + explicit MipsSelectionDAGInfo(const DataLayout &DL); ~MipsSelectionDAGInfo(); }; diff --git a/lib/Target/Mips/MipsSubtarget.cpp b/lib/Target/Mips/MipsSubtarget.cpp index 74ec064..693daa3 100644 --- a/lib/Target/Mips/MipsSubtarget.cpp +++ b/lib/Target/Mips/MipsSubtarget.cpp @@ -60,11 +60,9 @@ Mips16ConstantIslands( /// Select the Mips CPU for the given triple and cpu name. /// FIXME: Merge with the copy in MipsMCTargetDesc.cpp -static inline StringRef selectMipsCPU(StringRef TT, StringRef CPU) { +static StringRef selectMipsCPU(Triple TT, StringRef CPU) { if (CPU.empty() || CPU == "generic") { - Triple TheTriple(TT); - if (TheTriple.getArch() == Triple::mips || - TheTriple.getArch() == Triple::mipsel) + if (TT.getArch() == Triple::mips || TT.getArch() == Triple::mipsel) CPU = "mips32"; else CPU = "mips64"; @@ -74,39 +72,56 @@ static inline StringRef selectMipsCPU(StringRef TT, StringRef CPU) { void MipsSubtarget::anchor() { } +static std::string computeDataLayout(const MipsSubtarget &ST) { + std::string Ret = ""; + + // There are both little and big endian mips. + if (ST.isLittle()) + Ret += "e"; + else + Ret += "E"; + + Ret += "-m:m"; + + // Pointers are 32 bit on some ABIs. + if (!ST.isABI_N64()) + Ret += "-p:32:32"; + + // 8 and 16 bit integers only need no have natural alignment, but try to + // align them to 32 bits. 64 bit integers have natural alignment. + Ret += "-i8:8:32-i16:16:32-i64:64"; + + // 32 bit registers are always available and the stack is at least 64 bit + // aligned. On N64 64 bit registers are also available and the stack is + // 128 bit aligned. + if (ST.isABI_N64() || ST.isABI_N32()) + Ret += "-n32:64-S128"; + else + Ret += "-n32-S64"; + + return Ret; +} + MipsSubtarget::MipsSubtarget(const std::string &TT, const std::string &CPU, const std::string &FS, bool little, Reloc::Model _RM, MipsTargetMachine *_TM) : MipsGenSubtargetInfo(TT, CPU, FS), MipsArchVersion(Mips32), MipsABI(UnknownABI), IsLittle(little), IsSingleFloat(false), - IsFP64bit(false), IsNaN2008bit(false), IsGP64bit(false), HasVFPU(false), - HasCnMips(false), IsLinux(true), HasMips3_32(false), HasMips3_32r2(false), - HasMips4_32(false), HasMips4_32r2(false), HasMips5_32r2(false), - InMips16Mode(false), InMips16HardFloat(Mips16HardFloat), - InMicroMipsMode(false), HasDSP(false), HasDSPR2(false), - AllowMixed16_32(Mixed16_32 | Mips_Os16), Os16(Mips_Os16), HasMSA(false), - RM(_RM), OverrideMode(NoOverride), TM(_TM), TargetTriple(TT) { - std::string CPUName = CPU; - CPUName = selectMipsCPU(TT, CPUName); - - // Parse features string. - ParseSubtargetFeatures(CPUName, FS); - - if (InMips16Mode && !TM->Options.UseSoftFloat) { - // Hard float for mips16 means essentially to compile as soft float - // but to use a runtime library for soft float that is written with - // native mips32 floating point instructions (those runtime routines - // run in mips32 hard float mode). - TM->Options.UseSoftFloat = true; - TM->Options.FloatABIType = FloatABI::Soft; - InMips16HardFloat = true; - } + IsFPXX(false), IsFP64bit(false), UseOddSPReg(true), IsNaN2008bit(false), + IsGP64bit(false), HasVFPU(false), HasCnMips(false), IsLinux(true), + HasMips3_32(false), HasMips3_32r2(false), HasMips4_32(false), + HasMips4_32r2(false), HasMips5_32r2(false), InMips16Mode(false), + InMips16HardFloat(Mips16HardFloat), InMicroMipsMode(false), HasDSP(false), + HasDSPR2(false), AllowMixed16_32(Mixed16_32 | Mips_Os16), Os16(Mips_Os16), + HasMSA(false), RM(_RM), OverrideMode(NoOverride), TM(_TM), + TargetTriple(TT), + DL(computeDataLayout(initializeSubtargetDependencies(CPU, FS, TM))), + TSInfo(DL), JITInfo(), InstrInfo(MipsInstrInfo::create(*TM)), + FrameLowering(MipsFrameLowering::create(*TM, *this)), + TLInfo(MipsTargetLowering::create(*TM)) { PreviousInMips16Mode = InMips16Mode; - // Initialize scheduling itinerary for the specified CPU. - InstrItins = getInstrItineraryForCPU(CPUName); - // Don't even attempt to generate code for MIPS-I, MIPS-II, MIPS-III, and // MIPS-V. They have not been tested and currently exist for the integrated // assembler only. @@ -137,6 +152,11 @@ MipsSubtarget::MipsSubtarget(const std::string &TT, const std::string &CPU, "See -mattr=+fp64.", false); + if (!isABI_O32() && !useOddSPReg()) + report_fatal_error("-mattr=+nooddspreg is not currently permitted for a " + "the O32 ABI.", + false); + if (hasMips32r6()) { StringRef ISA = hasMips64r6() ? "MIPS64r6" : "MIPS32r6"; @@ -167,6 +187,29 @@ MipsSubtarget::enablePostRAScheduler(CodeGenOpt::Level OptLevel, return OptLevel >= CodeGenOpt::Aggressive; } +MipsSubtarget & +MipsSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS, + const TargetMachine *TM) { + std::string CPUName = selectMipsCPU(TargetTriple, CPU); + + // Parse features string. + ParseSubtargetFeatures(CPUName, FS); + // Initialize scheduling itinerary for the specified CPU. + InstrItins = getInstrItineraryForCPU(CPUName); + + if (InMips16Mode && !TM->Options.UseSoftFloat) { + // Hard float for mips16 means essentially to compile as soft float + // but to use a runtime library for soft float that is written with + // native mips32 floating point instructions (those runtime routines + // run in mips32 hard float mode). + TM->Options.UseSoftFloat = true; + TM->Options.FloatABIType = FloatABI::Soft; + InMips16HardFloat = true; + } + + return *this; +} + //FIXME: This logic for reseting the subtarget along with // the helper classes can probably be simplified but there are a lot of // cases so we will defer rewriting this to later. @@ -186,14 +229,14 @@ void MipsSubtarget::resetSubtarget(MachineFunction *MF) { return; OverrideMode = Mips16Override; PreviousInMips16Mode = true; - TM->setHelperClassesMips16(); + setHelperClassesMips16(); return; } else if (ChangeToNoMips16) { if (!PreviousInMips16Mode) return; OverrideMode = NoMips16Override; PreviousInMips16Mode = false; - TM->setHelperClassesMipsSE(); + setHelperClassesMipsSE(); return; } else { if (OverrideMode == NoOverride) @@ -201,16 +244,52 @@ void MipsSubtarget::resetSubtarget(MachineFunction *MF) { OverrideMode = NoOverride; DEBUG(dbgs() << "back to default" << "\n"); if (inMips16Mode() && !PreviousInMips16Mode) { - TM->setHelperClassesMips16(); + setHelperClassesMips16(); PreviousInMips16Mode = true; } else if (!inMips16Mode() && PreviousInMips16Mode) { - TM->setHelperClassesMipsSE(); + setHelperClassesMipsSE(); PreviousInMips16Mode = false; } return; } } +void MipsSubtarget::setHelperClassesMips16() { + InstrInfoSE.swap(InstrInfo); + FrameLoweringSE.swap(FrameLowering); + TLInfoSE.swap(TLInfo); + if (!InstrInfo16) { + InstrInfo.reset(MipsInstrInfo::create(*TM)); + FrameLowering.reset(MipsFrameLowering::create(*TM, *this)); + TLInfo.reset(MipsTargetLowering::create(*TM)); + } else { + InstrInfo16.swap(InstrInfo); + FrameLowering16.swap(FrameLowering); + TLInfo16.swap(TLInfo); + } + assert(TLInfo && "null target lowering 16"); + assert(InstrInfo && "null instr info 16"); + assert(FrameLowering && "null frame lowering 16"); +} + +void MipsSubtarget::setHelperClassesMipsSE() { + InstrInfo16.swap(InstrInfo); + FrameLowering16.swap(FrameLowering); + TLInfo16.swap(TLInfo); + if (!InstrInfoSE) { + InstrInfo.reset(MipsInstrInfo::create(*TM)); + FrameLowering.reset(MipsFrameLowering::create(*TM, *this)); + TLInfo.reset(MipsTargetLowering::create(*TM)); + } else { + InstrInfoSE.swap(InstrInfo); + FrameLoweringSE.swap(FrameLowering); + TLInfoSE.swap(TLInfo); + } + assert(TLInfo && "null target lowering in SE"); + assert(InstrInfo && "null instr info SE"); + assert(FrameLowering && "null frame lowering SE"); +} + bool MipsSubtarget::mipsSEUsesSoftFloat() const { return TM->Options.UseSoftFloat && !InMips16HardFloat; } diff --git a/lib/Target/Mips/MipsSubtarget.h b/lib/Target/Mips/MipsSubtarget.h index 373f481..a3dcf03 100644 --- a/lib/Target/Mips/MipsSubtarget.h +++ b/lib/Target/Mips/MipsSubtarget.h @@ -14,6 +14,12 @@ #ifndef MIPSSUBTARGET_H #define MIPSSUBTARGET_H +#include "MipsFrameLowering.h" +#include "MipsISelLowering.h" +#include "MipsInstrInfo.h" +#include "MipsJITInfo.h" +#include "MipsSelectionDAGInfo.h" +#include "llvm/IR/DataLayout.h" #include "llvm/MC/MCInstrItineraries.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Target/TargetSubtargetInfo.h" @@ -56,9 +62,16 @@ protected: // floating point registers instead of only using even ones. bool IsSingleFloat; + // IsFPXX - MIPS O32 modeless ABI. + bool IsFPXX; + // IsFP64bit - The target processor has 64-bit floating point registers. bool IsFP64bit; + /// Are odd single-precision registers permitted? + /// This corresponds to -modd-spreg and -mno-odd-spreg + bool UseOddSPReg; + // IsNan2008 - IEEE 754-2008 NaN encoding. bool IsNaN2008bit; @@ -132,6 +145,20 @@ protected: MipsTargetMachine *TM; Triple TargetTriple; + + const DataLayout DL; // Calculates type size & alignment + const MipsSelectionDAGInfo TSInfo; + MipsJITInfo JITInfo; + std::unique_ptr<const MipsInstrInfo> InstrInfo; + std::unique_ptr<const MipsFrameLowering> FrameLowering; + std::unique_ptr<const MipsTargetLowering> TLInfo; + std::unique_ptr<const MipsInstrInfo> InstrInfo16; + std::unique_ptr<const MipsFrameLowering> FrameLowering16; + std::unique_ptr<const MipsTargetLowering> TLInfo16; + std::unique_ptr<const MipsInstrInfo> InstrInfoSE; + std::unique_ptr<const MipsFrameLowering> FrameLoweringSE; + std::unique_ptr<const MipsTargetLowering> TLInfoSE; + public: bool enablePostRAScheduler(CodeGenOpt::Level OptLevel, AntiDepBreakMode& Mode, @@ -142,6 +169,7 @@ public: bool isABI_N64() const { return MipsABI == N64; } bool isABI_N32() const { return MipsABI == N32; } bool isABI_O32() const { return MipsABI == O32; } + bool isABI_FPXX() const { return false; } // TODO: add check for FPXX unsigned getTargetABI() const { return MipsABI; } /// This constructor initializes the data members to match that @@ -154,23 +182,36 @@ public: /// 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; } - bool hasMips32r2() const { return MipsArchVersion == Mips32r2 || - MipsArchVersion == Mips64r2; } - bool hasMips32r6() const { return MipsArchVersion == Mips32r6 || - MipsArchVersion == Mips64r6; } + bool hasMips32() const { + return MipsArchVersion >= Mips32 && MipsArchVersion != Mips3 && + MipsArchVersion != Mips4 && MipsArchVersion != Mips5; + } + bool hasMips32r2() const { + return MipsArchVersion == Mips32r2 || MipsArchVersion == Mips32r6 || + MipsArchVersion == Mips64r2 || MipsArchVersion == Mips64r6; + } + bool hasMips32r6() const { + return MipsArchVersion == Mips32r6 || MipsArchVersion == Mips64r6; + } bool hasMips64() const { return MipsArchVersion >= Mips64; } - bool hasMips64r2() const { return MipsArchVersion == Mips64r2; } + bool hasMips64r2() const { + return MipsArchVersion == Mips64r2 || MipsArchVersion == Mips64r6; + } bool hasMips64r6() const { return MipsArchVersion == Mips64r6; } bool hasCnMips() const { return HasCnMips; } bool isLittle() const { return IsLittle; } + bool isFPXX() const { return IsFPXX; } bool isFP64bit() const { return IsFP64bit; } + bool useOddSPReg() const { return UseOddSPReg; } bool isNaN2008() const { return IsNaN2008bit; } bool isNotFP64bit() const { return !IsFP64bit; } bool isGP64bit() const { return IsGP64bit; } @@ -234,12 +275,31 @@ public: /// \brief Reset the subtarget for the Mips target. void resetSubtarget(MachineFunction *MF); + 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(); + + MipsJITInfo *getJITInfo() { return &JITInfo; } + const MipsSelectionDAGInfo *getSelectionDAGInfo() const { return &TSInfo; } + const DataLayout *getDataLayout() const { return &DL; } + const MipsInstrInfo *getInstrInfo() const { return InstrInfo.get(); } + const TargetFrameLowering *getFrameLowering() const { + return FrameLowering.get(); + } + const MipsRegisterInfo *getRegisterInfo() const { + return &InstrInfo->getRegisterInfo(); + } + const MipsTargetLowering *getTargetLowering() const { return TLInfo.get(); } }; } // End llvm namespace diff --git a/lib/Target/Mips/MipsTargetMachine.cpp b/lib/Target/Mips/MipsTargetMachine.cpp index 984c58e..425dbf1 100644 --- a/lib/Target/Mips/MipsTargetMachine.cpp +++ b/lib/Target/Mips/MipsTargetMachine.cpp @@ -45,93 +45,21 @@ extern "C" void LLVMInitializeMipsTarget() { RegisterTargetMachine<MipselTargetMachine> B(TheMips64elTarget); } -static std::string computeDataLayout(const MipsSubtarget &ST) { - std::string Ret = ""; - - // There are both little and big endian mips. - if (ST.isLittle()) - Ret += "e"; - else - Ret += "E"; - - Ret += "-m:m"; - - // Pointers are 32 bit on some ABIs. - if (!ST.isABI_N64()) - Ret += "-p:32:32"; - - // 8 and 16 bit integers only need no have natural alignment, but try to - // align them to 32 bits. 64 bit integers have natural alignment. - Ret += "-i8:8:32-i16:16:32-i64:64"; - - // 32 bit registers are always available and the stack is at least 64 bit - // aligned. On N64 64 bit registers are also available and the stack is - // 128 bit aligned. - if (ST.isABI_N64() || ST.isABI_N32()) - Ret += "-n32:64-S128"; - else - Ret += "-n32-S64"; - - return Ret; -} - // On function prologue, the stack is created by decrementing // its pointer. Once decremented, all references are done with positive // offset from the stack/frame pointer, using StackGrowsUp enables // an easier handling. // Using CodeModel::Large enables different CALL behavior. -MipsTargetMachine:: -MipsTargetMachine(const Target &T, StringRef TT, - StringRef CPU, StringRef FS, const TargetOptions &Options, - Reloc::Model RM, CodeModel::Model CM, - CodeGenOpt::Level OL, - bool isLittle) - : LLVMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL), - Subtarget(TT, CPU, FS, isLittle, RM, this), - DL(computeDataLayout(Subtarget)), - InstrInfo(MipsInstrInfo::create(*this)), - FrameLowering(MipsFrameLowering::create(*this, Subtarget)), - TLInfo(MipsTargetLowering::create(*this)), TSInfo(*this), - InstrItins(Subtarget.getInstrItineraryData()), JITInfo() { +MipsTargetMachine::MipsTargetMachine(const Target &T, StringRef TT, + StringRef CPU, StringRef FS, + const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL, bool isLittle) + : LLVMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL), + Subtarget(TT, CPU, FS, isLittle, RM, this) { initAsmInfo(); } - -void MipsTargetMachine::setHelperClassesMips16() { - InstrInfoSE.swap(InstrInfo); - FrameLoweringSE.swap(FrameLowering); - TLInfoSE.swap(TLInfo); - if (!InstrInfo16) { - InstrInfo.reset(MipsInstrInfo::create(*this)); - FrameLowering.reset(MipsFrameLowering::create(*this, Subtarget)); - TLInfo.reset(MipsTargetLowering::create(*this)); - } else { - InstrInfo16.swap(InstrInfo); - FrameLowering16.swap(FrameLowering); - TLInfo16.swap(TLInfo); - } - assert(TLInfo && "null target lowering 16"); - assert(InstrInfo && "null instr info 16"); - assert(FrameLowering && "null frame lowering 16"); -} - -void MipsTargetMachine::setHelperClassesMipsSE() { - InstrInfo16.swap(InstrInfo); - FrameLowering16.swap(FrameLowering); - TLInfo16.swap(TLInfo); - if (!InstrInfoSE) { - InstrInfo.reset(MipsInstrInfo::create(*this)); - FrameLowering.reset(MipsFrameLowering::create(*this, Subtarget)); - TLInfo.reset(MipsTargetLowering::create(*this)); - } else { - InstrInfoSE.swap(InstrInfo); - FrameLoweringSE.swap(FrameLowering); - TLInfoSE.swap(TLInfo); - } - assert(TLInfo && "null target lowering in SE"); - assert(InstrInfo && "null instr info SE"); - assert(FrameLowering && "null frame lowering SE"); -} void MipsebTargetMachine::anchor() { } MipsebTargetMachine:: diff --git a/lib/Target/Mips/MipsTargetMachine.h b/lib/Target/Mips/MipsTargetMachine.h index a5aa39b..a0e7d43 100644 --- a/lib/Target/Mips/MipsTargetMachine.h +++ b/lib/Target/Mips/MipsTargetMachine.h @@ -14,15 +14,9 @@ #ifndef MIPSTARGETMACHINE_H #define MIPSTARGETMACHINE_H -#include "MipsFrameLowering.h" -#include "MipsISelLowering.h" -#include "MipsInstrInfo.h" -#include "MipsJITInfo.h" -#include "MipsSelectionDAGInfo.h" #include "MipsSubtarget.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/SelectionDAGISel.h" -#include "llvm/IR/DataLayout.h" #include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetMachine.h" @@ -32,68 +26,47 @@ class MipsRegisterInfo; class MipsTargetMachine : public LLVMTargetMachine { MipsSubtarget Subtarget; - const DataLayout DL; // Calculates type size & alignment - std::unique_ptr<const MipsInstrInfo> InstrInfo; - std::unique_ptr<const MipsFrameLowering> FrameLowering; - std::unique_ptr<const MipsTargetLowering> TLInfo; - std::unique_ptr<const MipsInstrInfo> InstrInfo16; - std::unique_ptr<const MipsFrameLowering> FrameLowering16; - std::unique_ptr<const MipsTargetLowering> TLInfo16; - std::unique_ptr<const MipsInstrInfo> InstrInfoSE; - std::unique_ptr<const MipsFrameLowering> FrameLoweringSE; - std::unique_ptr<const MipsTargetLowering> TLInfoSE; - MipsSelectionDAGInfo TSInfo; - const InstrItineraryData &InstrItins; - MipsJITInfo JITInfo; public: - MipsTargetMachine(const Target &T, StringRef TT, - StringRef CPU, StringRef FS, const TargetOptions &Options, - Reloc::Model RM, CodeModel::Model CM, - CodeGenOpt::Level OL, - bool isLittle); + MipsTargetMachine(const Target &T, StringRef TT, StringRef CPU, StringRef FS, + const TargetOptions &Options, Reloc::Model RM, + CodeModel::Model CM, CodeGenOpt::Level OL, bool isLittle); virtual ~MipsTargetMachine() {} void addAnalysisPasses(PassManagerBase &PM) override; - const MipsInstrInfo *getInstrInfo() const override - { return InstrInfo.get(); } - const TargetFrameLowering *getFrameLowering() const override - { return FrameLowering.get(); } - const MipsSubtarget *getSubtargetImpl() const override - { return &Subtarget; } - const DataLayout *getDataLayout() const override - { return &DL;} - + const MipsInstrInfo *getInstrInfo() const override { + return getSubtargetImpl()->getInstrInfo(); + } + const TargetFrameLowering *getFrameLowering() const override { + return getSubtargetImpl()->getFrameLowering(); + } + const MipsSubtarget *getSubtargetImpl() const override { return &Subtarget; } const InstrItineraryData *getInstrItineraryData() const override { - return Subtarget.inMips16Mode() ? nullptr : &InstrItins; + return Subtarget.inMips16Mode() + ? nullptr + : &getSubtargetImpl()->getInstrItineraryData(); + } + MipsJITInfo *getJITInfo() override { + return Subtarget.getJITInfo(); } - - MipsJITInfo *getJITInfo() override { return &JITInfo; } - const MipsRegisterInfo *getRegisterInfo() const override { - return &InstrInfo->getRegisterInfo(); + return getSubtargetImpl()->getRegisterInfo(); } - const MipsTargetLowering *getTargetLowering() const override { - return TLInfo.get(); + return getSubtargetImpl()->getTargetLowering(); + } + const DataLayout *getDataLayout() const override { + return getSubtargetImpl()->getDataLayout(); } - const MipsSelectionDAGInfo* getSelectionDAGInfo() const override { - return &TSInfo; + return getSubtargetImpl()->getSelectionDAGInfo(); } // Pass Pipeline Configuration TargetPassConfig *createPassConfig(PassManagerBase &PM) override; bool addCodeEmitter(PassManagerBase &PM, JITCodeEmitter &JCE) override; - - // Set helper classes - void setHelperClassesMips16(); - - void setHelperClassesMipsSE(); - - }; /// MipsebTargetMachine - Mips32/64 big endian target machine. diff --git a/lib/Target/Mips/MipsTargetStreamer.h b/lib/Target/Mips/MipsTargetStreamer.h index 4ad37ac..99f7d4c 100644 --- a/lib/Target/Mips/MipsTargetStreamer.h +++ b/lib/Target/Mips/MipsTargetStreamer.h @@ -12,46 +12,83 @@ #include "llvm/MC/MCELFStreamer.h" #include "llvm/MC/MCStreamer.h" +#include "MCTargetDesc/MipsABIFlagsSection.h" namespace llvm { -class MipsTargetStreamer : public MCTargetStreamer { - virtual void anchor(); +struct MipsABIFlagsSection; + +class MipsTargetStreamer : public MCTargetStreamer { public: MipsTargetStreamer(MCStreamer &S); - virtual void emitDirectiveSetMicroMips() = 0; - virtual void emitDirectiveSetNoMicroMips() = 0; - virtual void emitDirectiveSetMips16() = 0; - virtual void emitDirectiveSetNoMips16() = 0; - - virtual void emitDirectiveSetReorder() = 0; - virtual void emitDirectiveSetNoReorder() = 0; - virtual void emitDirectiveSetMacro() = 0; - virtual void emitDirectiveSetNoMacro() = 0; - virtual void emitDirectiveSetAt() = 0; - virtual void emitDirectiveSetNoAt() = 0; - virtual void emitDirectiveEnd(StringRef Name) = 0; - - virtual void emitDirectiveEnt(const MCSymbol &Symbol) = 0; - virtual void emitDirectiveAbiCalls() = 0; - virtual void emitDirectiveNaN2008() = 0; - virtual void emitDirectiveNaNLegacy() = 0; - virtual void emitDirectiveOptionPic0() = 0; - virtual void emitDirectiveOptionPic2() = 0; + virtual void emitDirectiveSetMicroMips(); + virtual void emitDirectiveSetNoMicroMips(); + virtual void emitDirectiveSetMips16(); + virtual void emitDirectiveSetNoMips16(); + + virtual void emitDirectiveSetReorder(); + virtual void emitDirectiveSetNoReorder(); + virtual void emitDirectiveSetMacro(); + virtual void emitDirectiveSetNoMacro(); + virtual void emitDirectiveSetAt(); + virtual void emitDirectiveSetNoAt(); + virtual void emitDirectiveEnd(StringRef Name); + + virtual void emitDirectiveEnt(const MCSymbol &Symbol); + virtual void emitDirectiveAbiCalls(); + virtual void emitDirectiveNaN2008(); + virtual void emitDirectiveNaNLegacy(); + virtual void emitDirectiveOptionPic0(); + virtual void emitDirectiveOptionPic2(); virtual void emitFrame(unsigned StackReg, unsigned StackSize, - unsigned ReturnReg) = 0; - virtual void emitMask(unsigned CPUBitmask, int CPUTopSavedRegOff) = 0; - virtual void emitFMask(unsigned FPUBitmask, int FPUTopSavedRegOff) = 0; + unsigned ReturnReg); + virtual void emitMask(unsigned CPUBitmask, int CPUTopSavedRegOff); + virtual void emitFMask(unsigned FPUBitmask, int FPUTopSavedRegOff); - virtual void emitDirectiveSetMips32R2() = 0; - virtual void emitDirectiveSetMips64() = 0; - virtual void emitDirectiveSetMips64R2() = 0; - virtual void emitDirectiveSetDsp() = 0; + virtual void emitDirectiveSetMips32R2(); + virtual void emitDirectiveSetMips64(); + virtual void emitDirectiveSetMips64R2(); + virtual void emitDirectiveSetDsp(); // PIC support - virtual void emitDirectiveCpload(unsigned RegNo) = 0; + virtual void emitDirectiveCpload(unsigned RegNo); virtual void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, - const MCSymbol &Sym, bool IsReg) = 0; + const MCSymbol &Sym, bool IsReg); + + /// Emit a '.module fp=value' directive using the given values. + /// Updates the .MIPS.abiflags section + virtual void emitDirectiveModuleFP(MipsABIFlagsSection::FpABIKind Value, + bool Is32BitABI) { + ABIFlagsSection.setFpABI(Value, Is32BitABI); + } + + /// Emit a '.module fp=value' directive using the current values of the + /// .MIPS.abiflags section. + void emitDirectiveModuleFP() { + emitDirectiveModuleFP(ABIFlagsSection.getFpABI(), + ABIFlagsSection.Is32BitABI); + } + + virtual void emitDirectiveModuleOddSPReg(bool Enabled, bool IsO32ABI); + virtual void emitDirectiveSetFp(MipsABIFlagsSection::FpABIKind Value){}; + virtual void emitMipsAbiFlags(){}; + void setCanHaveModuleDir(bool Can) { canHaveModuleDirective = Can; } + bool getCanHaveModuleDir() { return canHaveModuleDirective; } + + // This method enables template classes to set internal abi flags + // structure values. + template <class PredicateLibrary> + void updateABIInfo(const PredicateLibrary &P) { + ABIFlagsSection.setAllFromPredicates(P); + } + + MipsABIFlagsSection &getABIFlagsSection() { return ABIFlagsSection; } + +protected: + MipsABIFlagsSection ABIFlagsSection; + +private: + bool canHaveModuleDirective; }; // This part is for ascii assembly output @@ -93,6 +130,13 @@ public: virtual void emitDirectiveCpload(unsigned RegNo); void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, const MCSymbol &Sym, bool IsReg) override; + + // ABI Flags + void emitDirectiveModuleFP(MipsABIFlagsSection::FpABIKind Value, + bool Is32BitABI) override; + void emitDirectiveModuleOddSPReg(bool Enabled, bool IsO32ABI) override; + void emitDirectiveSetFp(MipsABIFlagsSection::FpABIKind Value) override; + void emitMipsAbiFlags() override; }; // This part is for ELF object output @@ -144,6 +188,10 @@ public: void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, const MCSymbol &Sym, bool IsReg) override; + // ABI Flags + void emitDirectiveModuleOddSPReg(bool Enabled, bool IsO32ABI) override; + void emitMipsAbiFlags() override; + protected: bool isO32() const { return STI.getFeatureBits() & Mips::FeatureO32; } bool isN32() const { return STI.getFeatureBits() & Mips::FeatureN32; } |