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