1 | //===--- Mips.cpp - Tools Implementations -----------------------*- 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 | #include "Mips.h" |
10 | #include "ToolChains/CommonArgs.h" |
11 | #include "clang/Driver/Driver.h" |
12 | #include "clang/Driver/DriverDiagnostic.h" |
13 | #include "clang/Driver/Options.h" |
14 | #include "llvm/ADT/StringSwitch.h" |
15 | #include "llvm/Option/ArgList.h" |
16 | |
17 | using namespace clang::driver; |
18 | using namespace clang::driver::tools; |
19 | using namespace clang; |
20 | using namespace llvm::opt; |
21 | |
22 | // Get CPU and ABI names. They are not independent |
23 | // so we have to calculate them together. |
24 | void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple, |
25 | StringRef &CPUName, StringRef &ABIName) { |
26 | const char *DefMips32CPU = "mips32r2" ; |
27 | const char *DefMips64CPU = "mips64r2" ; |
28 | |
29 | // MIPS32r6 is the default for mips(el)?-img-linux-gnu and MIPS64r6 is the |
30 | // default for mips64(el)?-img-linux-gnu. |
31 | if (Triple.getVendor() == llvm::Triple::ImaginationTechnologies && |
32 | Triple.isGNUEnvironment()) { |
33 | DefMips32CPU = "mips32r6" ; |
34 | DefMips64CPU = "mips64r6" ; |
35 | } |
36 | |
37 | if (Triple.getSubArch() == llvm::Triple::MipsSubArch_r6) { |
38 | DefMips32CPU = "mips32r6" ; |
39 | DefMips64CPU = "mips64r6" ; |
40 | } |
41 | |
42 | // MIPS3 is the default for mips64*-unknown-openbsd. |
43 | if (Triple.isOSOpenBSD()) |
44 | DefMips64CPU = "mips3" ; |
45 | |
46 | // MIPS2 is the default for mips(el)?-unknown-freebsd. |
47 | // MIPS3 is the default for mips64(el)?-unknown-freebsd. |
48 | if (Triple.isOSFreeBSD()) { |
49 | DefMips32CPU = "mips2" ; |
50 | DefMips64CPU = "mips3" ; |
51 | } |
52 | |
53 | if (Arg *A = Args.getLastArg(Ids: clang::driver::options::OPT_march_EQ, |
54 | Ids: options::OPT_mcpu_EQ)) |
55 | CPUName = A->getValue(); |
56 | |
57 | if (Arg *A = Args.getLastArg(Ids: options::OPT_mabi_EQ)) { |
58 | ABIName = A->getValue(); |
59 | // Convert a GNU style Mips ABI name to the name |
60 | // accepted by LLVM Mips backend. |
61 | ABIName = llvm::StringSwitch<llvm::StringRef>(ABIName) |
62 | .Case(S: "32" , Value: "o32" ) |
63 | .Case(S: "64" , Value: "n64" ) |
64 | .Default(Value: ABIName); |
65 | } |
66 | |
67 | // Setup default CPU and ABI names. |
68 | if (CPUName.empty() && ABIName.empty()) { |
69 | switch (Triple.getArch()) { |
70 | default: |
71 | llvm_unreachable("Unexpected triple arch name" ); |
72 | case llvm::Triple::mips: |
73 | case llvm::Triple::mipsel: |
74 | CPUName = DefMips32CPU; |
75 | break; |
76 | case llvm::Triple::mips64: |
77 | case llvm::Triple::mips64el: |
78 | CPUName = DefMips64CPU; |
79 | break; |
80 | } |
81 | } |
82 | |
83 | if (ABIName.empty() && (Triple.getEnvironment() == llvm::Triple::GNUABIN32)) |
84 | ABIName = "n32" ; |
85 | |
86 | if (ABIName.empty() && |
87 | (Triple.getVendor() == llvm::Triple::MipsTechnologies || |
88 | Triple.getVendor() == llvm::Triple::ImaginationTechnologies)) { |
89 | ABIName = llvm::StringSwitch<const char *>(CPUName) |
90 | .Case(S: "mips1" , Value: "o32" ) |
91 | .Case(S: "mips2" , Value: "o32" ) |
92 | .Case(S: "mips3" , Value: "n64" ) |
93 | .Case(S: "mips4" , Value: "n64" ) |
94 | .Case(S: "mips5" , Value: "n64" ) |
95 | .Case(S: "mips32" , Value: "o32" ) |
96 | .Case(S: "mips32r2" , Value: "o32" ) |
97 | .Case(S: "mips32r3" , Value: "o32" ) |
98 | .Case(S: "mips32r5" , Value: "o32" ) |
99 | .Case(S: "mips32r6" , Value: "o32" ) |
100 | .Case(S: "mips64" , Value: "n64" ) |
101 | .Case(S: "mips64r2" , Value: "n64" ) |
102 | .Case(S: "mips64r3" , Value: "n64" ) |
103 | .Case(S: "mips64r5" , Value: "n64" ) |
104 | .Case(S: "mips64r6" , Value: "n64" ) |
105 | .Case(S: "octeon" , Value: "n64" ) |
106 | .Case(S: "p5600" , Value: "o32" ) |
107 | .Default(Value: "" ); |
108 | } |
109 | |
110 | if (ABIName.empty()) { |
111 | // Deduce ABI name from the target triple. |
112 | ABIName = Triple.isMIPS32() ? "o32" : "n64" ; |
113 | } |
114 | |
115 | if (CPUName.empty()) { |
116 | // Deduce CPU name from ABI name. |
117 | CPUName = llvm::StringSwitch<const char *>(ABIName) |
118 | .Case(S: "o32" , Value: DefMips32CPU) |
119 | .Cases(S0: "n32" , S1: "n64" , Value: DefMips64CPU) |
120 | .Default(Value: "" ); |
121 | } |
122 | |
123 | // FIXME: Warn on inconsistent use of -march and -mabi. |
124 | } |
125 | |
126 | std::string mips::getMipsABILibSuffix(const ArgList &Args, |
127 | const llvm::Triple &Triple) { |
128 | StringRef CPUName, ABIName; |
129 | tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); |
130 | return llvm::StringSwitch<std::string>(ABIName) |
131 | .Case(S: "o32" , Value: "" ) |
132 | .Case(S: "n32" , Value: "32" ) |
133 | .Case(S: "n64" , Value: "64" ); |
134 | } |
135 | |
136 | // Convert ABI name to the GNU tools acceptable variant. |
137 | StringRef mips::getGnuCompatibleMipsABIName(StringRef ABI) { |
138 | return llvm::StringSwitch<llvm::StringRef>(ABI) |
139 | .Case(S: "o32" , Value: "32" ) |
140 | .Case(S: "n64" , Value: "64" ) |
141 | .Default(Value: ABI); |
142 | } |
143 | |
144 | // Select the MIPS float ABI as determined by -msoft-float, -mhard-float, |
145 | // and -mfloat-abi=. |
146 | mips::FloatABI mips::getMipsFloatABI(const Driver &D, const ArgList &Args, |
147 | const llvm::Triple &Triple) { |
148 | mips::FloatABI ABI = mips::FloatABI::Invalid; |
149 | if (Arg *A = |
150 | Args.getLastArg(Ids: options::OPT_msoft_float, Ids: options::OPT_mhard_float, |
151 | Ids: options::OPT_mfloat_abi_EQ)) { |
152 | if (A->getOption().matches(ID: options::OPT_msoft_float)) |
153 | ABI = mips::FloatABI::Soft; |
154 | else if (A->getOption().matches(ID: options::OPT_mhard_float)) |
155 | ABI = mips::FloatABI::Hard; |
156 | else { |
157 | ABI = llvm::StringSwitch<mips::FloatABI>(A->getValue()) |
158 | .Case(S: "soft" , Value: mips::FloatABI::Soft) |
159 | .Case(S: "hard" , Value: mips::FloatABI::Hard) |
160 | .Default(Value: mips::FloatABI::Invalid); |
161 | if (ABI == mips::FloatABI::Invalid && !StringRef(A->getValue()).empty()) { |
162 | D.Diag(DiagID: clang::diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); |
163 | ABI = mips::FloatABI::Hard; |
164 | } |
165 | } |
166 | } |
167 | |
168 | // If unspecified, choose the default based on the platform. |
169 | if (ABI == mips::FloatABI::Invalid) { |
170 | if (Triple.isOSFreeBSD()) { |
171 | // For FreeBSD, assume "soft" on all flavors of MIPS. |
172 | ABI = mips::FloatABI::Soft; |
173 | } else { |
174 | // Assume "hard", because it's a default value used by gcc. |
175 | // When we start to recognize specific target MIPS processors, |
176 | // we will be able to select the default more correctly. |
177 | ABI = mips::FloatABI::Hard; |
178 | } |
179 | } |
180 | |
181 | assert(ABI != mips::FloatABI::Invalid && "must select an ABI" ); |
182 | return ABI; |
183 | } |
184 | |
185 | void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, |
186 | const ArgList &Args, |
187 | std::vector<StringRef> &Features) { |
188 | StringRef CPUName; |
189 | StringRef ABIName; |
190 | getMipsCPUAndABI(Args, Triple, CPUName, ABIName); |
191 | ABIName = getGnuCompatibleMipsABIName(ABI: ABIName); |
192 | |
193 | // Historically, PIC code for MIPS was associated with -mabicalls, a.k.a |
194 | // SVR4 abicalls. Static code does not use SVR4 calling sequences. An ABI |
195 | // extension was developed by Richard Sandiford & Code Sourcery to support |
196 | // static code calling PIC code (CPIC). For O32 and N32 this means we have |
197 | // several combinations of PIC/static and abicalls. Pure static, static |
198 | // with the CPIC extension, and pure PIC code. |
199 | |
200 | // At final link time, O32 and N32 with CPIC will have another section |
201 | // added to the binary which contains the stub functions to perform |
202 | // any fixups required for PIC code. |
203 | |
204 | // For N64, the situation is more regular: code can either be static |
205 | // (non-abicalls) or PIC (abicalls). GCC has traditionally picked PIC code |
206 | // code for N64. Since Clang has already built the relocation model portion |
207 | // of the commandline, we pick add +noabicalls feature in the N64 static |
208 | // case. |
209 | |
210 | // The is another case to be accounted for: -msym32, which enforces that all |
211 | // symbols have 32 bits in size. In this case, N64 can in theory use CPIC |
212 | // but it is unsupported. |
213 | |
214 | // The combinations for N64 are: |
215 | // a) Static without abicalls and 64bit symbols. |
216 | // b) Static with abicalls and 32bit symbols. |
217 | // c) PIC with abicalls and 64bit symbols. |
218 | |
219 | // For case (a) we need to add +noabicalls for N64. |
220 | |
221 | bool IsN64 = ABIName == "64" ; |
222 | bool IsPIC = false; |
223 | bool NonPIC = false; |
224 | bool HasNaN2008Opt = false; |
225 | |
226 | Arg *LastPICArg = Args.getLastArg(Ids: options::OPT_fPIC, Ids: options::OPT_fno_PIC, |
227 | Ids: options::OPT_fpic, Ids: options::OPT_fno_pic, |
228 | Ids: options::OPT_fPIE, Ids: options::OPT_fno_PIE, |
229 | Ids: options::OPT_fpie, Ids: options::OPT_fno_pie); |
230 | if (LastPICArg) { |
231 | Option O = LastPICArg->getOption(); |
232 | NonPIC = |
233 | (O.matches(ID: options::OPT_fno_PIC) || O.matches(ID: options::OPT_fno_pic) || |
234 | O.matches(ID: options::OPT_fno_PIE) || O.matches(ID: options::OPT_fno_pie)); |
235 | IsPIC = |
236 | (O.matches(ID: options::OPT_fPIC) || O.matches(ID: options::OPT_fpic) || |
237 | O.matches(ID: options::OPT_fPIE) || O.matches(ID: options::OPT_fpie)); |
238 | } |
239 | |
240 | bool UseAbiCalls = false; |
241 | |
242 | Arg *ABICallsArg = |
243 | Args.getLastArg(Ids: options::OPT_mabicalls, Ids: options::OPT_mno_abicalls); |
244 | UseAbiCalls = |
245 | !ABICallsArg || ABICallsArg->getOption().matches(ID: options::OPT_mabicalls); |
246 | |
247 | if (IsN64 && NonPIC && (!ABICallsArg || UseAbiCalls)) { |
248 | D.Diag(DiagID: diag::warn_drv_unsupported_pic_with_mabicalls) |
249 | << LastPICArg->getAsString(Args) << (!ABICallsArg ? 0 : 1); |
250 | } |
251 | |
252 | if (ABICallsArg && !UseAbiCalls && IsPIC) { |
253 | D.Diag(DiagID: diag::err_drv_unsupported_noabicalls_pic); |
254 | } |
255 | |
256 | if (!UseAbiCalls) |
257 | Features.push_back(x: "+noabicalls" ); |
258 | else |
259 | Features.push_back(x: "-noabicalls" ); |
260 | |
261 | if (Arg *A = Args.getLastArg(Ids: options::OPT_mlong_calls, |
262 | Ids: options::OPT_mno_long_calls)) { |
263 | if (A->getOption().matches(ID: options::OPT_mno_long_calls)) |
264 | Features.push_back(x: "-long-calls" ); |
265 | else if (!UseAbiCalls) |
266 | Features.push_back(x: "+long-calls" ); |
267 | else |
268 | D.Diag(DiagID: diag::warn_drv_unsupported_longcalls) << (ABICallsArg ? 0 : 1); |
269 | } |
270 | |
271 | if (Arg *A = Args.getLastArg(Ids: options::OPT_mxgot, Ids: options::OPT_mno_xgot)) { |
272 | if (A->getOption().matches(ID: options::OPT_mxgot)) |
273 | Features.push_back(x: "+xgot" ); |
274 | else |
275 | Features.push_back(x: "-xgot" ); |
276 | } |
277 | |
278 | mips::FloatABI FloatABI = mips::getMipsFloatABI(D, Args, Triple); |
279 | if (FloatABI == mips::FloatABI::Soft) { |
280 | // FIXME: Note, this is a hack. We need to pass the selected float |
281 | // mode to the MipsTargetInfoBase to define appropriate macros there. |
282 | // Now it is the only method. |
283 | Features.push_back(x: "+soft-float" ); |
284 | } |
285 | |
286 | if (Arg *A = Args.getLastArg(Ids: options::OPT_mnan_EQ)) { |
287 | StringRef Val = StringRef(A->getValue()); |
288 | if (Val == "2008" ) { |
289 | if (mips::getIEEE754Standard(CPU&: CPUName) & mips::Std2008) { |
290 | Features.push_back(x: "+nan2008" ); |
291 | HasNaN2008Opt = true; |
292 | } else { |
293 | Features.push_back(x: "-nan2008" ); |
294 | D.Diag(DiagID: diag::warn_target_unsupported_nan2008) << CPUName; |
295 | } |
296 | } else if (Val == "legacy" ) { |
297 | if (mips::getIEEE754Standard(CPU&: CPUName) & mips::Legacy) |
298 | Features.push_back(x: "-nan2008" ); |
299 | else { |
300 | Features.push_back(x: "+nan2008" ); |
301 | D.Diag(DiagID: diag::warn_target_unsupported_nanlegacy) << CPUName; |
302 | } |
303 | } else |
304 | D.Diag(DiagID: diag::err_drv_unsupported_option_argument) |
305 | << A->getSpelling() << Val; |
306 | } |
307 | |
308 | if (Arg *A = Args.getLastArg(Ids: options::OPT_mabs_EQ)) { |
309 | StringRef Val = StringRef(A->getValue()); |
310 | if (Val == "2008" ) { |
311 | if (mips::getIEEE754Standard(CPU&: CPUName) & mips::Std2008) { |
312 | Features.push_back(x: "+abs2008" ); |
313 | } else { |
314 | Features.push_back(x: "-abs2008" ); |
315 | D.Diag(DiagID: diag::warn_target_unsupported_abs2008) << CPUName; |
316 | } |
317 | } else if (Val == "legacy" ) { |
318 | if (mips::getIEEE754Standard(CPU&: CPUName) & mips::Legacy) { |
319 | Features.push_back(x: "-abs2008" ); |
320 | } else { |
321 | Features.push_back(x: "+abs2008" ); |
322 | D.Diag(DiagID: diag::warn_target_unsupported_abslegacy) << CPUName; |
323 | } |
324 | } else { |
325 | D.Diag(DiagID: diag::err_drv_unsupported_option_argument) |
326 | << A->getSpelling() << Val; |
327 | } |
328 | } else if (HasNaN2008Opt) { |
329 | Features.push_back(x: "+abs2008" ); |
330 | } |
331 | |
332 | AddTargetFeature(Args, Features, OnOpt: options::OPT_msingle_float, |
333 | OffOpt: options::OPT_mdouble_float, FeatureName: "single-float" ); |
334 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mips16, OffOpt: options::OPT_mno_mips16, |
335 | FeatureName: "mips16" ); |
336 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mmicromips, |
337 | OffOpt: options::OPT_mno_micromips, FeatureName: "micromips" ); |
338 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mdsp, OffOpt: options::OPT_mno_dsp, |
339 | FeatureName: "dsp" ); |
340 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mdspr2, OffOpt: options::OPT_mno_dspr2, |
341 | FeatureName: "dspr2" ); |
342 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mmsa, OffOpt: options::OPT_mno_msa, |
343 | FeatureName: "msa" ); |
344 | if (Arg *A = Args.getLastArg( |
345 | Ids: options::OPT_mstrict_align, Ids: options::OPT_mno_strict_align, |
346 | Ids: options::OPT_mno_unaligned_access, Ids: options::OPT_munaligned_access)) { |
347 | if (A->getOption().matches(ID: options::OPT_mstrict_align) || |
348 | A->getOption().matches(ID: options::OPT_mno_unaligned_access)) |
349 | Features.push_back(x: Args.MakeArgString(Str: "+strict-align" )); |
350 | else |
351 | Features.push_back(x: Args.MakeArgString(Str: "-strict-align" )); |
352 | } |
353 | |
354 | // Add the last -mfp32/-mfpxx/-mfp64, if none are given and the ABI is O32 |
355 | // pass -mfpxx, or if none are given and fp64a is default, pass fp64 and |
356 | // nooddspreg. |
357 | if (Arg *A = Args.getLastArg(Ids: options::OPT_mfp32, Ids: options::OPT_mfpxx, |
358 | Ids: options::OPT_mfp64)) { |
359 | if (A->getOption().matches(ID: options::OPT_mfp32)) |
360 | Features.push_back(x: "-fp64" ); |
361 | else if (A->getOption().matches(ID: options::OPT_mfpxx)) { |
362 | Features.push_back(x: "+fpxx" ); |
363 | Features.push_back(x: "+nooddspreg" ); |
364 | } else |
365 | Features.push_back(x: "+fp64" ); |
366 | } else if (mips::shouldUseFPXX(Args, Triple, CPUName, ABIName, FloatABI)) { |
367 | Features.push_back(x: "+fpxx" ); |
368 | Features.push_back(x: "+nooddspreg" ); |
369 | } else if (mips::isFP64ADefault(Triple, CPUName)) { |
370 | Features.push_back(x: "+fp64" ); |
371 | Features.push_back(x: "+nooddspreg" ); |
372 | } else if (Arg *A = Args.getLastArg(Ids: options::OPT_mmsa)) { |
373 | if (A->getOption().matches(ID: options::OPT_mmsa)) |
374 | Features.push_back(x: "+fp64" ); |
375 | } |
376 | |
377 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mno_odd_spreg, |
378 | OffOpt: options::OPT_modd_spreg, FeatureName: "nooddspreg" ); |
379 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mno_madd4, OffOpt: options::OPT_mmadd4, |
380 | FeatureName: "nomadd4" ); |
381 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mmt, OffOpt: options::OPT_mno_mt, FeatureName: "mt" ); |
382 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mcrc, OffOpt: options::OPT_mno_crc, |
383 | FeatureName: "crc" ); |
384 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mvirt, OffOpt: options::OPT_mno_virt, |
385 | FeatureName: "virt" ); |
386 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mginv, OffOpt: options::OPT_mno_ginv, |
387 | FeatureName: "ginv" ); |
388 | |
389 | if (Arg *A = Args.getLastArg(Ids: options::OPT_mindirect_jump_EQ)) { |
390 | StringRef Val = StringRef(A->getValue()); |
391 | if (Val == "hazard" ) { |
392 | Arg *B = |
393 | Args.getLastArg(Ids: options::OPT_mmicromips, Ids: options::OPT_mno_micromips); |
394 | Arg *C = Args.getLastArg(Ids: options::OPT_mips16, Ids: options::OPT_mno_mips16); |
395 | |
396 | if (B && B->getOption().matches(ID: options::OPT_mmicromips)) |
397 | D.Diag(DiagID: diag::err_drv_unsupported_indirect_jump_opt) |
398 | << "hazard" << "micromips" ; |
399 | else if (C && C->getOption().matches(ID: options::OPT_mips16)) |
400 | D.Diag(DiagID: diag::err_drv_unsupported_indirect_jump_opt) |
401 | << "hazard" << "mips16" ; |
402 | else if (mips::supportsIndirectJumpHazardBarrier(CPU&: CPUName)) |
403 | Features.push_back(x: "+use-indirect-jump-hazard" ); |
404 | else |
405 | D.Diag(DiagID: diag::err_drv_unsupported_indirect_jump_opt) |
406 | << "hazard" << CPUName; |
407 | } else |
408 | D.Diag(DiagID: diag::err_drv_unknown_indirect_jump_opt) << Val; |
409 | } |
410 | } |
411 | |
412 | mips::IEEE754Standard mips::getIEEE754Standard(StringRef &CPU) { |
413 | // Strictly speaking, mips32r2 and mips64r2 do not conform to the |
414 | // IEEE754-2008 standard. Support for this standard was first introduced |
415 | // in Release 3. However, other compilers have traditionally allowed it |
416 | // for Release 2 so we should do the same. |
417 | return (IEEE754Standard)llvm::StringSwitch<int>(CPU) |
418 | .Case(S: "mips1" , Value: Legacy) |
419 | .Case(S: "mips2" , Value: Legacy) |
420 | .Case(S: "mips3" , Value: Legacy) |
421 | .Case(S: "mips4" , Value: Legacy) |
422 | .Case(S: "mips5" , Value: Legacy) |
423 | .Case(S: "mips32" , Value: Legacy) |
424 | .Case(S: "mips32r2" , Value: Legacy | Std2008) |
425 | .Case(S: "mips32r3" , Value: Legacy | Std2008) |
426 | .Case(S: "mips32r5" , Value: Legacy | Std2008) |
427 | .Case(S: "mips32r6" , Value: Std2008) |
428 | .Case(S: "mips64" , Value: Legacy) |
429 | .Case(S: "mips64r2" , Value: Legacy | Std2008) |
430 | .Case(S: "mips64r3" , Value: Legacy | Std2008) |
431 | .Case(S: "mips64r5" , Value: Legacy | Std2008) |
432 | .Case(S: "mips64r6" , Value: Std2008) |
433 | .Default(Value: Std2008); |
434 | } |
435 | |
436 | bool mips::hasCompactBranches(StringRef &CPU) { |
437 | // mips32r6 and mips64r6 have compact branches. |
438 | return llvm::StringSwitch<bool>(CPU) |
439 | .Case(S: "mips32r6" , Value: true) |
440 | .Case(S: "mips64r6" , Value: true) |
441 | .Default(Value: false); |
442 | } |
443 | |
444 | bool mips::hasMipsAbiArg(const ArgList &Args, const char *Value) { |
445 | Arg *A = Args.getLastArg(Ids: options::OPT_mabi_EQ); |
446 | return A && (A->getValue() == StringRef(Value)); |
447 | } |
448 | |
449 | bool mips::isUCLibc(const ArgList &Args) { |
450 | Arg *A = Args.getLastArg(Ids: options::OPT_m_libc_Group); |
451 | return A && A->getOption().matches(ID: options::OPT_muclibc); |
452 | } |
453 | |
454 | bool mips::isNaN2008(const Driver &D, const ArgList &Args, |
455 | const llvm::Triple &Triple) { |
456 | if (Arg *NaNArg = Args.getLastArg(Ids: options::OPT_mnan_EQ)) |
457 | return llvm::StringSwitch<bool>(NaNArg->getValue()) |
458 | .Case(S: "2008" , Value: true) |
459 | .Case(S: "legacy" , Value: false) |
460 | .Default(Value: false); |
461 | |
462 | // NaN2008 is the default for MIPS32r6/MIPS64r6. |
463 | return llvm::StringSwitch<bool>(getCPUName(D, Args, T: Triple)) |
464 | .Cases(S0: "mips32r6" , S1: "mips64r6" , Value: true) |
465 | .Default(Value: false); |
466 | } |
467 | |
468 | bool mips::isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName) { |
469 | if (!Triple.isAndroid()) |
470 | return false; |
471 | |
472 | // Android MIPS32R6 defaults to FP64A. |
473 | return llvm::StringSwitch<bool>(CPUName) |
474 | .Case(S: "mips32r6" , Value: true) |
475 | .Default(Value: false); |
476 | } |
477 | |
478 | bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, |
479 | StringRef ABIName, mips::FloatABI FloatABI) { |
480 | if (ABIName != "32" ) |
481 | return false; |
482 | |
483 | // FPXX shouldn't be used if either -msoft-float or -mfloat-abi=soft is |
484 | // present. |
485 | if (FloatABI == mips::FloatABI::Soft) |
486 | return false; |
487 | |
488 | return llvm::StringSwitch<bool>(CPUName) |
489 | .Cases(S0: "mips2" , S1: "mips3" , S2: "mips4" , S3: "mips5" , Value: true) |
490 | .Cases(S0: "mips32" , S1: "mips32r2" , S2: "mips32r3" , S3: "mips32r5" , Value: true) |
491 | .Cases(S0: "mips64" , S1: "mips64r2" , S2: "mips64r3" , S3: "mips64r5" , Value: true) |
492 | .Default(Value: false); |
493 | } |
494 | |
495 | bool mips::shouldUseFPXX(const ArgList &Args, const llvm::Triple &Triple, |
496 | StringRef CPUName, StringRef ABIName, |
497 | mips::FloatABI FloatABI) { |
498 | bool UseFPXX = isFPXXDefault(Triple, CPUName, ABIName, FloatABI); |
499 | |
500 | // FPXX shouldn't be used if -msingle-float is present. |
501 | if (Arg *A = Args.getLastArg(Ids: options::OPT_msingle_float, |
502 | Ids: options::OPT_mdouble_float)) |
503 | if (A->getOption().matches(ID: options::OPT_msingle_float)) |
504 | UseFPXX = false; |
505 | // FP64 should be used for MSA. |
506 | if (Arg *A = Args.getLastArg(Ids: options::OPT_mmsa)) |
507 | if (A->getOption().matches(ID: options::OPT_mmsa)) |
508 | UseFPXX = llvm::StringSwitch<bool>(CPUName) |
509 | .Cases(S0: "mips32r2" , S1: "mips32r3" , S2: "mips32r5" , Value: false) |
510 | .Cases(S0: "mips64r2" , S1: "mips64r3" , S2: "mips64r5" , Value: false) |
511 | .Default(Value: UseFPXX); |
512 | |
513 | return UseFPXX; |
514 | } |
515 | |
516 | bool mips::supportsIndirectJumpHazardBarrier(StringRef &CPU) { |
517 | // Supporting the hazard barrier method of dealing with indirect |
518 | // jumps requires MIPSR2 support. |
519 | return llvm::StringSwitch<bool>(CPU) |
520 | .Case(S: "mips32r2" , Value: true) |
521 | .Case(S: "mips32r3" , Value: true) |
522 | .Case(S: "mips32r5" , Value: true) |
523 | .Case(S: "mips32r6" , Value: true) |
524 | .Case(S: "mips64r2" , Value: true) |
525 | .Case(S: "mips64r3" , Value: true) |
526 | .Case(S: "mips64r5" , Value: true) |
527 | .Case(S: "mips64r6" , Value: true) |
528 | .Case(S: "octeon" , Value: true) |
529 | .Case(S: "p5600" , Value: true) |
530 | .Default(Value: false); |
531 | } |
532 | |