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);
((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; }
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;
}
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 {
}
bool MipsAsmParser::parseSetFpDirective() {
- Val_GNU_MIPS_ABI FpAbiVal;
+ MipsABIFlagsSection::FpABIKind FpAbiVal;
// Line can be: .set fp=32
// .set fp=xx
// .set fp=64
reportParseError("unexpected token in statement");
return false;
}
- getTargetStreamer().emitDirectiveSetFp(FpAbiVal, isABI_O32());
+ getTargetStreamer().emitDirectiveSetFp(FpAbiVal);
Parser.Lex(); // Consume the EndOfStatement.
return false;
}
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;
// 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();
return false;
}
- FpABI = MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_XX;
+ FpABI = MipsABIFlagsSection::FpABIKind::XX;
return true;
}
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;
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");
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;
}
}
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.
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 <class PredicateLibrary>
void setISALevelAndRevisionFromPredicates(const PredicateLibrary &P) {
template <class PredicateLibrary>
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;
}
}
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)
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)
OS << ABIFlagsSection;
}
+
+void MipsTargetELFStreamer::emitDirectiveModuleOddSPReg(bool Enabled,
+ bool IsO32ABI) {
+ MipsTargetStreamer::emitDirectiveModuleOddSPReg(Enabled, IsO32ABI);
+
+ ABIFlagsSection.OddSPReg = Enabled;
+}
"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",
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) {
Reserved.set(Mips::GP_64);
}
+ if (Subtarget.isABI_O32() && !Subtarget.useOddSPReg()) {
+ for (const auto &Reg : Mips::OddSPRegClass)
+ Reserved.set(Reg);
+ }
+
return Reserved;
}
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;
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)),
"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";
// 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;
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; }
struct MipsABIFlagsSection;
-typedef MipsABIFlagsSection::Val_GNU_MIPS_ABI Val_GNU_MIPS_ABI;
-
class MipsTargetStreamer : public MCTargetStreamer {
public:
MipsTargetStreamer(MCStreamer &S);
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; }
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;
};
const MCSymbol &Sym, bool IsReg) override;
// ABI Flags
+ void emitDirectiveModuleOddSPReg(bool Enabled, bool IsO32ABI) override;
void emitMipsAbiFlags() override;
protected:
--- /dev/null
+; 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).
--- /dev/null
+# 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.
--- /dev/null
+# 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-odd-spreg prohibits the use of odd FPU registers
+# CHECK-ERROR: :[[@LINE-2]]:25: error: -mno-odd-spreg 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.
--- /dev/null
+# 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.
--- /dev/null
+# 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.