llvm.org GIT mirror llvm / 24a071b
[mips] Add support for -modd-spreg/-mno-odd-spreg Summary: When -mno-odd-spreg is in effect, 32-bit floating point values are not permitted in odd FPU registers. The option also prohibits 32-bit and 64-bit floating point comparison results from being written to odd registers. This option has three purposes: * It allows support for certain MIPS implementations such as loongson-3a that do not allow the use of odd registers for single precision arithmetic. * When using -mfpxx, -mno-odd-spreg is the default and this allows us to statically check that code is compliant with the O32 FPXX ABI since mtc1/mfc1 instructions to/from odd registers are guaranteed not to appear for any reason. Once this has been established, the user can then re-enable -modd-spreg to regain the use of all 32 single-precision registers. * When using -mfp64 and -mno-odd-spreg together, an O32 extension named O32 FP64A is used as the ABI. This is intended to provide almost all functionality of an FR=1 processor but can also be executed on a FR=0 core with the assistance of a hardware compatibility mode which emulates FR=0 behaviour on an FR=1 processor. * Added '.module oddspreg' and '.module nooddspreg' each of which update the .MIPS.abiflags section appropriately * Moved setFpABI() call inside emitDirectiveModuleFP() so that the caller doesn't have to remember to do it. * MipsABIFlags now calculates the flags1 and flags2 member on demand rather than trying to maintain them in the same format they will be emitted in. There is one portion of the -mfp64 and -mno-odd-spreg combination that is not implemented yet. Moves to/from odd-numbered double-precision registers must not use mtc1. I will fix this in a follow-up. Differential Revision: http://reviews.llvm.org/D4383 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@212717 91177308-0d34-0410-b5e6-96231b3b80d8 Daniel Sanders 5 years ago
16 changed file(s) with 468 addition(s) and 104 deletion(s). Raw diff Collapse all Expand all
164164 bool parseDirectiveGpDWord();
165165 bool parseDirectiveModule();
166166 bool parseDirectiveModuleFP();
167 bool parseFpABIValue(Val_GNU_MIPS_ABI &FpABI, StringRef Directive);
167 bool parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI,
168 StringRef Directive);
168169
169170 MCSymbolRefExpr::VariantKind getVariantKind(StringRef Symbol);
170171
234235 ((STI.getFeatureBits() & Mips::FeatureEABI) != 0) +
235236 ((STI.getFeatureBits() & Mips::FeatureN32) != 0) +
236237 ((STI.getFeatureBits() & Mips::FeatureN64) != 0)) == 1);
238
239 if (!isABI_O32() && !allowOddSPReg() != 0)
240 report_fatal_error("-mno-odd-spreg requires the O32 ABI");
237241 }
238242
239243 MCAsmParser &getParser() const { return Parser; }
248252 bool isABI_N64() const { return STI.getFeatureBits() & Mips::FeatureN64; }
249253 bool isABI_O32() const { return STI.getFeatureBits() & Mips::FeatureO32; }
250254 bool isABI_FPXX() const { return false; } // TODO: add check for FeatureXX
255
256 bool allowOddSPReg() const {
257 return !(STI.getFeatureBits() & Mips::FeatureNoOddSPReg);
258 }
251259
252260 bool inMicroMipsMode() const {
253261 return STI.getFeatureBits() & Mips::FeatureMicroMips;
562570 void addFGR32AsmRegOperands(MCInst &Inst, unsigned N) const {
563571 assert(N == 1 && "Invalid number of operands!");
564572 Inst.addOperand(MCOperand::CreateReg(getFGR32Reg()));
573 // FIXME: We ought to do this for -integrated-as without -via-file-asm too.
574 if (!AsmParser.allowOddSPReg() && RegIdx.Index & 1)
575 AsmParser.Error(StartLoc, "-mno-odd-spreg prohibits the use of odd FPU "
576 "registers");
565577 }
566578
567579 void addFGRH32AsmRegOperands(MCInst &Inst, unsigned N) const {
24432455 }
24442456
24452457 bool MipsAsmParser::parseSetFpDirective() {
2446 Val_GNU_MIPS_ABI FpAbiVal;
2458 MipsABIFlagsSection::FpABIKind FpAbiVal;
24472459 // Line can be: .set fp=32
24482460 // .set fp=xx
24492461 // .set fp=64
24632475 reportParseError("unexpected token in statement");
24642476 return false;
24652477 }
2466 getTargetStreamer().emitDirectiveSetFp(FpAbiVal, isABI_O32());
2478 getTargetStreamer().emitDirectiveSetFp(FpAbiVal);
24672479 Parser.Lex(); // Consume the EndOfStatement.
24682480 return false;
24692481 }
27832795 return false;
27842796 }
27852797
2798 /// parseDirectiveModule
2799 /// ::= .module oddspreg
2800 /// ::= .module nooddspreg
2801 /// ::= .module fp=value
27862802 bool MipsAsmParser::parseDirectiveModule() {
2787 // Line can be: .module fp=32
2788 // .module fp=xx
2789 // .module fp=64
2803 MCAsmLexer &Lexer = getLexer();
2804 SMLoc L = Lexer.getLoc();
2805
27902806 if (!getTargetStreamer().getCanHaveModuleDir()) {
27912807 // TODO : get a better message.
27922808 reportParseError(".module directive must appear before any code");
27932809 return false;
27942810 }
2795 AsmToken Tok = Parser.getTok();
2796 if (Tok.isNot(AsmToken::Identifier) && Tok.getString() != "fp") {
2797 reportParseError("unexpected token in .module directive, 'fp' expected");
2798 return false;
2799 }
2800 Parser.Lex(); // Eat fp token
2801 Tok = Parser.getTok();
2802 if (Tok.isNot(AsmToken::Equal)) {
2811
2812 if (Lexer.is(AsmToken::Identifier)) {
2813 StringRef Option = Parser.getTok().getString();
2814 Parser.Lex();
2815
2816 if (Option == "oddspreg") {
2817 getTargetStreamer().emitDirectiveModuleOddSPReg(true, isABI_O32());
2818 clearFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg");
2819
2820 if (getLexer().isNot(AsmToken::EndOfStatement)) {
2821 reportParseError("Expected end of statement");
2822 return false;
2823 }
2824
2825 return false;
2826 } else if (Option == "nooddspreg") {
2827 if (!isABI_O32()) {
2828 Error(L, "'.module nooddspreg' requires the O32 ABI");
2829 return false;
2830 }
2831
2832 getTargetStreamer().emitDirectiveModuleOddSPReg(false, isABI_O32());
2833 setFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg");
2834
2835 if (getLexer().isNot(AsmToken::EndOfStatement)) {
2836 reportParseError("Expected end of statement");
2837 return false;
2838 }
2839
2840 return false;
2841 } else if (Option == "fp") {
2842 return parseDirectiveModuleFP();
2843 }
2844
2845 return Error(L, "'" + Twine(Option) + "' is not a valid .module option.");
2846 }
2847
2848 return false;
2849 }
2850
2851 /// parseDirectiveModuleFP
2852 /// ::= =32
2853 /// ::= =xx
2854 /// ::= =64
2855 bool MipsAsmParser::parseDirectiveModuleFP() {
2856 MCAsmLexer &Lexer = getLexer();
2857
2858 if (Lexer.isNot(AsmToken::Equal)) {
28032859 reportParseError("unexpected token in statement");
28042860 return false;
28052861 }
28062862 Parser.Lex(); // Eat '=' token.
28072863
2808 Val_GNU_MIPS_ABI FpABI;
2864 MipsABIFlagsSection::FpABIKind FpABI;
28092865 if (!parseFpABIValue(FpABI, ".module"))
28102866 return false;
28112867
28162872
28172873 // Emit appropriate flags.
28182874 getTargetStreamer().emitDirectiveModuleFP(FpABI, isABI_O32());
2819
2875 Parser.Lex(); // Consume the EndOfStatement.
28202876 return false;
28212877 }
28222878
2823 bool MipsAsmParser::parseFpABIValue(Val_GNU_MIPS_ABI &FpABI,
2879 bool MipsAsmParser::parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI,
28242880 StringRef Directive) {
28252881 MCAsmLexer &Lexer = getLexer();
28262882
28382894 return false;
28392895 }
28402896
2841 FpABI = MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_XX;
2897 FpABI = MipsABIFlagsSection::FpABIKind::XX;
28422898 return true;
28432899 }
28442900
28572913 return false;
28582914 }
28592915
2860 FpABI = MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_DOUBLE;
2861 return true;
2862 } else {
2863 if (isABI_N32() || isABI_N64()) {
2864 FpABI = MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_DOUBLE;
2865 return true;
2866 }
2867
2868 if (isABI_O32()) {
2869 FpABI = MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_64;
2870 return true;
2871 }
2872
2873 llvm_unreachable("Unknown ABI");
2874 }
2916 FpABI = MipsABIFlagsSection::FpABIKind::S32;
2917 } else
2918 FpABI = MipsABIFlagsSection::FpABIKind::S64;
2919
2920 return true;
28752921 }
28762922
28772923 return false;
1010
1111 using namespace llvm;
1212
13 StringRef MipsABIFlagsSection::getFpABIString(Val_GNU_MIPS_ABI Value,
14 bool Is32BitAbi) {
13 uint8_t MipsABIFlagsSection::getFpABIValue() {
14 switch (FpABI) {
15 case FpABIKind::ANY:
16 return Val_GNU_MIPS_ABI_FP_ANY;
17 case FpABIKind::XX:
18 return Val_GNU_MIPS_ABI_FP_XX;
19 case FpABIKind::S32:
20 return Val_GNU_MIPS_ABI_FP_DOUBLE;
21 case FpABIKind::S64:
22 if (Is32BitABI)
23 return OddSPReg ? Val_GNU_MIPS_ABI_FP_64 : Val_GNU_MIPS_ABI_FP_64A;
24 return Val_GNU_MIPS_ABI_FP_DOUBLE;
25 default:
26 return 0;
27 }
28 }
29
30 StringRef MipsABIFlagsSection::getFpABIString(FpABIKind Value) {
1531 switch (Value) {
16 case MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_XX:
32 case FpABIKind::XX:
1733 return "xx";
18 case MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_64:
19 return "64";
20 case MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_DOUBLE:
21 if (Is32BitAbi)
22 return "32";
34 case FpABIKind::S32:
35 return "32";
36 case FpABIKind::S64:
2337 return "64";
2438 default:
2539 llvm_unreachable("unsupported fp abi value");
2943 namespace llvm {
3044 MCStreamer &operator<<(MCStreamer &OS, MipsABIFlagsSection &ABIFlagsSection) {
3145 // Write out a Elf_Internal_ABIFlags_v0 struct
32 OS.EmitIntValue(ABIFlagsSection.getVersion(), 2); // version
33 OS.EmitIntValue(ABIFlagsSection.getISALevel(), 1); // isa_level
34 OS.EmitIntValue(ABIFlagsSection.getISARevision(), 1); // isa_rev
35 OS.EmitIntValue(ABIFlagsSection.getGPRSize(), 1); // gpr_size
36 OS.EmitIntValue(ABIFlagsSection.getCPR1Size(), 1); // cpr1_size
37 OS.EmitIntValue(ABIFlagsSection.getCPR2Size(), 1); // cpr2_size
38 OS.EmitIntValue(ABIFlagsSection.getFpABI(), 1); // fp_abi
39 OS.EmitIntValue(ABIFlagsSection.getISAExtensionSet(), 4); // isa_ext
40 OS.EmitIntValue(ABIFlagsSection.getASESet(), 4); // ases
41 OS.EmitIntValue(ABIFlagsSection.getFlags1(), 4); // flags1
42 OS.EmitIntValue(ABIFlagsSection.getFlags2(), 4); // flags2
46 OS.EmitIntValue(ABIFlagsSection.getVersionValue(), 2); // version
47 OS.EmitIntValue(ABIFlagsSection.getISALevelValue(), 1); // isa_level
48 OS.EmitIntValue(ABIFlagsSection.getISARevisionValue(), 1); // isa_rev
49 OS.EmitIntValue(ABIFlagsSection.getGPRSizeValue(), 1); // gpr_size
50 OS.EmitIntValue(ABIFlagsSection.getCPR1SizeValue(), 1); // cpr1_size
51 OS.EmitIntValue(ABIFlagsSection.getCPR2SizeValue(), 1); // cpr2_size
52 OS.EmitIntValue(ABIFlagsSection.getFpABIValue(), 1); // fp_abi
53 OS.EmitIntValue(ABIFlagsSection.getISAExtensionSetValue(), 4); // isa_ext
54 OS.EmitIntValue(ABIFlagsSection.getASESetValue(), 4); // ases
55 OS.EmitIntValue(ABIFlagsSection.getFlags1Value(), 4); // flags1
56 OS.EmitIntValue(ABIFlagsSection.getFlags2Value(), 4); // flags2
4357 return OS;
4458 }
4559 }
6868 Val_GNU_MIPS_ABI_FP_ANY = 0,
6969 Val_GNU_MIPS_ABI_FP_DOUBLE = 1,
7070 Val_GNU_MIPS_ABI_FP_XX = 5,
71 Val_GNU_MIPS_ABI_FP_64 = 6
72 };
71 Val_GNU_MIPS_ABI_FP_64 = 6,
72 Val_GNU_MIPS_ABI_FP_64A = 7
73 };
74
75 enum AFL_FLAGS1 {
76 AFL_FLAGS1_ODDSPREG = 1
77 };
78
79 // Internal representation of the values used in .module fp=value
80 enum class FpABIKind { ANY, XX, S32, S64 };
7381
7482 // Version of flags structure.
7583 uint16_t Version;
8391 AFL_REG CPR1Size;
8492 // The size of co-processor 2 registers.
8593 AFL_REG CPR2Size;
86 // The floating-point ABI.
87 Val_GNU_MIPS_ABI FpABI;
8894 // Processor-specific extension.
8995 uint32_t ISAExtensionSet;
9096 // Mask of ASEs used.
9197 uint32_t ASESet;
9298
99 bool OddSPReg;
100
101 bool Is32BitABI;
102
103 protected:
104 // The floating-point ABI.
105 FpABIKind FpABI;
106
107 public:
93108 MipsABIFlagsSection()
94109 : Version(0), ISALevel(0), ISARevision(0), GPRSize(AFL_REG_NONE),
95 CPR1Size(AFL_REG_NONE), CPR2Size(AFL_REG_NONE),
96 FpABI(Val_GNU_MIPS_ABI_FP_ANY), ISAExtensionSet(0), ASESet(0) {}
97
98 uint16_t getVersion() { return (uint16_t)Version; }
99 uint8_t getISALevel() { return (uint8_t)ISALevel; }
100 uint8_t getISARevision() { return (uint8_t)ISARevision; }
101 uint8_t getGPRSize() { return (uint8_t)GPRSize; }
102 uint8_t getCPR1Size() { return (uint8_t)CPR1Size; }
103 uint8_t getCPR2Size() { return (uint8_t)CPR2Size; }
104 uint8_t getFpABI() { return (uint8_t)FpABI; }
105 uint32_t getISAExtensionSet() { return (uint32_t)ISAExtensionSet; }
106 uint32_t getASESet() { return (uint32_t)ASESet; }
107 uint32_t getFlags1() { return 0; }
108 uint32_t getFlags2() { return 0; }
109
110 StringRef getFpABIString(Val_GNU_MIPS_ABI Value, bool Is32BitAbi);
110 CPR1Size(AFL_REG_NONE), CPR2Size(AFL_REG_NONE), ISAExtensionSet(0),
111 ASESet(0), OddSPReg(false), Is32BitABI(false), FpABI(FpABIKind::ANY) {}
112
113 uint16_t getVersionValue() { return (uint16_t)Version; }
114 uint8_t getISALevelValue() { return (uint8_t)ISALevel; }
115 uint8_t getISARevisionValue() { return (uint8_t)ISARevision; }
116 uint8_t getGPRSizeValue() { return (uint8_t)GPRSize; }
117 uint8_t getCPR1SizeValue() { return (uint8_t)CPR1Size; }
118 uint8_t getCPR2SizeValue() { return (uint8_t)CPR2Size; }
119 uint8_t getFpABIValue();
120 uint32_t getISAExtensionSetValue() { return (uint32_t)ISAExtensionSet; }
121 uint32_t getASESetValue() { return (uint32_t)ASESet; }
122
123 uint32_t getFlags1Value() {
124 uint32_t Value = 0;
125
126 if (OddSPReg)
127 Value |= (uint32_t)AFL_FLAGS1_ODDSPREG;
128
129 return Value;
130 }
131
132 uint32_t getFlags2Value() { return 0; }
133
134 FpABIKind getFpABI() { return FpABI; }
135 void setFpABI(FpABIKind Value, bool IsABI32Bit) {
136 FpABI = Value;
137 Is32BitABI = IsABI32Bit;
138 }
139 StringRef getFpABIString(FpABIKind Value);
111140
112141 template
113142 void setISALevelAndRevisionFromPredicates(const PredicateLibrary &P) {
176205
177206 template
178207 void setFpAbiFromPredicates(const PredicateLibrary &P) {
179 FpABI = Val_GNU_MIPS_ABI_FP_ANY;
208 Is32BitABI = P.isABI_O32();
209
210 FpABI = FpABIKind::ANY;
180211 if (P.isABI_N32() || P.isABI_N64())
181 FpABI = Val_GNU_MIPS_ABI_FP_DOUBLE;
212 FpABI = FpABIKind::S64;
182213 else if (P.isABI_O32()) {
183214 if (P.isFP64bit())
184 FpABI = Val_GNU_MIPS_ABI_FP_64;
215 FpABI = FpABIKind::S64;
185216 else if (P.isABI_FPXX())
186 FpABI = Val_GNU_MIPS_ABI_FP_XX;
187 else
188 FpABI = Val_GNU_MIPS_ABI_FP_DOUBLE;
217 FpABI = FpABIKind::XX;
218 else
219 FpABI = FpABIKind::S32;
189220 }
190221 }
191222
5858 void MipsTargetStreamer::emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,
5959 const MCSymbol &Sym, bool IsReg) {
6060 }
61 void MipsTargetStreamer::emitDirectiveModuleOddSPReg(bool Enabled,
62 bool IsO32ABI) {
63 if (!Enabled && !IsO32ABI)
64 report_fatal_error("+nooddspreg is only valid for O32");
65 }
6166
6267 MipsTargetAsmStreamer::MipsTargetAsmStreamer(MCStreamer &S,
6368 formatted_raw_ostream &OS)
210215 setCanHaveModuleDir(false);
211216 }
212217
213 void MipsTargetAsmStreamer::emitDirectiveModuleFP(Val_GNU_MIPS_ABI Value,
214 bool Is32BitAbi) {
215 MipsTargetStreamer::emitDirectiveModuleFP(Value, Is32BitAbi);
218 void MipsTargetAsmStreamer::emitDirectiveModuleFP(
219 MipsABIFlagsSection::FpABIKind Value, bool Is32BitABI) {
220 MipsTargetStreamer::emitDirectiveModuleFP(Value, Is32BitABI);
216221
217222 StringRef ModuleValue;
218223 OS << "\t.module\tfp=";
219 OS << ABIFlagsSection.getFpABIString(Value, Is32BitAbi) << "\n";
220 }
221
222 void MipsTargetAsmStreamer::emitDirectiveSetFp(Val_GNU_MIPS_ABI Value,
223 bool Is32BitAbi) {
224 OS << ABIFlagsSection.getFpABIString(Value) << "\n";
225 }
226
227 void MipsTargetAsmStreamer::emitDirectiveSetFp(
228 MipsABIFlagsSection::FpABIKind Value) {
224229 StringRef ModuleValue;
225230 OS << "\t.set\tfp=";
226 OS << ABIFlagsSection.getFpABIString(Value, Is32BitAbi) << "\n";
231 OS << ABIFlagsSection.getFpABIString(Value) << "\n";
227232 }
228233
229234 void MipsTargetAsmStreamer::emitMipsAbiFlags() {
230235 // No action required for text output.
236 }
237
238 void MipsTargetAsmStreamer::emitDirectiveModuleOddSPReg(bool Enabled,
239 bool IsO32ABI) {
240 MipsTargetStreamer::emitDirectiveModuleOddSPReg(Enabled, IsO32ABI);
241
242 OS << "\t.module\t" << (Enabled ? "" : "no") << "oddspreg\n";
231243 }
232244
233245 // This part is for ELF object output.
632644
633645 OS << ABIFlagsSection;
634646 }
647
648 void MipsTargetELFStreamer::emitDirectiveModuleOddSPReg(bool Enabled,
649 bool IsO32ABI) {
650 MipsTargetStreamer::emitDirectiveModuleOddSPReg(Enabled, IsO32ABI);
651
652 ABIFlagsSection.OddSPReg = Enabled;
653 }
7272 "Enable n64 ABI">;
7373 def FeatureEABI : SubtargetFeature<"eabi", "MipsABI", "EABI",
7474 "Enable eabi ABI">;
75 def FeatureNoOddSPReg : SubtargetFeature<"nooddspreg", "UseOddSPReg", "false",
76 "Disable odd numbered single-precision "
77 "registers">;
7578 def FeatureVFPU : SubtargetFeature<"vfpu", "HasVFPU",
7679 "true", "Enable vector FPU instructions.">;
7780 def FeatureMips1 : SubtargetFeature<"mips1", "MipsArchVersion", "Mips1",
703703 OutContext.getELFSection(".gcc_compiled_long64", ELF::SHT_PROGBITS, 0,
704704 SectionKind::getDataRel()));
705705 }
706
706707 getTargetStreamer().updateABIInfo(*Subtarget);
707 getTargetStreamer().emitDirectiveModuleFP(
708 getTargetStreamer().getABIFlagsSection().FpABI, Subtarget->isABI_O32());
708 getTargetStreamer().emitDirectiveModuleFP();
709
710 if (Subtarget->isABI_O32())
711 getTargetStreamer().emitDirectiveModuleOddSPReg(Subtarget->useOddSPReg(),
712 Subtarget->isABI_O32());
709713 }
710714
711715 void MipsAsmPrinter::EmitJal(MCSymbol *Symbol) {
200200 Reserved.set(Mips::GP_64);
201201 }
202202
203 if (Subtarget.isABI_O32() && !Subtarget.useOddSPReg()) {
204 for (const auto &Reg : Mips::OddSPRegClass)
205 Reserved.set(Reg);
206 }
207
203208 return Reserved;
204209 }
205210
339339
340340 def FGR64 : RegisterClass<"Mips", [f64], 64, (sequence "D%u_64", 0, 31)>;
341341
342 // Used to reserve odd registers when given -mattr=+nooddspreg
343 def OddSP : RegisterClass<"Mips", [f32], 32,
344 (add (decimate (sequence "F%u", 1, 31), 2),
345 (decimate (sequence "F_HI%u", 1, 31), 2))>,
346 Unallocatable;
347
342348 // FP control registers.
343349 def CCR : RegisterClass<"Mips", [i32], 32, (sequence "FCR%u", 0, 31)>,
344350 Unallocatable;
106106 Reloc::Model _RM, MipsTargetMachine *_TM)
107107 : MipsGenSubtargetInfo(TT, CPU, FS), MipsArchVersion(Mips32),
108108 MipsABI(UnknownABI), IsLittle(little), IsSingleFloat(false),
109 IsFP64bit(false), IsNaN2008bit(false), IsGP64bit(false), HasVFPU(false),
110 HasCnMips(false), IsLinux(true), HasMips3_32(false), HasMips3_32r2(false),
111 HasMips4_32(false), HasMips4_32r2(false), HasMips5_32r2(false),
112 InMips16Mode(false), InMips16HardFloat(Mips16HardFloat),
113 InMicroMipsMode(false), HasDSP(false), HasDSPR2(false),
114 AllowMixed16_32(Mixed16_32 | Mips_Os16), Os16(Mips_Os16), HasMSA(false),
115 RM(_RM), OverrideMode(NoOverride), TM(_TM), TargetTriple(TT),
109 IsFP64bit(false), UseOddSPReg(true), IsNaN2008bit(false),
110 IsGP64bit(false), HasVFPU(false), HasCnMips(false), IsLinux(true),
111 HasMips3_32(false), HasMips3_32r2(false), HasMips4_32(false),
112 HasMips4_32r2(false), HasMips5_32r2(false), InMips16Mode(false),
113 InMips16HardFloat(Mips16HardFloat), InMicroMipsMode(false), HasDSP(false),
114 HasDSPR2(false), AllowMixed16_32(Mixed16_32 | Mips_Os16), Os16(Mips_Os16),
115 HasMSA(false), RM(_RM), OverrideMode(NoOverride), TM(_TM),
116 TargetTriple(TT),
116117 DL(computeDataLayout(initializeSubtargetDependencies(CPU, FS, TM))),
117118 TSInfo(DL), JITInfo(), InstrInfo(MipsInstrInfo::create(*TM)),
118119 FrameLowering(MipsFrameLowering::create(*TM, *this)),
148149 if (hasMSA() && !isFP64bit())
149150 report_fatal_error("MSA requires a 64-bit FPU register file (FR=1 mode). "
150151 "See -mattr=+fp64.",
152 false);
153
154 if (!isABI_O32() && !useOddSPReg())
155 report_fatal_error("-mattr=+nooddspreg is not currently permitted for a "
156 "the O32 ABI.",
151157 false);
152158
153159 if (hasMips32r6()) {
6363
6464 // IsFP64bit - The target processor has 64-bit floating point registers.
6565 bool IsFP64bit;
66
67 /// Are odd single-precision registers permitted?
68 /// This corresponds to -modd-spreg and -mno-odd-spreg
69 bool UseOddSPReg;
6670
6771 // IsNan2008 - IEEE 754-2008 NaN encoding.
6872 bool IsNaN2008bit;
202206
203207 bool isLittle() const { return IsLittle; }
204208 bool isFP64bit() const { return IsFP64bit; }
209 bool useOddSPReg() const { return UseOddSPReg; }
205210 bool isNaN2008() const { return IsNaN2008bit; }
206211 bool isNotFP64bit() const { return !IsFP64bit; }
207212 bool isGP64bit() const { return IsGP64bit; }
1616 namespace llvm {
1717
1818 struct MipsABIFlagsSection;
19
20 typedef MipsABIFlagsSection::Val_GNU_MIPS_ABI Val_GNU_MIPS_ABI;
2119
2220 class MipsTargetStreamer : public MCTargetStreamer {
2321 public:
5553 virtual void emitDirectiveCpload(unsigned RegNo);
5654 virtual void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,
5755 const MCSymbol &Sym, bool IsReg);
58 // ABI Flags
59 virtual void emitDirectiveModuleFP(Val_GNU_MIPS_ABI Value, bool Is32BitAbi) {
60 ABIFlagsSection.FpABI = Value;
56
57 /// Emit a '.module fp=value' directive using the given values.
58 /// Updates the .MIPS.abiflags section
59 virtual void emitDirectiveModuleFP(MipsABIFlagsSection::FpABIKind Value,
60 bool Is32BitABI) {
61 ABIFlagsSection.setFpABI(Value, Is32BitABI);
6162 }
62 virtual void emitDirectiveSetFp(Val_GNU_MIPS_ABI Value, bool Is32BitAbi){};
63
64 /// Emit a '.module fp=value' directive using the current values of the
65 /// .MIPS.abiflags section.
66 void emitDirectiveModuleFP() {
67 emitDirectiveModuleFP(ABIFlagsSection.getFpABI(),
68 ABIFlagsSection.Is32BitABI);
69 }
70
71 virtual void emitDirectiveModuleOddSPReg(bool Enabled, bool IsO32ABI);
72 virtual void emitDirectiveSetFp(MipsABIFlagsSection::FpABIKind Value){};
6373 virtual void emitMipsAbiFlags(){};
6474 void setCanHaveModuleDir(bool Can) { canHaveModuleDirective = Can; }
6575 bool getCanHaveModuleDir() { return canHaveModuleDirective; }
121131 const MCSymbol &Sym, bool IsReg) override;
122132
123133 // ABI Flags
124 void emitDirectiveModuleFP(Val_GNU_MIPS_ABI Value, bool Is32BitAbi) override;
125 void emitDirectiveSetFp(Val_GNU_MIPS_ABI Value, bool Is32BitAbi) override;
134 void emitDirectiveModuleFP(MipsABIFlagsSection::FpABIKind Value,
135 bool Is32BitABI) override;
136 void emitDirectiveModuleOddSPReg(bool Enabled, bool IsO32ABI) override;
137 void emitDirectiveSetFp(MipsABIFlagsSection::FpABIKind Value) override;
126138 void emitMipsAbiFlags() override;
127139 };
128140
176188 const MCSymbol &Sym, bool IsReg) override;
177189
178190 // ABI Flags
191 void emitDirectiveModuleOddSPReg(bool Enabled, bool IsO32ABI) override;
179192 void emitMipsAbiFlags() override;
180193
181194 protected:
0 ; RUN: llc -march=mipsel -mcpu=mips32 < %s | FileCheck %s -check-prefix=ALL -check-prefix=ODDSPREG
1 ; RUN: llc -march=mipsel -mcpu=mips32 -mattr=+nooddspreg < %s | FileCheck %s -check-prefix=ALL -check-prefix=NOODDSPREG
2 ; RUN: llc -march=mipsel -mcpu=mips32r6 -mattr=fp64 < %s | FileCheck %s -check-prefix=ALL -check-prefix=ODDSPREG
3 ; RUN: llc -march=mipsel -mcpu=mips32r6 -mattr=fp64,+nooddspreg < %s | FileCheck %s -check-prefix=ALL -check-prefix=NOODDSPREG
4
5 ; ODDSPREG: .module oddspreg
6 ; NOODDSPREG: .module nooddspreg
7
8 define float @two_floats(float %a) {
9 entry:
10 ; Clobber all except $f12 and $f13
11 ;
12 ; The intention is that if odd single precision registers are permitted, the
13 ; allocator will choose $f12 and $f13 to avoid the spill/reload.
14 ;
15 ; On the other hand, if odd single precision registers are not permitted, it
16 ; will be forced to spill/reload either %a or %0.
17
18 %0 = fadd float %a, 1.0
19 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}"()
20 %1 = fadd float %a, %0
21 ret float %1
22 }
23
24 ; ALL-LABEL: two_floats:
25 ; ODDSPREG: add.s $f13, $f12, ${{f[0-9]+}}
26 ; ODDSPREG-NOT: swc1
27 ; ODDSPREG-NOT: lwc1
28 ; ODDSPREG: add.s $f0, $f12, $f13
29
30 ; NOODDSPREG: add.s $[[T0:f[0-9]*[02468]]], $f12, ${{f[0-9]+}}
31 ; NOODDSPREG: swc1 $[[T0]],
32 ; NOODDSPREG: lwc1 $[[T1:f[0-9]*[02468]]],
33 ; NOODDSPREG: add.s $f0, $f12, $[[T1]]
34
35 define double @two_doubles(double %a) {
36 entry:
37 ; Clobber all except $f12 and $f13
38 ;
39 ; -mno-odd-sp-reg doesn't need to affect double precision values so both cases
40 ; use $f12 and $f13.
41
42 %0 = fadd double %a, 1.0
43 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}"()
44 %1 = fadd double %a, %0
45 ret double %1
46 }
47
48 ; ALL-LABEL: two_doubles:
49 ; ALL: add.d $[[T0:f[0-9]+]], $f12, ${{f[0-9]+}}
50 ; ALL: add.d $f0, $f12, $[[T0]]
51
52
53 ; INVALID: -mattr=+nooddspreg is not currently permitted for a 32-bit FPU register file (FR=0 mode).
0 # RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+fp64,+nooddspreg | \
1 # RUN: FileCheck %s -check-prefix=CHECK-ASM
2 #
3 # RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+fp64,+nooddspreg -filetype=obj -o - | \
4 # RUN: llvm-readobj -sections -section-data -section-relocations - | \
5 # RUN: FileCheck %s -check-prefix=CHECK-OBJ
6
7 # RUN: not llvm-mc %s -arch=mips -mcpu=mips64 -mattr=-n64,+n32,+nooddspreg 2> %t0
8 # RUN: FileCheck %s -check-prefix=INVALID < %t0
9 #
10 # RUN: not llvm-mc %s -arch=mips -mcpu=mips64 -mattr=+nooddspreg 2> %t0
11 # RUN: FileCheck %s -check-prefix=INVALID < %t0
12 #
13 # CHECK-ASM-NOT: .module nooddspreg
14
15 # Checking if the Mips.abiflags were correctly emitted.
16 # CHECK-OBJ: Section {
17 # CHECK-OBJ: Index: 5
18 # CHECK-OBJ: Name: .MIPS.abiflags (12)
19 # CHECK-OBJ: Type: (0x7000002A)
20 # CHECK-OBJ: Flags [ (0x2)
21 # CHECK-OBJ: SHF_ALLOC (0x2)
22 # CHECK-OBJ: ]
23 # CHECK-OBJ: Address: 0x0
24 # CHECK-OBJ: Offset: 0x50
25 # CHECK-OBJ: Size: 24
26 # CHECK-OBJ: Link: 0
27 # CHECK-OBJ: Info: 0
28 # CHECK-OBJ: AddressAlignment: 8
29 # CHECK-OBJ: EntrySize: 0
30 # CHECK-OBJ: Relocations [
31 # CHECK-OBJ: ]
32 # CHECK-OBJ: SectionData (
33 # CHECK-OBJ: 0000: 00002001 01020007 00000000 00000000 |.. .............|
34 # CHECK-OBJ: 0010: 00000000 00000000 |........|
35 # CHECK-OBJ: )
36 # CHECK-OBJ: }
37
38 # INVALID: ERROR: -mno-odd-spreg requires the O32 ABI
39
40 # FIXME: Test should include gnu_attributes directive when implemented.
41 # An explicit .gnu_attribute must be checked against the effective
42 # command line options and any inconsistencies reported via a warning.
0 # RUN: not llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+fp64 2> %t0 | \
1 # RUN: FileCheck %s -check-prefix=CHECK-ASM
2 # RUN: FileCheck %s -check-prefix=CHECK-ERROR < %t0
3 #
4 .module nooddspreg
5 # CHECK-ASM: .module nooddspreg
6
7 add.s $f1, $f2, $f5
8 # CHECK-ERROR: :[[@LINE-1]]:15: error: -mno-odd-spreg prohibits the use of odd FPU registers
9 # CHECK-ERROR: :[[@LINE-2]]:25: error: -mno-odd-spreg prohibits the use of odd FPU registers
10
11 # FIXME: Test should include gnu_attributes directive when implemented.
12 # An explicit .gnu_attribute must be checked against the effective
13 # command line options and any inconsistencies reported via a warning.
0 # RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+fp64 | \
1 # RUN: FileCheck %s -check-prefix=CHECK-ASM
2 #
3 # RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+fp64 -filetype=obj -o - | \
4 # RUN: llvm-readobj -sections -section-data -section-relocations - | \
5 # RUN: FileCheck %s -check-prefix=CHECK-OBJ
6
7 # RUN: not llvm-mc %s -arch=mips -mcpu=mips64 -mattr=-n64,n32 2> %t1
8 # RUN: FileCheck %s -check-prefix=INVALID < %t1
9 #
10 # RUN: not llvm-mc %s -arch=mips -mcpu=mips64 2> %t2
11 # RUN: FileCheck %s -check-prefix=INVALID < %t2
12 #
13 # CHECK-ASM: .module nooddspreg
14
15 # Checking if the Mips.abiflags were correctly emitted.
16 # CHECK-OBJ: Section {
17 # CHECK-OBJ: Index: 5
18 # CHECK-OBJ: Name: .MIPS.abiflags (12)
19 # CHECK-OBJ: Type: (0x7000002A)
20 # CHECK-OBJ: Flags [ (0x2)
21 # CHECK-OBJ: SHF_ALLOC (0x2)
22 # CHECK-OBJ: ]
23 # CHECK-OBJ: Address: 0x0
24 # CHECK-OBJ: Offset: 0x50
25 # CHECK-OBJ: Size: 24
26 # CHECK-OBJ: Link: 0
27 # CHECK-OBJ: Info: 0
28 # CHECK-OBJ: AddressAlignment: 8
29 # CHECK-OBJ: EntrySize: 0
30 # CHECK-OBJ: Relocations [
31 # CHECK-OBJ: ]
32 # CHECK-OBJ: SectionData (
33 # CHECK-OBJ: 0000: 00002001 01020007 00000000 00000000 |.. .............|
34 # CHECK-OBJ: 0010: 00000000 00000000 |........|
35 # CHECK-OBJ: )
36 # CHECK-OBJ: }
37
38 # INVALID: '.module nooddspreg' requires the O32 ABI
39
40 .module nooddspreg
41
42 # FIXME: Test should include gnu_attributes directive when implemented.
43 # An explicit .gnu_attribute must be checked against the effective
44 # command line options and any inconsistencies reported via a warning.
0 # RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+fp64 | \
1 # RUN: FileCheck %s -check-prefix=CHECK-ASM
2 #
3 # RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+fp64 -filetype=obj -o - | \
4 # RUN: llvm-readobj -sections -section-data -section-relocations - | \
5 # RUN: FileCheck %s -check-prefix=CHECK-OBJ-ALL -check-prefix=CHECK-OBJ-O32
6 #
7 # RUN: llvm-mc %s -arch=mips64 -mcpu=mips64 -mattr=-n64,+n32 | \
8 # RUN: FileCheck %s -check-prefix=CHECK-ASM
9 #
10 # RUN: llvm-mc %s -arch=mips64 -mcpu=mips64 -mattr=-n64,+n32 -filetype=obj -o - | \
11 # RUN: llvm-readobj -sections -section-data -section-relocations - | \
12 # RUN: FileCheck %s -check-prefix=CHECK-OBJ-ALL -check-prefix=CHECK-OBJ-N32
13
14 # RUN: llvm-mc %s -arch=mips64 -mcpu=mips64 | \
15 # RUN: FileCheck %s -check-prefix=CHECK-ASM
16 #
17 # RUN: llvm-mc %s -arch=mips64 -mcpu=mips64 -filetype=obj -o - | \
18 # RUN: llvm-readobj -sections -section-data -section-relocations - | \
19 # RUN: FileCheck %s -check-prefix=CHECK-OBJ-ALL -check-prefix=CHECK-OBJ-N64
20
21 # CHECK-ASM: .module oddspreg
22
23 # Checking if the Mips.abiflags were correctly emitted.
24 # CHECK-OBJ-ALL: Section {
25 # CHECK-OBJ-ALL: Index: 5
26 # CHECK-OBJ-ALL: Name: .MIPS.abiflags ({{[0-9]+}})
27 # CHECK-OBJ-ALL: Type: (0x7000002A)
28 # CHECK-OBJ-ALL: Flags [ (0x2)
29 # CHECK-OBJ-ALL: SHF_ALLOC (0x2)
30 # CHECK-OBJ-ALL: ]
31 # CHECK-OBJ-ALL: Address: 0x0
32 # CHECK-OBJ-ALL: Offset: 0x{{[0-9A-F]+}}
33 # CHECK-OBJ-ALL: Size: 24
34 # CHECK-OBJ-ALL: Link: 0
35 # CHECK-OBJ-ALL: Info: 0
36 # CHECK-OBJ-ALL: AddressAlignment: 8
37 # CHECK-OBJ-ALL: EntrySize: 0
38 # CHECK-OBJ-ALL: Relocations [
39 # CHECK-OBJ-ALL: ]
40 # CHECK-OBJ-ALL: SectionData (
41 # CHECK-OBJ-O32: 0000: 00002001 01020006 00000000 00000000 |.. .............|
42 # CHECK-OBJ-O32: 0010: 00000001 00000000 |........|
43 # CHECK-OBJ-N32: 0000: 00004001 02020001 00000000 00000000 |..@.............|
44 # CHECK-OBJ-N32: 0010: 00000001 00000000 |........|
45 # CHECK-OBJ-N64: 0000: 00004001 02020001 00000000 00000000 |..@.............|
46 # CHECK-OBJ-N64: 0010: 00000001 00000000 |........|
47 # CHECK-OBJ-ALL: )
48 # CHECK-OBJ-ALL: }
49
50 .module oddspreg
51 add.s $f3, $f1, $f5
52
53 # FIXME: Test should include gnu_attributes directive when implemented.
54 # An explicit .gnu_attribute must be checked against the effective
55 # command line options and any inconsistencies reported via a warning.