clang 22.0.0git
Mips.cpp
Go to the documentation of this file.
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"
11#include "clang/Driver/Driver.h"
13#include "llvm/ADT/StringSwitch.h"
14#include "llvm/Option/ArgList.h"
15
16using namespace clang::driver;
17using namespace clang::driver::tools;
18using namespace clang;
19using namespace llvm::opt;
20
21// Get CPU and ABI names. They are not independent
22// so we have to calculate them together.
23void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple,
24 StringRef &CPUName, StringRef &ABIName) {
25 const char *DefMips32CPU = "mips32r2";
26 const char *DefMips64CPU = "mips64r2";
27
28 // MIPS32r6 is the default for mips(el)?-img-linux-gnu and MIPS64r6 is the
29 // default for mips64(el)?-img-linux-gnu.
30 if (Triple.getVendor() == llvm::Triple::ImaginationTechnologies &&
31 Triple.isGNUEnvironment()) {
32 DefMips32CPU = "mips32r6";
33 DefMips64CPU = "mips64r6";
34 }
35
36 if (Triple.getSubArch() == llvm::Triple::MipsSubArch_r6) {
37 DefMips32CPU = "mips32r6";
38 DefMips64CPU = "mips64r6";
39 }
40
41 // MIPS3 is the default for mips64*-unknown-openbsd.
42 if (Triple.isOSOpenBSD())
43 DefMips64CPU = "mips3";
44
45 // MIPS2 is the default for mips(el)?-unknown-freebsd.
46 // MIPS3 is the default for mips64(el)?-unknown-freebsd.
47 if (Triple.isOSFreeBSD()) {
48 DefMips32CPU = "mips2";
49 DefMips64CPU = "mips3";
50 }
51
52 if (Arg *A = Args.getLastArg(options::OPT_march_EQ, options::OPT_mcpu_EQ))
53 CPUName = A->getValue();
54
55 if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
56 ABIName = A->getValue();
57 // Convert a GNU style Mips ABI name to the name
58 // accepted by LLVM Mips backend.
59 ABIName = llvm::StringSwitch<llvm::StringRef>(ABIName)
60 .Case("32", "o32")
61 .Case("64", "n64")
62 .Default(ABIName);
63 }
64
65 // Setup default CPU and ABI names.
66 if (CPUName.empty() && ABIName.empty()) {
67 switch (Triple.getArch()) {
68 default:
69 llvm_unreachable("Unexpected triple arch name");
70 case llvm::Triple::mips:
71 case llvm::Triple::mipsel:
72 CPUName = DefMips32CPU;
73 break;
74 case llvm::Triple::mips64:
75 case llvm::Triple::mips64el:
76 CPUName = DefMips64CPU;
77 break;
78 }
79 }
80
81 if (ABIName.empty() && Triple.isABIN32())
82 ABIName = "n32";
83
84 if (ABIName.empty() &&
85 (Triple.getVendor() == llvm::Triple::MipsTechnologies ||
86 Triple.getVendor() == llvm::Triple::ImaginationTechnologies)) {
87 ABIName = llvm::StringSwitch<const char *>(CPUName)
88 .Case("mips1", "o32")
89 .Case("mips2", "o32")
90 .Case("mips3", "n64")
91 .Case("mips4", "n64")
92 .Case("mips5", "n64")
93 .Case("mips32", "o32")
94 .Case("mips32r2", "o32")
95 .Case("mips32r3", "o32")
96 .Case("mips32r5", "o32")
97 .Case("mips32r6", "o32")
98 .Case("mips64", "n64")
99 .Case("mips64r2", "n64")
100 .Case("mips64r3", "n64")
101 .Case("mips64r5", "n64")
102 .Case("mips64r6", "n64")
103 .Case("octeon", "n64")
104 .Case("p5600", "o32")
105 .Case("i6400", "n64")
106 .Case("i6500", "n64")
107 .Default("");
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("o32", DefMips32CPU)
119 .Cases({"n32", "n64"}, DefMips64CPU)
120 .Default("");
121 }
122
123 // FIXME: Warn on inconsistent use of -march and -mabi.
124}
125
126std::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("o32", "")
132 .Case("n32", "32")
133 .Case("n64", "64");
134}
135
136// Convert ABI name to the GNU tools acceptable variant.
137StringRef mips::getGnuCompatibleMipsABIName(StringRef ABI) {
138 return llvm::StringSwitch<llvm::StringRef>(ABI)
139 .Case("o32", "32")
140 .Case("n64", "64")
141 .Default(ABI);
142}
143
144// Select the MIPS float ABI as determined by -msoft-float, -mhard-float,
145// and -mfloat-abi=.
146mips::FloatABI mips::getMipsFloatABI(const Driver &D, const ArgList &Args,
147 const llvm::Triple &Triple) {
149 if (Arg *A =
150 Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
151 options::OPT_mfloat_abi_EQ)) {
152 if (A->getOption().matches(options::OPT_msoft_float))
154 else if (A->getOption().matches(options::OPT_mhard_float))
156 else {
157 ABI = llvm::StringSwitch<mips::FloatABI>(A->getValue())
158 .Case("soft", mips::FloatABI::Soft)
159 .Case("hard", mips::FloatABI::Hard)
160 .Default(mips::FloatABI::Invalid);
161 if (ABI == mips::FloatABI::Invalid && !StringRef(A->getValue()).empty()) {
162 D.Diag(clang::diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
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.
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.
178 }
179 }
180
181 assert(ABI != mips::FloatABI::Invalid && "must select an ABI");
182 return ABI;
183}
184
185void 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(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(options::OPT_fPIC, options::OPT_fno_PIC,
227 options::OPT_fpic, options::OPT_fno_pic,
228 options::OPT_fPIE, options::OPT_fno_PIE,
229 options::OPT_fpie, options::OPT_fno_pie);
230 if (LastPICArg) {
231 Option O = LastPICArg->getOption();
232 NonPIC =
233 (O.matches(options::OPT_fno_PIC) || O.matches(options::OPT_fno_pic) ||
234 O.matches(options::OPT_fno_PIE) || O.matches(options::OPT_fno_pie));
235 IsPIC =
236 (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) ||
237 O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie));
238 }
239
240 bool UseAbiCalls = false;
241
242 Arg *ABICallsArg =
243 Args.getLastArg(options::OPT_mabicalls, options::OPT_mno_abicalls);
244 UseAbiCalls =
245 !ABICallsArg || ABICallsArg->getOption().matches(options::OPT_mabicalls);
246
247 if (IsN64 && NonPIC && (!ABICallsArg || UseAbiCalls)) {
248 D.Diag(diag::warn_drv_unsupported_pic_with_mabicalls)
249 << LastPICArg->getAsString(Args) << (!ABICallsArg ? 0 : 1);
250 }
251
252 if (ABICallsArg && !UseAbiCalls && IsPIC) {
253 D.Diag(diag::err_drv_unsupported_noabicalls_pic);
254 }
255
256 if (CPUName == "i6500" || CPUName == "i6400") {
257 // MIPS cpu i6400 and i6500 support MSA (Mips SIMD Architecture)
258 // by default.
259 Features.push_back("+msa");
260 }
261
262 if (!UseAbiCalls)
263 Features.push_back("+noabicalls");
264 else
265 Features.push_back("-noabicalls");
266
267 if (Arg *A = Args.getLastArg(options::OPT_mlong_calls,
268 options::OPT_mno_long_calls)) {
269 if (A->getOption().matches(options::OPT_mno_long_calls))
270 Features.push_back("-long-calls");
271 else if (!UseAbiCalls)
272 Features.push_back("+long-calls");
273 else
274 D.Diag(diag::warn_drv_unsupported_longcalls) << (ABICallsArg ? 0 : 1);
275 }
276
277 if (Arg *A = Args.getLastArg(options::OPT_mxgot, options::OPT_mno_xgot)) {
278 if (A->getOption().matches(options::OPT_mxgot))
279 Features.push_back("+xgot");
280 else
281 Features.push_back("-xgot");
282 }
283
285 if (FloatABI == mips::FloatABI::Soft) {
286 // FIXME: Note, this is a hack. We need to pass the selected float
287 // mode to the MipsTargetInfoBase to define appropriate macros there.
288 // Now it is the only method.
289 Features.push_back("+soft-float");
290 }
291
292 if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) {
293 StringRef Val = StringRef(A->getValue());
294 if (Val == "2008") {
296 Features.push_back("+nan2008");
297 HasNaN2008Opt = true;
298 } else {
299 Features.push_back("-nan2008");
300 D.Diag(diag::warn_target_unsupported_nan2008) << CPUName;
301 }
302 } else if (Val == "legacy") {
304 Features.push_back("-nan2008");
305 else {
306 Features.push_back("+nan2008");
307 D.Diag(diag::warn_target_unsupported_nanlegacy) << CPUName;
308 }
309 } else
310 D.Diag(diag::err_drv_unsupported_option_argument)
311 << A->getSpelling() << Val;
312 }
313
314 if (Arg *A = Args.getLastArg(options::OPT_mabs_EQ)) {
315 StringRef Val = StringRef(A->getValue());
316 if (Val == "2008") {
318 Features.push_back("+abs2008");
319 } else {
320 Features.push_back("-abs2008");
321 D.Diag(diag::warn_target_unsupported_abs2008) << CPUName;
322 }
323 } else if (Val == "legacy") {
324 if (mips::getIEEE754Standard(CPUName) & mips::Legacy) {
325 Features.push_back("-abs2008");
326 } else {
327 Features.push_back("+abs2008");
328 D.Diag(diag::warn_target_unsupported_abslegacy) << CPUName;
329 }
330 } else {
331 D.Diag(diag::err_drv_unsupported_option_argument)
332 << A->getSpelling() << Val;
333 }
334 } else if (HasNaN2008Opt) {
335 Features.push_back("+abs2008");
336 }
337
338 AddTargetFeature(Args, Features, options::OPT_msingle_float,
339 options::OPT_mdouble_float, "single-float");
340 AddTargetFeature(Args, Features, options::OPT_mips16, options::OPT_mno_mips16,
341 "mips16");
342 AddTargetFeature(Args, Features, options::OPT_mmicromips,
343 options::OPT_mno_micromips, "micromips");
344 AddTargetFeature(Args, Features, options::OPT_mdsp, options::OPT_mno_dsp,
345 "dsp");
346 AddTargetFeature(Args, Features, options::OPT_mdspr2, options::OPT_mno_dspr2,
347 "dspr2");
348 AddTargetFeature(Args, Features, options::OPT_mmsa, options::OPT_mno_msa,
349 "msa");
350 if (Arg *A = Args.getLastArg(
351 options::OPT_mstrict_align, options::OPT_mno_strict_align,
352 options::OPT_mno_unaligned_access, options::OPT_munaligned_access)) {
353 if (A->getOption().matches(options::OPT_mstrict_align) ||
354 A->getOption().matches(options::OPT_mno_unaligned_access))
355 Features.push_back(Args.MakeArgString("+strict-align"));
356 else
357 Features.push_back(Args.MakeArgString("-strict-align"));
358 }
359
360 // Add the last -mfp32/-mfpxx/-mfp64, if none are given and the ABI is O32
361 // pass -mfpxx, or if none are given and fp64a is default, pass fp64 and
362 // nooddspreg.
363 if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx,
364 options::OPT_mfp64)) {
365 if (A->getOption().matches(options::OPT_mfp32))
366 Features.push_back("-fp64");
367 else if (A->getOption().matches(options::OPT_mfpxx)) {
368 Features.push_back("+fpxx");
369 Features.push_back("+nooddspreg");
370 } else
371 Features.push_back("+fp64");
372 } else if (mips::shouldUseFPXX(Args, Triple, CPUName, ABIName, FloatABI)) {
373 Features.push_back("+fpxx");
374 Features.push_back("+nooddspreg");
375 } else if (Arg *A = Args.getLastArg(options::OPT_mmsa)) {
376 if (A->getOption().matches(options::OPT_mmsa))
377 Features.push_back("+fp64");
378 }
379
380 AddTargetFeature(Args, Features, options::OPT_mno_odd_spreg,
381 options::OPT_modd_spreg, "nooddspreg");
382 AddTargetFeature(Args, Features, options::OPT_mno_madd4, options::OPT_mmadd4,
383 "nomadd4");
384 AddTargetFeature(Args, Features, options::OPT_mmt, options::OPT_mno_mt, "mt");
385 AddTargetFeature(Args, Features, options::OPT_mcrc, options::OPT_mno_crc,
386 "crc");
387 AddTargetFeature(Args, Features, options::OPT_mvirt, options::OPT_mno_virt,
388 "virt");
389 AddTargetFeature(Args, Features, options::OPT_mginv, options::OPT_mno_ginv,
390 "ginv");
391
392 if (Arg *A = Args.getLastArg(options::OPT_mindirect_jump_EQ)) {
393 StringRef Val = StringRef(A->getValue());
394 if (Val == "hazard") {
395 Arg *B =
396 Args.getLastArg(options::OPT_mmicromips, options::OPT_mno_micromips);
397 Arg *C = Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16);
398
399 if (B && B->getOption().matches(options::OPT_mmicromips))
400 D.Diag(diag::err_drv_unsupported_indirect_jump_opt)
401 << "hazard" << "micromips";
402 else if (C && C->getOption().matches(options::OPT_mips16))
403 D.Diag(diag::err_drv_unsupported_indirect_jump_opt)
404 << "hazard" << "mips16";
406 Features.push_back("+use-indirect-jump-hazard");
407 else
408 D.Diag(diag::err_drv_unsupported_indirect_jump_opt)
409 << "hazard" << CPUName;
410 } else
411 D.Diag(diag::err_drv_unknown_indirect_jump_opt) << Val;
412 }
413}
414
416 // Strictly speaking, mips32r2 and mips64r2 do not conform to the
417 // IEEE754-2008 standard. Support for this standard was first introduced
418 // in Release 3. However, other compilers have traditionally allowed it
419 // for Release 2 so we should do the same.
420 return (IEEE754Standard)llvm::StringSwitch<int>(CPU)
421 .Case("mips1", Legacy)
422 .Case("mips2", Legacy)
423 .Case("mips3", Legacy)
424 .Case("mips4", Legacy)
425 .Case("mips5", Legacy)
426 .Case("mips32", Legacy)
427 .Case("mips32r2", Legacy | Std2008)
428 .Case("mips32r3", Legacy | Std2008)
429 .Case("mips32r5", Legacy | Std2008)
430 .Case("mips32r6", Std2008)
431 .Case("mips64", Legacy)
432 .Case("mips64r2", Legacy | Std2008)
433 .Case("mips64r3", Legacy | Std2008)
434 .Case("mips64r5", Legacy | Std2008)
435 .Case("mips64r6", Std2008)
436 .Default(Std2008);
437}
438
439bool mips::hasCompactBranches(StringRef &CPU) {
440 // mips32r6 and mips64r6 have compact branches.
441 return llvm::StringSwitch<bool>(CPU)
442 .Case("mips32r6", true)
443 .Case("mips64r6", true)
444 .Case("i6400", true)
445 .Case("i6500", true)
446 .Default(false);
447}
448
449bool mips::hasMipsAbiArg(const ArgList &Args, const char *Value) {
450 Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
451 return A && (A->getValue() == StringRef(Value));
452}
453
454bool mips::isUCLibc(const ArgList &Args) {
455 Arg *A = Args.getLastArg(options::OPT_m_libc_Group);
456 return A && A->getOption().matches(options::OPT_muclibc);
457}
458
459bool mips::isNaN2008(const Driver &D, const ArgList &Args,
460 const llvm::Triple &Triple) {
461 if (Arg *NaNArg = Args.getLastArg(options::OPT_mnan_EQ))
462 return llvm::StringSwitch<bool>(NaNArg->getValue())
463 .Case("2008", true)
464 .Case("legacy", false)
465 .Default(false);
466
467 // NaN2008 is the default for MIPS32r6/MIPS64r6.
468 return llvm::StringSwitch<bool>(getCPUName(D, Args, Triple))
469 .Cases({"mips32r6", "mips64r6"}, true)
470 .Default(false);
471}
472
473bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName,
474 StringRef ABIName, mips::FloatABI FloatABI) {
475 if (ABIName != "32")
476 return false;
477
478 // FPXX shouldn't be used if either -msoft-float or -mfloat-abi=soft is
479 // present.
481 return false;
482
483 return llvm::StringSwitch<bool>(CPUName)
484 .Cases({"mips2", "mips3", "mips4", "mips5"}, true)
485 .Cases({"mips32", "mips32r2", "mips32r3", "mips32r5"}, true)
486 .Cases({"mips64", "mips64r2", "mips64r3", "mips64r5"}, true)
487 .Default(false);
488}
489
490bool mips::shouldUseFPXX(const ArgList &Args, const llvm::Triple &Triple,
491 StringRef CPUName, StringRef ABIName,
492 mips::FloatABI FloatABI) {
493 bool UseFPXX = isFPXXDefault(Triple, CPUName, ABIName, FloatABI);
494
495 // FPXX shouldn't be used if -msingle-float is present.
496 if (Arg *A = Args.getLastArg(options::OPT_msingle_float,
497 options::OPT_mdouble_float))
498 if (A->getOption().matches(options::OPT_msingle_float))
499 UseFPXX = false;
500 // FP64 should be used for MSA.
501 if (Arg *A = Args.getLastArg(options::OPT_mmsa))
502 if (A->getOption().matches(options::OPT_mmsa))
503 UseFPXX = llvm::StringSwitch<bool>(CPUName)
504 .Cases({"mips32r2", "mips32r3", "mips32r5"}, false)
505 .Cases({"mips64r2", "mips64r3", "mips64r5"}, false)
506 .Default(UseFPXX);
507
508 return UseFPXX;
509}
510
512 // Supporting the hazard barrier method of dealing with indirect
513 // jumps requires MIPSR2 support.
514 return llvm::StringSwitch<bool>(CPU)
515 .Case("mips32r2", true)
516 .Case("mips32r3", true)
517 .Case("mips32r5", true)
518 .Case("mips32r6", true)
519 .Case("mips64r2", true)
520 .Case("mips64r3", true)
521 .Case("mips64r5", true)
522 .Case("mips64r6", true)
523 .Case("octeon", true)
524 .Case("p5600", true)
525 .Case("i6400", true)
526 .Case("i6500", true)
527 .Default(false);
528}
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition Driver.h:99
DiagnosticBuilder Diag(unsigned DiagID) const
Definition Driver.h:169
void getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args, std::vector< StringRef > &Features)
StringRef getGnuCompatibleMipsABIName(StringRef ABI)
Definition Mips.cpp:137
bool isNaN2008(const Driver &D, const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
bool hasMipsAbiArg(const llvm::opt::ArgList &Args, const char *Value)
mips::FloatABI getMipsFloatABI(const Driver &D, const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
std::string getMipsABILibSuffix(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
bool shouldUseFPXX(const llvm::opt::ArgList &Args, const llvm::Triple &Triple, StringRef CPUName, StringRef ABIName, mips::FloatABI FloatABI)
bool hasCompactBranches(StringRef &CPU)
Definition Mips.cpp:439
bool isUCLibc(const llvm::opt::ArgList &Args)
void getMipsCPUAndABI(const llvm::opt::ArgList &Args, const llvm::Triple &Triple, StringRef &CPUName, StringRef &ABIName)
bool isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, StringRef ABIName, mips::FloatABI FloatABI)
Definition Mips.cpp:473
IEEE754Standard getIEEE754Standard(StringRef &CPU)
Definition Mips.cpp:415
bool supportsIndirectJumpHazardBarrier(StringRef &CPU)
Definition Mips.cpp:511
std::string getCPUName(const Driver &D, const llvm::opt::ArgList &Args, const llvm::Triple &T, bool FromAs=false)
void AddTargetFeature(const llvm::opt::ArgList &Args, std::vector< StringRef > &Features, llvm::opt::OptSpecifier OnOpt, llvm::opt::OptSpecifier OffOpt, StringRef FeatureName)
The JSON file list parser is used to communicate input to InstallAPI.