1 | //===--- Mips.h - Declare Mips target feature support -----------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file declares Mips TargetInfo objects. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_CLANG_LIB_BASIC_TARGETS_MIPS_H |
14 | #define LLVM_CLANG_LIB_BASIC_TARGETS_MIPS_H |
15 | |
16 | #include "clang/Basic/TargetInfo.h" |
17 | #include "clang/Basic/TargetOptions.h" |
18 | #include "llvm/Support/Compiler.h" |
19 | #include "llvm/TargetParser/Triple.h" |
20 | |
21 | namespace clang { |
22 | namespace targets { |
23 | |
24 | class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public TargetInfo { |
25 | void setDataLayout() { |
26 | StringRef Layout; |
27 | |
28 | if (ABI == "o32" ) |
29 | Layout = "m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64" ; |
30 | else if (ABI == "n32" ) |
31 | Layout = "m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32:64-S128" ; |
32 | else if (ABI == "n64" ) |
33 | Layout = "m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128" ; |
34 | else |
35 | llvm_unreachable("Invalid ABI" ); |
36 | |
37 | if (BigEndian) |
38 | resetDataLayout(DL: ("E-" + Layout).str()); |
39 | else |
40 | resetDataLayout(DL: ("e-" + Layout).str()); |
41 | } |
42 | |
43 | std::string CPU; |
44 | bool IsMips16; |
45 | bool IsMicromips; |
46 | bool IsNan2008; |
47 | bool IsAbs2008; |
48 | bool IsSingleFloat; |
49 | bool IsNoABICalls; |
50 | bool CanUseBSDABICalls; |
51 | enum MipsFloatABI { HardFloat, SoftFloat } FloatABI; |
52 | enum DspRevEnum { NoDSP, DSP1, DSP2 } DspRev; |
53 | bool HasMSA; |
54 | bool DisableMadd4; |
55 | bool UseIndirectJumpHazard; |
56 | bool NoOddSpreg; |
57 | |
58 | protected: |
59 | enum FPModeEnum { FPXX, FP32, FP64 } FPMode; |
60 | std::string ABI; |
61 | |
62 | public: |
63 | MipsTargetInfo(const llvm::Triple &Triple, const TargetOptions &) |
64 | : TargetInfo(Triple), IsMips16(false), IsMicromips(false), |
65 | IsNan2008(false), IsAbs2008(false), IsSingleFloat(false), |
66 | IsNoABICalls(false), CanUseBSDABICalls(false), FloatABI(HardFloat), |
67 | DspRev(NoDSP), HasMSA(false), DisableMadd4(false), |
68 | UseIndirectJumpHazard(false), FPMode(FPXX) { |
69 | TheCXXABI.set(TargetCXXABI::GenericMIPS); |
70 | |
71 | if (Triple.isMIPS32()) |
72 | setABI("o32" ); |
73 | else if (Triple.getEnvironment() == llvm::Triple::GNUABIN32) |
74 | setABI("n32" ); |
75 | else |
76 | setABI("n64" ); |
77 | |
78 | CPU = ABI == "o32" ? "mips32r2" : "mips64r2" ; |
79 | |
80 | CanUseBSDABICalls = Triple.isOSFreeBSD() || |
81 | Triple.isOSOpenBSD(); |
82 | } |
83 | |
84 | bool isIEEE754_2008Default() const { |
85 | return CPU == "mips32r6" || CPU == "mips64r6" ; |
86 | } |
87 | |
88 | enum FPModeEnum getDefaultFPMode() const { |
89 | if (CPU == "mips32r6" || ABI == "n32" || ABI == "n64" || ABI == "64" ) |
90 | return FP64; |
91 | else if (CPU == "mips1" ) |
92 | return FP32; |
93 | else |
94 | return FPXX; |
95 | } |
96 | |
97 | bool isNan2008() const override { return IsNan2008; } |
98 | |
99 | bool processorSupportsGPR64() const; |
100 | |
101 | StringRef getABI() const override { return ABI; } |
102 | |
103 | bool setABI(const std::string &Name) override { |
104 | if (Name == "o32" ) { |
105 | setO32ABITypes(); |
106 | ABI = Name; |
107 | return true; |
108 | } |
109 | |
110 | if (Name == "n32" ) { |
111 | setN32ABITypes(); |
112 | ABI = Name; |
113 | return true; |
114 | } |
115 | if (Name == "n64" ) { |
116 | setN64ABITypes(); |
117 | ABI = Name; |
118 | return true; |
119 | } |
120 | return false; |
121 | } |
122 | |
123 | void setO32ABITypes() { |
124 | Int64Type = SignedLongLong; |
125 | IntMaxType = Int64Type; |
126 | LongDoubleFormat = &llvm::APFloat::IEEEdouble(); |
127 | LongDoubleWidth = LongDoubleAlign = 64; |
128 | LongWidth = LongAlign = 32; |
129 | MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; |
130 | PointerWidth = PointerAlign = 32; |
131 | PtrDiffType = SignedInt; |
132 | SizeType = UnsignedInt; |
133 | SuitableAlign = 64; |
134 | } |
135 | |
136 | void setN32N64ABITypes() { |
137 | LongDoubleWidth = LongDoubleAlign = 128; |
138 | LongDoubleFormat = &llvm::APFloat::IEEEquad(); |
139 | if (getTriple().isOSFreeBSD()) { |
140 | LongDoubleWidth = LongDoubleAlign = 64; |
141 | LongDoubleFormat = &llvm::APFloat::IEEEdouble(); |
142 | } |
143 | MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; |
144 | SuitableAlign = 128; |
145 | } |
146 | |
147 | void setN64ABITypes() { |
148 | setN32N64ABITypes(); |
149 | if (getTriple().isOSOpenBSD()) { |
150 | Int64Type = SignedLongLong; |
151 | } else { |
152 | Int64Type = SignedLong; |
153 | } |
154 | IntMaxType = Int64Type; |
155 | LongWidth = LongAlign = 64; |
156 | PointerWidth = PointerAlign = 64; |
157 | PtrDiffType = SignedLong; |
158 | SizeType = UnsignedLong; |
159 | } |
160 | |
161 | void setN32ABITypes() { |
162 | setN32N64ABITypes(); |
163 | Int64Type = SignedLongLong; |
164 | IntMaxType = Int64Type; |
165 | LongWidth = LongAlign = 32; |
166 | PointerWidth = PointerAlign = 32; |
167 | PtrDiffType = SignedInt; |
168 | SizeType = UnsignedInt; |
169 | } |
170 | |
171 | bool isValidCPUName(StringRef Name) const override; |
172 | void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; |
173 | |
174 | bool setCPU(const std::string &Name) override { |
175 | CPU = Name; |
176 | return isValidCPUName(Name); |
177 | } |
178 | |
179 | const std::string &getCPU() const { return CPU; } |
180 | bool |
181 | initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, |
182 | StringRef CPU, |
183 | const std::vector<std::string> &FeaturesVec) const override { |
184 | if (CPU.empty()) |
185 | CPU = getCPU(); |
186 | if (CPU == "octeon" ) |
187 | Features["mips64r2" ] = Features["cnmips" ] = true; |
188 | else if (CPU == "octeon+" ) |
189 | Features["mips64r2" ] = Features["cnmips" ] = Features["cnmipsp" ] = true; |
190 | else |
191 | Features[CPU] = true; |
192 | return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec: FeaturesVec); |
193 | } |
194 | |
195 | unsigned getISARev() const; |
196 | |
197 | void getTargetDefines(const LangOptions &Opts, |
198 | MacroBuilder &Builder) const override; |
199 | |
200 | ArrayRef<Builtin::Info> getTargetBuiltins() const override; |
201 | |
202 | bool hasFeature(StringRef Feature) const override; |
203 | |
204 | BuiltinVaListKind getBuiltinVaListKind() const override { |
205 | return TargetInfo::VoidPtrBuiltinVaList; |
206 | } |
207 | |
208 | ArrayRef<const char *> getGCCRegNames() const override { |
209 | static const char *const GCCRegNames[] = { |
210 | // CPU register names |
211 | // Must match second column of GCCRegAliases |
212 | "$0" , "$1" , "$2" , "$3" , "$4" , "$5" , "$6" , "$7" , "$8" , "$9" , "$10" , |
213 | "$11" , "$12" , "$13" , "$14" , "$15" , "$16" , "$17" , "$18" , "$19" , "$20" , |
214 | "$21" , "$22" , "$23" , "$24" , "$25" , "$26" , "$27" , "$28" , "$29" , "$30" , |
215 | "$31" , |
216 | // Floating point register names |
217 | "$f0" , "$f1" , "$f2" , "$f3" , "$f4" , "$f5" , "$f6" , "$f7" , "$f8" , "$f9" , |
218 | "$f10" , "$f11" , "$f12" , "$f13" , "$f14" , "$f15" , "$f16" , "$f17" , "$f18" , |
219 | "$f19" , "$f20" , "$f21" , "$f22" , "$f23" , "$f24" , "$f25" , "$f26" , "$f27" , |
220 | "$f28" , "$f29" , "$f30" , "$f31" , |
221 | // Hi/lo and condition register names |
222 | "hi" , "lo" , "" , "$fcc0" , "$fcc1" , "$fcc2" , "$fcc3" , "$fcc4" , "$fcc5" , |
223 | "$fcc6" , "$fcc7" , "$ac1hi" , "$ac1lo" , "$ac2hi" , "$ac2lo" , "$ac3hi" , |
224 | "$ac3lo" , |
225 | // MSA register names |
226 | "$w0" , "$w1" , "$w2" , "$w3" , "$w4" , "$w5" , "$w6" , "$w7" , "$w8" , "$w9" , |
227 | "$w10" , "$w11" , "$w12" , "$w13" , "$w14" , "$w15" , "$w16" , "$w17" , "$w18" , |
228 | "$w19" , "$w20" , "$w21" , "$w22" , "$w23" , "$w24" , "$w25" , "$w26" , "$w27" , |
229 | "$w28" , "$w29" , "$w30" , "$w31" , |
230 | // MSA control register names |
231 | "$msair" , "$msacsr" , "$msaaccess" , "$msasave" , "$msamodify" , |
232 | "$msarequest" , "$msamap" , "$msaunmap" |
233 | }; |
234 | return llvm::ArrayRef(GCCRegNames); |
235 | } |
236 | |
237 | bool validateAsmConstraint(const char *&Name, |
238 | TargetInfo::ConstraintInfo &Info) const override { |
239 | switch (*Name) { |
240 | default: |
241 | return false; |
242 | case 'r': // CPU registers. |
243 | case 'd': // Equivalent to "r" unless generating MIPS16 code. |
244 | case 'y': // Equivalent to "r", backward compatibility only. |
245 | case 'c': // $25 for indirect jumps |
246 | case 'l': // lo register |
247 | case 'x': // hilo register pair |
248 | Info.setAllowsRegister(); |
249 | return true; |
250 | case 'f': // floating-point registers. |
251 | Info.setAllowsRegister(); |
252 | return FloatABI != SoftFloat; |
253 | case 'I': // Signed 16-bit constant |
254 | case 'J': // Integer 0 |
255 | case 'K': // Unsigned 16-bit constant |
256 | case 'L': // Signed 32-bit constant, lower 16-bit zeros (for lui) |
257 | case 'M': // Constants not loadable via lui, addiu, or ori |
258 | case 'N': // Constant -1 to -65535 |
259 | case 'O': // A signed 15-bit constant |
260 | case 'P': // A constant between 1 go 65535 |
261 | return true; |
262 | case 'R': // An address that can be used in a non-macro load or store |
263 | Info.setAllowsMemory(); |
264 | return true; |
265 | case 'Z': |
266 | if (Name[1] == 'C') { // An address usable by ll, and sc. |
267 | Info.setAllowsMemory(); |
268 | Name++; // Skip over 'Z'. |
269 | return true; |
270 | } |
271 | return false; |
272 | } |
273 | } |
274 | |
275 | std::string convertConstraint(const char *&Constraint) const override { |
276 | std::string R; |
277 | switch (*Constraint) { |
278 | case 'Z': // Two-character constraint; add "^" hint for later parsing. |
279 | if (Constraint[1] == 'C') { |
280 | R = std::string("^" ) + std::string(Constraint, 2); |
281 | Constraint++; |
282 | return R; |
283 | } |
284 | break; |
285 | } |
286 | return TargetInfo::convertConstraint(Constraint); |
287 | } |
288 | |
289 | std::string_view getClobbers() const override { |
290 | // In GCC, $1 is not widely used in generated code (it's used only in a few |
291 | // specific situations), so there is no real need for users to add it to |
292 | // the clobbers list if they want to use it in their inline assembly code. |
293 | // |
294 | // In LLVM, $1 is treated as a normal GPR and is always allocatable during |
295 | // code generation, so using it in inline assembly without adding it to the |
296 | // clobbers list can cause conflicts between the inline assembly code and |
297 | // the surrounding generated code. |
298 | // |
299 | // Another problem is that LLVM is allowed to choose $1 for inline assembly |
300 | // operands, which will conflict with the ".set at" assembler option (which |
301 | // we use only for inline assembly, in order to maintain compatibility with |
302 | // GCC) and will also conflict with the user's usage of $1. |
303 | // |
304 | // The easiest way to avoid these conflicts and keep $1 as an allocatable |
305 | // register for generated code is to automatically clobber $1 for all inline |
306 | // assembly code. |
307 | // |
308 | // FIXME: We should automatically clobber $1 only for inline assembly code |
309 | // which actually uses it. This would allow LLVM to use $1 for inline |
310 | // assembly operands if the user's assembly code doesn't use it. |
311 | return "~{$1}" ; |
312 | } |
313 | |
314 | bool handleTargetFeatures(std::vector<std::string> &Features, |
315 | DiagnosticsEngine &Diags) override { |
316 | IsMips16 = false; |
317 | IsMicromips = false; |
318 | IsNan2008 = isIEEE754_2008Default(); |
319 | IsAbs2008 = isIEEE754_2008Default(); |
320 | IsSingleFloat = false; |
321 | FloatABI = HardFloat; |
322 | DspRev = NoDSP; |
323 | NoOddSpreg = false; |
324 | FPMode = getDefaultFPMode(); |
325 | bool OddSpregGiven = false; |
326 | bool StrictAlign = false; |
327 | bool FpGiven = false; |
328 | |
329 | for (const auto &Feature : Features) { |
330 | if (Feature == "+single-float" ) |
331 | IsSingleFloat = true; |
332 | else if (Feature == "+soft-float" ) |
333 | FloatABI = SoftFloat; |
334 | else if (Feature == "+mips16" ) |
335 | IsMips16 = true; |
336 | else if (Feature == "+micromips" ) |
337 | IsMicromips = true; |
338 | else if (Feature == "+mips32r6" || Feature == "+mips64r6" ) |
339 | HasUnalignedAccess = true; |
340 | // We cannot be sure that the order of strict-align vs mips32r6. |
341 | // Thus we need an extra variable here. |
342 | else if (Feature == "+strict-align" ) |
343 | StrictAlign = true; |
344 | else if (Feature == "+dsp" ) |
345 | DspRev = std::max(a: DspRev, b: DSP1); |
346 | else if (Feature == "+dspr2" ) |
347 | DspRev = std::max(a: DspRev, b: DSP2); |
348 | else if (Feature == "+msa" ) |
349 | HasMSA = true; |
350 | else if (Feature == "+nomadd4" ) |
351 | DisableMadd4 = true; |
352 | else if (Feature == "+fp64" ) { |
353 | FPMode = FP64; |
354 | FpGiven = true; |
355 | } else if (Feature == "-fp64" ) { |
356 | FPMode = FP32; |
357 | FpGiven = true; |
358 | } else if (Feature == "+fpxx" ) { |
359 | FPMode = FPXX; |
360 | FpGiven = true; |
361 | } else if (Feature == "+nan2008" ) |
362 | IsNan2008 = true; |
363 | else if (Feature == "-nan2008" ) |
364 | IsNan2008 = false; |
365 | else if (Feature == "+abs2008" ) |
366 | IsAbs2008 = true; |
367 | else if (Feature == "-abs2008" ) |
368 | IsAbs2008 = false; |
369 | else if (Feature == "+noabicalls" ) |
370 | IsNoABICalls = true; |
371 | else if (Feature == "+use-indirect-jump-hazard" ) |
372 | UseIndirectJumpHazard = true; |
373 | else if (Feature == "+nooddspreg" ) { |
374 | NoOddSpreg = true; |
375 | OddSpregGiven = false; |
376 | } else if (Feature == "-nooddspreg" ) { |
377 | NoOddSpreg = false; |
378 | OddSpregGiven = true; |
379 | } |
380 | } |
381 | |
382 | if (FPMode == FPXX && !OddSpregGiven) |
383 | NoOddSpreg = true; |
384 | |
385 | if (StrictAlign) |
386 | HasUnalignedAccess = false; |
387 | |
388 | if (HasMSA && !FpGiven) { |
389 | FPMode = FP64; |
390 | Features.push_back(x: "+fp64" ); |
391 | } |
392 | |
393 | setDataLayout(); |
394 | |
395 | return true; |
396 | } |
397 | |
398 | int getEHDataRegisterNumber(unsigned RegNo) const override { |
399 | if (RegNo == 0) |
400 | return 4; |
401 | if (RegNo == 1) |
402 | return 5; |
403 | return -1; |
404 | } |
405 | |
406 | bool isCLZForZeroUndef() const override { return false; } |
407 | |
408 | ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { |
409 | static const TargetInfo::GCCRegAlias O32RegAliases[] = { |
410 | {.Aliases: {"at" }, .Register: "$1" }, {.Aliases: {"v0" }, .Register: "$2" }, {.Aliases: {"v1" }, .Register: "$3" }, |
411 | {.Aliases: {"a0" }, .Register: "$4" }, {.Aliases: {"a1" }, .Register: "$5" }, {.Aliases: {"a2" }, .Register: "$6" }, |
412 | {.Aliases: {"a3" }, .Register: "$7" }, {.Aliases: {"t0" }, .Register: "$8" }, {.Aliases: {"t1" }, .Register: "$9" }, |
413 | {.Aliases: {"t2" }, .Register: "$10" }, {.Aliases: {"t3" }, .Register: "$11" }, {.Aliases: {"t4" }, .Register: "$12" }, |
414 | {.Aliases: {"t5" }, .Register: "$13" }, {.Aliases: {"t6" }, .Register: "$14" }, {.Aliases: {"t7" }, .Register: "$15" }, |
415 | {.Aliases: {"s0" }, .Register: "$16" }, {.Aliases: {"s1" }, .Register: "$17" }, {.Aliases: {"s2" }, .Register: "$18" }, |
416 | {.Aliases: {"s3" }, .Register: "$19" }, {.Aliases: {"s4" }, .Register: "$20" }, {.Aliases: {"s5" }, .Register: "$21" }, |
417 | {.Aliases: {"s6" }, .Register: "$22" }, {.Aliases: {"s7" }, .Register: "$23" }, {.Aliases: {"t8" }, .Register: "$24" }, |
418 | {.Aliases: {"t9" }, .Register: "$25" }, {.Aliases: {"k0" }, .Register: "$26" }, {.Aliases: {"k1" }, .Register: "$27" }, |
419 | {.Aliases: {"gp" }, .Register: "$28" }, {.Aliases: {"sp" , "$sp" }, .Register: "$29" }, {.Aliases: {"fp" , "$fp" }, .Register: "$30" }, |
420 | {.Aliases: {"ra" }, .Register: "$31" } |
421 | }; |
422 | static const TargetInfo::GCCRegAlias NewABIRegAliases[] = { |
423 | {.Aliases: {"at" }, .Register: "$1" }, {.Aliases: {"v0" }, .Register: "$2" }, {.Aliases: {"v1" }, .Register: "$3" }, |
424 | {.Aliases: {"a0" }, .Register: "$4" }, {.Aliases: {"a1" }, .Register: "$5" }, {.Aliases: {"a2" }, .Register: "$6" }, |
425 | {.Aliases: {"a3" }, .Register: "$7" }, {.Aliases: {"a4" }, .Register: "$8" }, {.Aliases: {"a5" }, .Register: "$9" }, |
426 | {.Aliases: {"a6" }, .Register: "$10" }, {.Aliases: {"a7" }, .Register: "$11" }, {.Aliases: {"t0" }, .Register: "$12" }, |
427 | {.Aliases: {"t1" }, .Register: "$13" }, {.Aliases: {"t2" }, .Register: "$14" }, {.Aliases: {"t3" }, .Register: "$15" }, |
428 | {.Aliases: {"s0" }, .Register: "$16" }, {.Aliases: {"s1" }, .Register: "$17" }, {.Aliases: {"s2" }, .Register: "$18" }, |
429 | {.Aliases: {"s3" }, .Register: "$19" }, {.Aliases: {"s4" }, .Register: "$20" }, {.Aliases: {"s5" }, .Register: "$21" }, |
430 | {.Aliases: {"s6" }, .Register: "$22" }, {.Aliases: {"s7" }, .Register: "$23" }, {.Aliases: {"t8" }, .Register: "$24" }, |
431 | {.Aliases: {"t9" }, .Register: "$25" }, {.Aliases: {"k0" }, .Register: "$26" }, {.Aliases: {"k1" }, .Register: "$27" }, |
432 | {.Aliases: {"gp" }, .Register: "$28" }, {.Aliases: {"sp" , "$sp" }, .Register: "$29" }, {.Aliases: {"fp" , "$fp" }, .Register: "$30" }, |
433 | {.Aliases: {"ra" }, .Register: "$31" } |
434 | }; |
435 | if (ABI == "o32" ) |
436 | return llvm::ArrayRef(O32RegAliases); |
437 | return llvm::ArrayRef(NewABIRegAliases); |
438 | } |
439 | |
440 | bool hasInt128Type() const override { |
441 | return (ABI == "n32" || ABI == "n64" ) || getTargetOpts().ForceEnableInt128; |
442 | } |
443 | |
444 | unsigned getUnwindWordWidth() const override; |
445 | |
446 | bool validateTarget(DiagnosticsEngine &Diags) const override; |
447 | bool hasBitIntType() const override { return true; } |
448 | |
449 | std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override { |
450 | return std::make_pair(x: 32, y: 32); |
451 | } |
452 | }; |
453 | } // namespace targets |
454 | } // namespace clang |
455 | |
456 | #endif // LLVM_CLANG_LIB_BASIC_TARGETS_MIPS_H |
457 | |