Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -165,7 +165,8 @@ bool parseDirectiveGpDWord(); bool parseDirectiveModule(); bool parseDirectiveModuleFP(); - bool parseFpABIValue(Val_GNU_MIPS_ABI &FpABI, StringRef Directive); + bool parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI, + StringRef Directive); MCSymbolRefExpr::VariantKind getVariantKind(StringRef Symbol); @@ -235,6 +236,9 @@ ((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; } @@ -250,6 +254,10 @@ 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; } @@ -563,6 +571,10 @@ 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 { @@ -2444,7 +2456,7 @@ } bool MipsAsmParser::parseSetFpDirective() { - Val_GNU_MIPS_ABI FpAbiVal; + MipsABIFlagsSection::FpABIKind FpAbiVal; // Line can be: .set fp=32 // .set fp=xx // .set fp=64 @@ -2464,7 +2476,7 @@ reportParseError("unexpected token in statement"); return false; } - getTargetStreamer().emitDirectiveSetFp(FpAbiVal, isABI_O32()); + getTargetStreamer().emitDirectiveSetFp(FpAbiVal); Parser.Lex(); // Consume the EndOfStatement. return false; } @@ -2784,29 +2796,73 @@ return false; } +/// parseDirectiveModule +/// ::= .module oddspreg +/// ::= .module nooddspreg +/// ::= .module fp=value bool MipsAsmParser::parseDirectiveModule() { - // Line can be: .module fp=32 - // .module fp=xx - // .module fp=64 + 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; } - AsmToken Tok = Parser.getTok(); - if (Tok.isNot(AsmToken::Identifier) && Tok.getString() != "fp") { - reportParseError("unexpected token in .module directive, 'fp' expected"); - 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."); } - Parser.Lex(); // Eat fp token - Tok = Parser.getTok(); - if (Tok.isNot(AsmToken::Equal)) { + + 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. - Val_GNU_MIPS_ABI FpABI; + MipsABIFlagsSection::FpABIKind FpABI; if (!parseFpABIValue(FpABI, ".module")) return false; @@ -2817,11 +2873,11 @@ // Emit appropriate flags. getTargetStreamer().emitDirectiveModuleFP(FpABI, isABI_O32()); - + Parser.Lex(); // Consume the EndOfStatement. return false; } -bool MipsAsmParser::parseFpABIValue(Val_GNU_MIPS_ABI &FpABI, +bool MipsAsmParser::parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI, StringRef Directive) { MCAsmLexer &Lexer = getLexer(); @@ -2839,7 +2895,7 @@ return false; } - FpABI = MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_XX; + FpABI = MipsABIFlagsSection::FpABIKind::XX; return true; } @@ -2858,21 +2914,11 @@ return false; } - FpABI = MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_DOUBLE; - return true; - } else { - if (isABI_N32() || isABI_N64()) { - FpABI = MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_DOUBLE; - return true; - } + FpABI = MipsABIFlagsSection::FpABIKind::S32; + } else + FpABI = MipsABIFlagsSection::FpABIKind::S64; - if (isABI_O32()) { - FpABI = MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_64; - return true; - } - - llvm_unreachable("Unknown ABI"); - } + return true; } return false; Index: lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h +++ lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h @@ -69,9 +69,17 @@ 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_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. @@ -84,31 +92,52 @@ AFL_REG CPR1Size; // The size of co-processor 2 registers. AFL_REG CPR2Size; - // The floating-point ABI. - Val_GNU_MIPS_ABI FpABI; // 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), - FpABI(Val_GNU_MIPS_ABI_FP_ANY), ISAExtensionSet(0), ASESet(0) {} - - uint16_t getVersion() { return (uint16_t)Version; } - uint8_t getISALevel() { return (uint8_t)ISALevel; } - uint8_t getISARevision() { return (uint8_t)ISARevision; } - uint8_t getGPRSize() { return (uint8_t)GPRSize; } - uint8_t getCPR1Size() { return (uint8_t)CPR1Size; } - uint8_t getCPR2Size() { return (uint8_t)CPR2Size; } - uint8_t getFpABI() { return (uint8_t)FpABI; } - uint32_t getISAExtensionSet() { return (uint32_t)ISAExtensionSet; } - uint32_t getASESet() { return (uint32_t)ASESet; } - uint32_t getFlags1() { return 0; } - uint32_t getFlags2() { return 0; } - - StringRef getFpABIString(Val_GNU_MIPS_ABI Value, bool Is32BitAbi); + 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 void setISALevelAndRevisionFromPredicates(const PredicateLibrary &P) { @@ -177,16 +206,18 @@ template void setFpAbiFromPredicates(const PredicateLibrary &P) { - FpABI = Val_GNU_MIPS_ABI_FP_ANY; + Is32BitABI = P.isABI_O32(); + + FpABI = FpABIKind::ANY; if (P.isABI_N32() || P.isABI_N64()) - FpABI = Val_GNU_MIPS_ABI_FP_DOUBLE; + FpABI = FpABIKind::S64; else if (P.isABI_O32()) { if (P.isFP64bit()) - FpABI = Val_GNU_MIPS_ABI_FP_64; + FpABI = FpABIKind::S64; else if (P.isABI_FPXX()) - FpABI = Val_GNU_MIPS_ABI_FP_XX; + FpABI = FpABIKind::XX; else - FpABI = Val_GNU_MIPS_ABI_FP_DOUBLE; + FpABI = FpABIKind::S32; } } Index: lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.cpp +++ lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.cpp @@ -11,16 +11,30 @@ using namespace llvm; -StringRef MipsABIFlagsSection::getFpABIString(Val_GNU_MIPS_ABI Value, - bool Is32BitAbi) { +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; + default: + return 0; + } +} + +StringRef MipsABIFlagsSection::getFpABIString(FpABIKind Value) { switch (Value) { - case MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_XX: + case FpABIKind::XX: return "xx"; - case MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_64: - return "64"; - case MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_DOUBLE: - if (Is32BitAbi) - return "32"; + case FpABIKind::S32: + return "32"; + case FpABIKind::S64: return "64"; default: llvm_unreachable("unsupported fp abi value"); @@ -30,17 +44,17 @@ namespace llvm { MCStreamer &operator<<(MCStreamer &OS, MipsABIFlagsSection &ABIFlagsSection) { // Write out a Elf_Internal_ABIFlags_v0 struct - OS.EmitIntValue(ABIFlagsSection.getVersion(), 2); // version - OS.EmitIntValue(ABIFlagsSection.getISALevel(), 1); // isa_level - OS.EmitIntValue(ABIFlagsSection.getISARevision(), 1); // isa_rev - OS.EmitIntValue(ABIFlagsSection.getGPRSize(), 1); // gpr_size - OS.EmitIntValue(ABIFlagsSection.getCPR1Size(), 1); // cpr1_size - OS.EmitIntValue(ABIFlagsSection.getCPR2Size(), 1); // cpr2_size - OS.EmitIntValue(ABIFlagsSection.getFpABI(), 1); // fp_abi - OS.EmitIntValue(ABIFlagsSection.getISAExtensionSet(), 4); // isa_ext - OS.EmitIntValue(ABIFlagsSection.getASESet(), 4); // ases - OS.EmitIntValue(ABIFlagsSection.getFlags1(), 4); // flags1 - OS.EmitIntValue(ABIFlagsSection.getFlags2(), 4); // flags2 + 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; } } Index: lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -59,6 +59,11 @@ 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) @@ -211,26 +216,33 @@ setCanHaveModuleDir(false); } -void MipsTargetAsmStreamer::emitDirectiveModuleFP(Val_GNU_MIPS_ABI Value, - bool Is32BitAbi) { - MipsTargetStreamer::emitDirectiveModuleFP(Value, Is32BitAbi); +void MipsTargetAsmStreamer::emitDirectiveModuleFP( + MipsABIFlagsSection::FpABIKind Value, bool Is32BitABI) { + MipsTargetStreamer::emitDirectiveModuleFP(Value, Is32BitABI); StringRef ModuleValue; OS << "\t.module\tfp="; - OS << ABIFlagsSection.getFpABIString(Value, Is32BitAbi) << "\n"; + OS << ABIFlagsSection.getFpABIString(Value) << "\n"; } -void MipsTargetAsmStreamer::emitDirectiveSetFp(Val_GNU_MIPS_ABI Value, - bool Is32BitAbi) { +void MipsTargetAsmStreamer::emitDirectiveSetFp( + MipsABIFlagsSection::FpABIKind Value) { StringRef ModuleValue; OS << "\t.set\tfp="; - OS << ABIFlagsSection.getFpABIString(Value, Is32BitAbi) << "\n"; + OS << ABIFlagsSection.getFpABIString(Value) << "\n"; } void MipsTargetAsmStreamer::emitMipsAbiFlags() { // No action required for text output. } +void MipsTargetAsmStreamer::emitDirectiveModuleOddSPReg(bool Enabled, + bool IsO32ABI) { + MipsTargetStreamer::emitDirectiveModuleOddSPReg(Enabled, IsO32ABI); + + OS << "\t.module\t" << (Enabled ? "" : "no") << "oddspreg\n"; +} + // This part is for ELF object output. MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI) @@ -633,3 +645,10 @@ OS << ABIFlagsSection; } + +void MipsTargetELFStreamer::emitDirectiveModuleOddSPReg(bool Enabled, + bool IsO32ABI) { + MipsTargetStreamer::emitDirectiveModuleOddSPReg(Enabled, IsO32ABI); + + ABIFlagsSection.OddSPReg = Enabled; +} Index: lib/Target/Mips/Mips.td =================================================================== --- lib/Target/Mips/Mips.td +++ lib/Target/Mips/Mips.td @@ -73,6 +73,9 @@ "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", Index: lib/Target/Mips/MipsAsmPrinter.cpp =================================================================== --- lib/Target/Mips/MipsAsmPrinter.cpp +++ lib/Target/Mips/MipsAsmPrinter.cpp @@ -704,9 +704,13 @@ OutContext.getELFSection(".gcc_compiled_long64", ELF::SHT_PROGBITS, 0, SectionKind::getDataRel())); } + getTargetStreamer().updateABIInfo(*Subtarget); - getTargetStreamer().emitDirectiveModuleFP( - getTargetStreamer().getABIFlagsSection().FpABI, Subtarget->isABI_O32()); + getTargetStreamer().emitDirectiveModuleFP(); + + if (Subtarget->isABI_O32()) + getTargetStreamer().emitDirectiveModuleOddSPReg(Subtarget->useOddSPReg(), + Subtarget->isABI_O32()); } void MipsAsmPrinter::EmitJal(MCSymbol *Symbol) { Index: lib/Target/Mips/MipsRegisterInfo.cpp =================================================================== --- lib/Target/Mips/MipsRegisterInfo.cpp +++ lib/Target/Mips/MipsRegisterInfo.cpp @@ -201,6 +201,11 @@ Reserved.set(Mips::GP_64); } + if (Subtarget.isABI_O32() && !Subtarget.useOddSPReg()) { + for (const auto &Reg : Mips::OddSPRegClass) + Reserved.set(Reg); + } + return Reserved; } Index: lib/Target/Mips/MipsRegisterInfo.td =================================================================== --- lib/Target/Mips/MipsRegisterInfo.td +++ lib/Target/Mips/MipsRegisterInfo.td @@ -340,6 +340,12 @@ 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; Index: lib/Target/Mips/MipsSubtarget.h =================================================================== --- lib/Target/Mips/MipsSubtarget.h +++ lib/Target/Mips/MipsSubtarget.h @@ -65,6 +65,10 @@ // 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; @@ -203,6 +207,7 @@ bool isLittle() const { return IsLittle; } 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; } Index: lib/Target/Mips/MipsSubtarget.cpp =================================================================== --- lib/Target/Mips/MipsSubtarget.cpp +++ lib/Target/Mips/MipsSubtarget.cpp @@ -107,13 +107,14 @@ 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), + 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)), @@ -151,6 +152,11 @@ "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"; Index: lib/Target/Mips/MipsTargetStreamer.h =================================================================== --- lib/Target/Mips/MipsTargetStreamer.h +++ lib/Target/Mips/MipsTargetStreamer.h @@ -18,8 +18,6 @@ struct MipsABIFlagsSection; -typedef MipsABIFlagsSection::Val_GNU_MIPS_ABI Val_GNU_MIPS_ABI; - class MipsTargetStreamer : public MCTargetStreamer { public: MipsTargetStreamer(MCStreamer &S); @@ -56,11 +54,23 @@ virtual void emitDirectiveCpload(unsigned RegNo); virtual void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, const MCSymbol &Sym, bool IsReg); - // ABI Flags - virtual void emitDirectiveModuleFP(Val_GNU_MIPS_ABI Value, bool Is32BitAbi) { - ABIFlagsSection.FpABI = Value; + + /// 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); } - virtual void emitDirectiveSetFp(Val_GNU_MIPS_ABI Value, bool 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; } @@ -122,8 +132,10 @@ const MCSymbol &Sym, bool IsReg) override; // ABI Flags - void emitDirectiveModuleFP(Val_GNU_MIPS_ABI Value, bool Is32BitAbi) override; - void emitDirectiveSetFp(Val_GNU_MIPS_ABI Value, bool Is32BitAbi) override; + void emitDirectiveModuleFP(MipsABIFlagsSection::FpABIKind Value, + bool Is32BitABI) override; + void emitDirectiveModuleOddSPReg(bool Enabled, bool IsO32ABI) override; + void emitDirectiveSetFp(MipsABIFlagsSection::FpABIKind Value) override; void emitMipsAbiFlags() override; }; @@ -177,6 +189,7 @@ const MCSymbol &Sym, bool IsReg) override; // ABI Flags + void emitDirectiveModuleOddSPReg(bool Enabled, bool IsO32ABI) override; void emitMipsAbiFlags() override; protected: Index: test/CodeGen/Mips/no-odd-spreg.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/no-odd-spreg.ll @@ -0,0 +1,54 @@ +; RUN: llc -march=mipsel -mcpu=mips32 < %s | FileCheck %s -check-prefix=ALL -check-prefix=ODDSPREG +; RUN: llc -march=mipsel -mcpu=mips32 -mattr=+nooddspreg < %s | FileCheck %s -check-prefix=ALL -check-prefix=NOODDSPREG +; RUN: llc -march=mipsel -mcpu=mips32r6 -mattr=fp64 < %s | FileCheck %s -check-prefix=ALL -check-prefix=ODDSPREG +; RUN: llc -march=mipsel -mcpu=mips32r6 -mattr=fp64,+nooddspreg < %s | FileCheck %s -check-prefix=ALL -check-prefix=NOODDSPREG + +; ODDSPREG: .module oddspreg +; NOODDSPREG: .module nooddspreg + +define float @two_floats(float %a) { +entry: + ; Clobber all except $f12 and $f13 + ; + ; The intention is that if odd single precision registers are permitted, the + ; allocator will choose $f12 and $f13 to avoid the spill/reload. + ; + ; On the other hand, if odd single precision registers are not permitted, it + ; will be forced to spill/reload either %a or %0. + + %0 = fadd float %a, 1.0 + call void asm "# Clobber", "~{$f0},~{$f1},~{$f2},~{$f3},~{$f4},~{$f5},~{$f6},~{$f7},~{$f8},~{$f9},~{$f10},~{$f11},~{$f14},~{$f15},~{$f16},~{$f17},~{$f18},~{$f19},~{$f20},~{$f21},~{$f22},~{$f23},~{$f24},~{$f25},~{$f26},~{$f27},~{$f28},~{$f29},~{$f30},~{$f31}"() + %1 = fadd float %a, %0 + ret float %1 +} + +; ALL-LABEL: two_floats: +; ODDSPREG: add.s $f13, $f12, ${{f[0-9]+}} +; ODDSPREG-NOT: swc1 +; ODDSPREG-NOT: lwc1 +; ODDSPREG: add.s $f0, $f12, $f13 + +; NOODDSPREG: add.s $[[T0:f[0-9]*[02468]]], $f12, ${{f[0-9]+}} +; NOODDSPREG: swc1 $[[T0]], +; NOODDSPREG: lwc1 $[[T1:f[0-9]*[02468]]], +; NOODDSPREG: add.s $f0, $f12, $[[T1]] + +define double @two_doubles(double %a) { +entry: + ; Clobber all except $f12 and $f13 + ; + ; -mno-odd-sp-reg doesn't need to affect double precision values so both cases + ; use $f12 and $f13. + + %0 = fadd double %a, 1.0 + call void asm "# Clobber", "~{$f0},~{$f1},~{$f2},~{$f3},~{$f4},~{$f5},~{$f6},~{$f7},~{$f8},~{$f9},~{$f10},~{$f11},~{$f14},~{$f15},~{$f16},~{$f17},~{$f18},~{$f19},~{$f20},~{$f21},~{$f22},~{$f23},~{$f24},~{$f25},~{$f26},~{$f27},~{$f28},~{$f29},~{$f30},~{$f31}"() + %1 = fadd double %a, %0 + ret double %1 +} + +; ALL-LABEL: two_doubles: +; ALL: add.d $[[T0:f[0-9]+]], $f12, ${{f[0-9]+}} +; ALL: add.d $f0, $f12, $[[T0]] + + +; INVALID: -mattr=+nooddspreg is not currently permitted for a 32-bit FPU register file (FR=0 mode). Index: test/MC/Mips/nooddspreg-cmdarg.s =================================================================== --- /dev/null +++ test/MC/Mips/nooddspreg-cmdarg.s @@ -0,0 +1,43 @@ +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+fp64,+nooddspreg | \ +# RUN: FileCheck %s -check-prefix=CHECK-ASM +# +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+fp64,+nooddspreg -filetype=obj -o - | \ +# RUN: llvm-readobj -sections -section-data -section-relocations - | \ +# RUN: FileCheck %s -check-prefix=CHECK-OBJ + +# RUN: not llvm-mc %s -arch=mips -mcpu=mips64 -mattr=-n64,+n32,+nooddspreg 2> %t0 +# RUN: FileCheck %s -check-prefix=INVALID < %t0 +# +# RUN: not llvm-mc %s -arch=mips -mcpu=mips64 -mattr=+nooddspreg 2> %t0 +# RUN: FileCheck %s -check-prefix=INVALID < %t0 +# +# CHECK-ASM-NOT: .module nooddspreg + +# Checking if the Mips.abiflags were correctly emitted. +# CHECK-OBJ: Section { +# CHECK-OBJ: Index: 5 +# CHECK-OBJ: Name: .MIPS.abiflags (12) +# CHECK-OBJ: Type: (0x7000002A) +# CHECK-OBJ: Flags [ (0x2) +# CHECK-OBJ: SHF_ALLOC (0x2) +# CHECK-OBJ: ] +# CHECK-OBJ: Address: 0x0 +# CHECK-OBJ: Offset: 0x50 +# CHECK-OBJ: Size: 24 +# CHECK-OBJ: Link: 0 +# CHECK-OBJ: Info: 0 +# CHECK-OBJ: AddressAlignment: 8 +# CHECK-OBJ: EntrySize: 0 +# CHECK-OBJ: Relocations [ +# CHECK-OBJ: ] +# CHECK-OBJ: SectionData ( +# CHECK-OBJ: 0000: 00002001 01020007 00000000 00000000 |.. .............| +# CHECK-OBJ: 0010: 00000000 00000000 |........| +# CHECK-OBJ: ) +# CHECK-OBJ: } + +# INVALID: ERROR: -mno-odd-spreg requires the O32 ABI + +# FIXME: Test should include gnu_attributes directive when implemented. +# An explicit .gnu_attribute must be checked against the effective +# command line options and any inconsistencies reported via a warning. Index: test/MC/Mips/nooddspreg-error.s =================================================================== --- /dev/null +++ test/MC/Mips/nooddspreg-error.s @@ -0,0 +1,14 @@ +# RUN: not llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+fp64 2> %t0 | \ +# RUN: FileCheck %s -check-prefix=CHECK-ASM +# RUN: FileCheck %s -check-prefix=CHECK-ERROR < %t0 +# + .module nooddspreg +# CHECK-ASM: .module nooddspreg + + add.s $f1, $f2, $f5 +# CHECK-ERROR: :[[@LINE-1]]:15: error: -mno-oddspreg prohibits the use of odd FPU registers +# CHECK-ERROR: :[[@LINE-2]]:25: error: -mno-oddspreg prohibits the use of odd FPU registers + +# FIXME: Test should include gnu_attributes directive when implemented. +# An explicit .gnu_attribute must be checked against the effective +# command line options and any inconsistencies reported via a warning. Index: test/MC/Mips/nooddspreg.s =================================================================== --- /dev/null +++ test/MC/Mips/nooddspreg.s @@ -0,0 +1,45 @@ +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+fp64 | \ +# RUN: FileCheck %s -check-prefix=CHECK-ASM +# +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+fp64 -filetype=obj -o - | \ +# RUN: llvm-readobj -sections -section-data -section-relocations - | \ +# RUN: FileCheck %s -check-prefix=CHECK-OBJ + +# RUN: not llvm-mc %s -arch=mips -mcpu=mips64 -mattr=-n64,n32 2> %t1 +# RUN: FileCheck %s -check-prefix=INVALID < %t1 +# +# RUN: not llvm-mc %s -arch=mips -mcpu=mips64 2> %t2 +# RUN: FileCheck %s -check-prefix=INVALID < %t2 +# +# CHECK-ASM: .module nooddspreg + +# Checking if the Mips.abiflags were correctly emitted. +# CHECK-OBJ: Section { +# CHECK-OBJ: Index: 5 +# CHECK-OBJ: Name: .MIPS.abiflags (12) +# CHECK-OBJ: Type: (0x7000002A) +# CHECK-OBJ: Flags [ (0x2) +# CHECK-OBJ: SHF_ALLOC (0x2) +# CHECK-OBJ: ] +# CHECK-OBJ: Address: 0x0 +# CHECK-OBJ: Offset: 0x50 +# CHECK-OBJ: Size: 24 +# CHECK-OBJ: Link: 0 +# CHECK-OBJ: Info: 0 +# CHECK-OBJ: AddressAlignment: 8 +# CHECK-OBJ: EntrySize: 0 +# CHECK-OBJ: Relocations [ +# CHECK-OBJ: ] +# CHECK-OBJ: SectionData ( +# CHECK-OBJ: 0000: 00002001 01020007 00000000 00000000 |.. .............| +# CHECK-OBJ: 0010: 00000000 00000000 |........| +# CHECK-OBJ: ) +# CHECK-OBJ: } + +# INVALID: '.module nooddspreg' requires the O32 ABI + + .module nooddspreg + +# FIXME: Test should include gnu_attributes directive when implemented. +# An explicit .gnu_attribute must be checked against the effective +# command line options and any inconsistencies reported via a warning. Index: test/MC/Mips/oddspreg.s =================================================================== --- /dev/null +++ test/MC/Mips/oddspreg.s @@ -0,0 +1,56 @@ +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+fp64 | \ +# RUN: FileCheck %s -check-prefix=CHECK-ASM +# +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+fp64 -filetype=obj -o - | \ +# RUN: llvm-readobj -sections -section-data -section-relocations - | \ +# RUN: FileCheck %s -check-prefix=CHECK-OBJ-ALL -check-prefix=CHECK-OBJ-O32 +# +# RUN: llvm-mc %s -arch=mips64 -mcpu=mips64 -mattr=-n64,+n32 | \ +# RUN: FileCheck %s -check-prefix=CHECK-ASM +# +# RUN: llvm-mc %s -arch=mips64 -mcpu=mips64 -mattr=-n64,+n32 -filetype=obj -o - | \ +# RUN: llvm-readobj -sections -section-data -section-relocations - | \ +# RUN: FileCheck %s -check-prefix=CHECK-OBJ-ALL -check-prefix=CHECK-OBJ-N32 + +# RUN: llvm-mc %s -arch=mips64 -mcpu=mips64 | \ +# RUN: FileCheck %s -check-prefix=CHECK-ASM +# +# RUN: llvm-mc %s -arch=mips64 -mcpu=mips64 -filetype=obj -o - | \ +# RUN: llvm-readobj -sections -section-data -section-relocations - | \ +# RUN: FileCheck %s -check-prefix=CHECK-OBJ-ALL -check-prefix=CHECK-OBJ-N64 + +# CHECK-ASM: .module oddspreg + +# Checking if the Mips.abiflags were correctly emitted. +# CHECK-OBJ-ALL: Section { +# CHECK-OBJ-ALL: Index: 5 +# CHECK-OBJ-ALL: Name: .MIPS.abiflags ({{[0-9]+}}) +# CHECK-OBJ-ALL: Type: (0x7000002A) +# CHECK-OBJ-ALL: Flags [ (0x2) +# CHECK-OBJ-ALL: SHF_ALLOC (0x2) +# CHECK-OBJ-ALL: ] +# CHECK-OBJ-ALL: Address: 0x0 +# CHECK-OBJ-ALL: Offset: 0x{{[0-9A-F]+}} +# CHECK-OBJ-ALL: Size: 24 +# CHECK-OBJ-ALL: Link: 0 +# CHECK-OBJ-ALL: Info: 0 +# CHECK-OBJ-ALL: AddressAlignment: 8 +# CHECK-OBJ-ALL: EntrySize: 0 +# CHECK-OBJ-ALL: Relocations [ +# CHECK-OBJ-ALL: ] +# CHECK-OBJ-ALL: SectionData ( +# CHECK-OBJ-O32: 0000: 00002001 01020006 00000000 00000000 |.. .............| +# CHECK-OBJ-O32: 0010: 00000001 00000000 |........| +# CHECK-OBJ-N32: 0000: 00004001 02020001 00000000 00000000 |..@.............| +# CHECK-OBJ-N32: 0010: 00000001 00000000 |........| +# CHECK-OBJ-N64: 0000: 00004001 02020001 00000000 00000000 |..@.............| +# CHECK-OBJ-N64: 0010: 00000001 00000000 |........| +# CHECK-OBJ-ALL: ) +# CHECK-OBJ-ALL: } + + .module oddspreg + add.s $f3, $f1, $f5 + +# FIXME: Test should include gnu_attributes directive when implemented. +# An explicit .gnu_attribute must be checked against the effective +# command line options and any inconsistencies reported via a warning.