xref: /llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp (revision 3a9380f21d05eb8ced03349c8c503dc911f22621)
1 //===-- BareMetal.cpp - Bare Metal ToolChain --------------------*- 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 "BareMetal.h"
10 
11 #include "CommonArgs.h"
12 #include "Gnu.h"
13 #include "clang/Driver/InputInfo.h"
14 
15 #include "Arch/ARM.h"
16 #include "Arch/RISCV.h"
17 #include "clang/Driver/Compilation.h"
18 #include "clang/Driver/Driver.h"
19 #include "clang/Driver/DriverDiagnostic.h"
20 #include "clang/Driver/MultilibBuilder.h"
21 #include "clang/Driver/Options.h"
22 #include "llvm/ADT/StringExtras.h"
23 #include "llvm/Option/ArgList.h"
24 #include "llvm/Support/Path.h"
25 #include "llvm/Support/VirtualFileSystem.h"
26 #include "llvm/Support/raw_ostream.h"
27 
28 #include <sstream>
29 
30 using namespace llvm::opt;
31 using namespace clang;
32 using namespace clang::driver;
33 using namespace clang::driver::tools;
34 using namespace clang::driver::toolchains;
35 
36 static bool findRISCVMultilibs(const Driver &D,
37                                const llvm::Triple &TargetTriple,
38                                const ArgList &Args, DetectedMultilibs &Result) {
39   Multilib::flags_list Flags;
40   std::string Arch = riscv::getRISCVArch(Args, TargetTriple);
41   StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple);
42 
43   if (TargetTriple.isRISCV64()) {
44     MultilibBuilder Imac =
45         MultilibBuilder().flag("-march=rv64imac").flag("-mabi=lp64");
46     MultilibBuilder Imafdc = MultilibBuilder("/rv64imafdc/lp64d")
47                                  .flag("-march=rv64imafdc")
48                                  .flag("-mabi=lp64d");
49 
50     // Multilib reuse
51     bool UseImafdc =
52         (Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc
53 
54     addMultilibFlag((Arch == "rv64imac"), "-march=rv64imac", Flags);
55     addMultilibFlag(UseImafdc, "-march=rv64imafdc", Flags);
56     addMultilibFlag(Abi == "lp64", "-mabi=lp64", Flags);
57     addMultilibFlag(Abi == "lp64d", "-mabi=lp64d", Flags);
58 
59     Result.Multilibs =
60         MultilibSetBuilder().Either(Imac, Imafdc).makeMultilibSet();
61     return Result.Multilibs.select(D, Flags, Result.SelectedMultilibs);
62   }
63   if (TargetTriple.isRISCV32()) {
64     MultilibBuilder Imac =
65         MultilibBuilder().flag("-march=rv32imac").flag("-mabi=ilp32");
66     MultilibBuilder I = MultilibBuilder("/rv32i/ilp32")
67                             .flag("-march=rv32i")
68                             .flag("-mabi=ilp32");
69     MultilibBuilder Im = MultilibBuilder("/rv32im/ilp32")
70                              .flag("-march=rv32im")
71                              .flag("-mabi=ilp32");
72     MultilibBuilder Iac = MultilibBuilder("/rv32iac/ilp32")
73                               .flag("-march=rv32iac")
74                               .flag("-mabi=ilp32");
75     MultilibBuilder Imafc = MultilibBuilder("/rv32imafc/ilp32f")
76                                 .flag("-march=rv32imafc")
77                                 .flag("-mabi=ilp32f");
78 
79     // Multilib reuse
80     bool UseI = (Arch == "rv32i") || (Arch == "rv32ic");    // ic => i
81     bool UseIm = (Arch == "rv32im") || (Arch == "rv32imc"); // imc => im
82     bool UseImafc = (Arch == "rv32imafc") || (Arch == "rv32imafdc") ||
83                     (Arch == "rv32gc"); // imafdc,gc => imafc
84 
85     addMultilibFlag(UseI, "-march=rv32i", Flags);
86     addMultilibFlag(UseIm, "-march=rv32im", Flags);
87     addMultilibFlag((Arch == "rv32iac"), "-march=rv32iac", Flags);
88     addMultilibFlag((Arch == "rv32imac"), "-march=rv32imac", Flags);
89     addMultilibFlag(UseImafc, "-march=rv32imafc", Flags);
90     addMultilibFlag(Abi == "ilp32", "-mabi=ilp32", Flags);
91     addMultilibFlag(Abi == "ilp32f", "-mabi=ilp32f", Flags);
92 
93     Result.Multilibs =
94         MultilibSetBuilder().Either(I, Im, Iac, Imac, Imafc).makeMultilibSet();
95     return Result.Multilibs.select(D, Flags, Result.SelectedMultilibs);
96   }
97   return false;
98 }
99 
100 static std::string computeBaseSysRoot(const Driver &D, bool IncludeTriple) {
101   if (!D.SysRoot.empty())
102     return D.SysRoot;
103 
104   SmallString<128> SysRootDir(D.Dir);
105   llvm::sys::path::append(SysRootDir, "..", "lib", "clang-runtimes");
106 
107   if (IncludeTriple)
108     llvm::sys::path::append(SysRootDir, D.getTargetTriple());
109 
110   return std::string(SysRootDir);
111 }
112 
113 BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
114                      const ArgList &Args)
115     : ToolChain(D, Triple, Args),
116       SysRoot(computeBaseSysRoot(D, /*IncludeTriple=*/true)) {
117   getProgramPaths().push_back(getDriver().Dir);
118 
119   findMultilibs(D, Triple, Args);
120   SmallString<128> SysRoot(computeSysRoot());
121   if (!SysRoot.empty()) {
122     for (const Multilib &M : getOrderedMultilibs()) {
123       SmallString<128> Dir(SysRoot);
124       llvm::sys::path::append(Dir, M.osSuffix(), "lib");
125       getFilePaths().push_back(std::string(Dir));
126       getLibraryPaths().push_back(std::string(Dir));
127     }
128   }
129 }
130 
131 /// Is the triple {aarch64.aarch64_be}-none-elf?
132 static bool isAArch64BareMetal(const llvm::Triple &Triple) {
133   if (Triple.getArch() != llvm::Triple::aarch64 &&
134       Triple.getArch() != llvm::Triple::aarch64_be)
135     return false;
136 
137   if (Triple.getVendor() != llvm::Triple::UnknownVendor)
138     return false;
139 
140   if (Triple.getOS() != llvm::Triple::UnknownOS)
141     return false;
142 
143   return Triple.getEnvironmentName() == "elf";
144 }
145 
146 static bool isRISCVBareMetal(const llvm::Triple &Triple) {
147   if (!Triple.isRISCV())
148     return false;
149 
150   if (Triple.getVendor() != llvm::Triple::UnknownVendor)
151     return false;
152 
153   if (Triple.getOS() != llvm::Triple::UnknownOS)
154     return false;
155 
156   return Triple.getEnvironmentName() == "elf";
157 }
158 
159 /// Is the triple powerpc[64][le]-*-none-eabi?
160 static bool isPPCBareMetal(const llvm::Triple &Triple) {
161   return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS &&
162          Triple.getEnvironment() == llvm::Triple::EABI;
163 }
164 
165 static void
166 findMultilibsFromYAML(const ToolChain &TC, const Driver &D,
167                       StringRef MultilibPath, const ArgList &Args,
168                       DetectedMultilibs &Result,
169                       SmallVector<StringRef> &CustomFlagsMacroDefines) {
170   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB =
171       D.getVFS().getBufferForFile(MultilibPath);
172   if (!MB)
173     return;
174   Multilib::flags_list Flags = TC.getMultilibFlags(Args);
175   llvm::ErrorOr<MultilibSet> ErrorOrMultilibSet =
176       MultilibSet::parseYaml(*MB.get());
177   if (ErrorOrMultilibSet.getError())
178     return;
179   Result.Multilibs = ErrorOrMultilibSet.get();
180   if (Result.Multilibs.select(D, Flags, Result.SelectedMultilibs,
181                               &CustomFlagsMacroDefines))
182     return;
183   D.Diag(clang::diag::warn_drv_missing_multilib) << llvm::join(Flags, " ");
184   std::stringstream ss;
185 
186   // If multilib selection didn't complete successfully, report a list
187   // of all the configurations the user could have provided.
188   for (const Multilib &Multilib : Result.Multilibs)
189     if (!Multilib.isError())
190       ss << "\n" << llvm::join(Multilib.flags(), " ");
191   D.Diag(clang::diag::note_drv_available_multilibs) << ss.str();
192 
193   // Now report any custom error messages requested by the YAML. We do
194   // this after displaying the list of available multilibs, because
195   // that list is probably large, and (in interactive use) risks
196   // scrolling the useful error message off the top of the user's
197   // terminal.
198   for (const Multilib &Multilib : Result.SelectedMultilibs)
199     if (Multilib.isError())
200       D.Diag(clang::diag::err_drv_multilib_custom_error)
201           << Multilib.getErrorMessage();
202 
203   // If there was an error, clear the SelectedMultilibs vector, in
204   // case it contains partial data.
205   Result.SelectedMultilibs.clear();
206 }
207 
208 static constexpr llvm::StringLiteral MultilibFilename = "multilib.yaml";
209 
210 static std::optional<llvm::SmallString<128>>
211 getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple,
212                       const ArgList &Args) {
213   llvm::SmallString<128> MultilibPath;
214   if (Arg *ConfigFileArg = Args.getLastArg(options::OPT_multi_lib_config)) {
215     MultilibPath = ConfigFileArg->getValue();
216     if (!D.getVFS().exists(MultilibPath)) {
217       D.Diag(clang::diag::err_drv_no_such_file) << MultilibPath.str();
218       return {};
219     }
220   } else {
221     MultilibPath = computeBaseSysRoot(D, /*IncludeTriple=*/false);
222     llvm::sys::path::append(MultilibPath, MultilibFilename);
223   }
224   return MultilibPath;
225 }
226 
227 void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
228                               const ArgList &Args) {
229   DetectedMultilibs Result;
230   // Look for a multilib.yaml before trying target-specific hardwired logic.
231   // If it exists, always do what it specifies.
232   std::optional<llvm::SmallString<128>> MultilibPath =
233       getMultilibConfigPath(D, Triple, Args);
234   if (!MultilibPath)
235     return;
236   if (D.getVFS().exists(*MultilibPath)) {
237     // If multilib.yaml is found, update sysroot so it doesn't use a target
238     // specific suffix
239     SysRoot = computeBaseSysRoot(D, /*IncludeTriple=*/false);
240     SmallVector<StringRef> CustomFlagMacroDefines;
241     findMultilibsFromYAML(*this, D, *MultilibPath, Args, Result,
242                           CustomFlagMacroDefines);
243     SelectedMultilibs = Result.SelectedMultilibs;
244     Multilibs = Result.Multilibs;
245     MultilibMacroDefines.append(CustomFlagMacroDefines.begin(),
246                                 CustomFlagMacroDefines.end());
247   } else if (isRISCVBareMetal(Triple)) {
248     if (findRISCVMultilibs(D, Triple, Args, Result)) {
249       SelectedMultilibs = Result.SelectedMultilibs;
250       Multilibs = Result.Multilibs;
251     }
252   }
253 }
254 
255 bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
256   return arm::isARMEABIBareMetal(Triple) || isAArch64BareMetal(Triple) ||
257          isRISCVBareMetal(Triple) || isPPCBareMetal(Triple);
258 }
259 
260 Tool *BareMetal::buildLinker() const {
261   return new tools::baremetal::Linker(*this);
262 }
263 
264 Tool *BareMetal::buildStaticLibTool() const {
265   return new tools::baremetal::StaticLibTool(*this);
266 }
267 
268 std::string BareMetal::computeSysRoot() const { return SysRoot; }
269 
270 BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const {
271   // Get multilibs in reverse order because they're ordered most-specific last.
272   if (!SelectedMultilibs.empty())
273     return llvm::reverse(SelectedMultilibs);
274 
275   // No multilibs selected so return a single default multilib.
276   static const llvm::SmallVector<Multilib> Default = {Multilib()};
277   return llvm::reverse(Default);
278 }
279 
280 void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
281                                           ArgStringList &CC1Args) const {
282   if (DriverArgs.hasArg(options::OPT_nostdinc))
283     return;
284 
285   if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
286     SmallString<128> Dir(getDriver().ResourceDir);
287     llvm::sys::path::append(Dir, "include");
288     addSystemInclude(DriverArgs, CC1Args, Dir.str());
289   }
290 
291   if (DriverArgs.hasArg(options::OPT_nostdlibinc))
292     return;
293 
294   if (std::optional<std::string> Path = getStdlibIncludePath())
295     addSystemInclude(DriverArgs, CC1Args, *Path);
296 
297   const SmallString<128> SysRoot(computeSysRoot());
298   if (!SysRoot.empty()) {
299     for (const Multilib &M : getOrderedMultilibs()) {
300       SmallString<128> Dir(SysRoot);
301       llvm::sys::path::append(Dir, M.includeSuffix());
302       llvm::sys::path::append(Dir, "include");
303       addSystemInclude(DriverArgs, CC1Args, Dir.str());
304     }
305   }
306 }
307 
308 void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
309                                       ArgStringList &CC1Args,
310                                       Action::OffloadKind) const {
311   CC1Args.push_back("-nostdsysteminc");
312 }
313 
314 void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
315                                              ArgStringList &CC1Args) const {
316   if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
317                         options::OPT_nostdincxx))
318     return;
319 
320   const Driver &D = getDriver();
321   std::string Target = getTripleString();
322 
323   auto AddCXXIncludePath = [&](StringRef Path) {
324     std::string Version = detectLibcxxVersion(Path);
325     if (Version.empty())
326       return;
327 
328     {
329       // First the per-target include dir: include/<target>/c++/v1.
330       SmallString<128> TargetDir(Path);
331       llvm::sys::path::append(TargetDir, Target, "c++", Version);
332       addSystemInclude(DriverArgs, CC1Args, TargetDir);
333     }
334 
335     {
336       // Then the generic dir: include/c++/v1.
337       SmallString<128> Dir(Path);
338       llvm::sys::path::append(Dir, "c++", Version);
339       addSystemInclude(DriverArgs, CC1Args, Dir);
340     }
341   };
342 
343   switch (GetCXXStdlibType(DriverArgs)) {
344     case ToolChain::CST_Libcxx: {
345       SmallString<128> P(D.Dir);
346       llvm::sys::path::append(P, "..", "include");
347       AddCXXIncludePath(P);
348       break;
349     }
350     case ToolChain::CST_Libstdcxx:
351       // We only support libc++ toolchain installation.
352       break;
353   }
354 
355   std::string SysRoot(computeSysRoot());
356   if (SysRoot.empty())
357     return;
358 
359   for (const Multilib &M : getOrderedMultilibs()) {
360     SmallString<128> Dir(SysRoot);
361     llvm::sys::path::append(Dir, M.gccSuffix());
362     switch (GetCXXStdlibType(DriverArgs)) {
363     case ToolChain::CST_Libcxx: {
364       // First check sysroot/usr/include/c++/v1 if it exists.
365       SmallString<128> TargetDir(Dir);
366       llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1");
367       if (D.getVFS().exists(TargetDir)) {
368         addSystemInclude(DriverArgs, CC1Args, TargetDir.str());
369         break;
370       }
371       // Add generic path if nothing else succeeded so far.
372       llvm::sys::path::append(Dir, "include", "c++", "v1");
373       addSystemInclude(DriverArgs, CC1Args, Dir.str());
374       break;
375     }
376     case ToolChain::CST_Libstdcxx: {
377       llvm::sys::path::append(Dir, "include", "c++");
378       std::error_code EC;
379       Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
380       // Walk the subdirs, and find the one with the newest gcc version:
381       for (llvm::vfs::directory_iterator
382                LI = D.getVFS().dir_begin(Dir.str(), EC),
383                LE;
384            !EC && LI != LE; LI = LI.increment(EC)) {
385         StringRef VersionText = llvm::sys::path::filename(LI->path());
386         auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
387         if (CandidateVersion.Major == -1)
388           continue;
389         if (CandidateVersion <= Version)
390           continue;
391         Version = CandidateVersion;
392       }
393       if (Version.Major != -1) {
394         llvm::sys::path::append(Dir, Version.Text);
395         addSystemInclude(DriverArgs, CC1Args, Dir.str());
396       }
397       break;
398     }
399     }
400   }
401 }
402 
403 void baremetal::StaticLibTool::ConstructJob(Compilation &C, const JobAction &JA,
404                                             const InputInfo &Output,
405                                             const InputInfoList &Inputs,
406                                             const ArgList &Args,
407                                             const char *LinkingOutput) const {
408   const Driver &D = getToolChain().getDriver();
409 
410   // Silence warning for "clang -g foo.o -o foo"
411   Args.ClaimAllArgs(options::OPT_g_Group);
412   // and "clang -emit-llvm foo.o -o foo"
413   Args.ClaimAllArgs(options::OPT_emit_llvm);
414   // and for "clang -w foo.o -o foo". Other warning options are already
415   // handled somewhere else.
416   Args.ClaimAllArgs(options::OPT_w);
417   // Silence warnings when linking C code with a C++ '-stdlib' argument.
418   Args.ClaimAllArgs(options::OPT_stdlib_EQ);
419 
420   // ar tool command "llvm-ar <options> <output_file> <input_files>".
421   ArgStringList CmdArgs;
422   // Create and insert file members with a deterministic index.
423   CmdArgs.push_back("rcsD");
424   CmdArgs.push_back(Output.getFilename());
425 
426   for (const auto &II : Inputs) {
427     if (II.isFilename()) {
428       CmdArgs.push_back(II.getFilename());
429     }
430   }
431 
432   // Delete old output archive file if it already exists before generating a new
433   // archive file.
434   const char *OutputFileName = Output.getFilename();
435   if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) {
436     if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) {
437       D.Diag(diag::err_drv_unable_to_remove_file) << EC.message();
438       return;
439     }
440   }
441 
442   const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath());
443   C.addCommand(std::make_unique<Command>(JA, *this,
444                                          ResponseFileSupport::AtFileCurCP(),
445                                          Exec, CmdArgs, Inputs, Output));
446 }
447 
448 void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
449                                      const InputInfo &Output,
450                                      const InputInfoList &Inputs,
451                                      const ArgList &Args,
452                                      const char *LinkingOutput) const {
453   ArgStringList CmdArgs;
454 
455   auto &TC = static_cast<const toolchains::BareMetal &>(getToolChain());
456   const Driver &D = getToolChain().getDriver();
457   const llvm::Triple::ArchType Arch = TC.getArch();
458   const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
459 
460   AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
461 
462   CmdArgs.push_back("-Bstatic");
463 
464   if (TC.getTriple().isRISCV() && Args.hasArg(options::OPT_mno_relax))
465     CmdArgs.push_back("--no-relax");
466 
467   if (Triple.isARM() || Triple.isThumb()) {
468     bool IsBigEndian = arm::isARMBigEndian(Triple, Args);
469     if (IsBigEndian)
470       arm::appendBE8LinkFlag(Args, CmdArgs, Triple);
471     CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL");
472   } else if (Triple.isAArch64()) {
473     CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL");
474   }
475 
476   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
477                    options::OPT_r)) {
478     CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt0.o")));
479   }
480 
481   Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
482                             options::OPT_s, options::OPT_t, options::OPT_r});
483 
484   TC.AddFilePathLibArgs(Args, CmdArgs);
485 
486   for (const auto &LibPath : TC.getLibraryPaths())
487     CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-L", LibPath)));
488 
489   if (TC.ShouldLinkCXXStdlib(Args)) {
490     bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
491                                !Args.hasArg(options::OPT_static);
492     if (OnlyLibstdcxxStatic)
493       CmdArgs.push_back("-Bstatic");
494     TC.AddCXXStdlibLibArgs(Args, CmdArgs);
495     if (OnlyLibstdcxxStatic)
496       CmdArgs.push_back("-Bdynamic");
497     CmdArgs.push_back("-lm");
498   }
499 
500   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
501     AddRunTimeLibs(TC, D, CmdArgs, Args);
502 
503     CmdArgs.push_back("-lc");
504   }
505 
506   if (D.isUsingLTO()) {
507     assert(!Inputs.empty() && "Must have at least one input.");
508     // Find the first filename InputInfo object.
509     auto Input = llvm::find_if(
510         Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); });
511     if (Input == Inputs.end())
512       // For a very rare case, all of the inputs to the linker are
513       // InputArg. If that happens, just use the first InputInfo.
514       Input = Inputs.begin();
515 
516     addLTOOptions(TC, Args, CmdArgs, Output, *Input,
517                   D.getLTOMode() == LTOK_Thin);
518   }
519   if (TC.getTriple().isRISCV())
520     CmdArgs.push_back("-X");
521 
522   // The R_ARM_TARGET2 relocation must be treated as R_ARM_REL32 on arm*-*-elf
523   // and arm*-*-eabi (the default is R_ARM_GOT_PREL, used on arm*-*-linux and
524   // arm*-*-*bsd).
525   if (arm::isARMEABIBareMetal(TC.getTriple()))
526     CmdArgs.push_back("--target2=rel");
527 
528   CmdArgs.push_back("-o");
529   CmdArgs.push_back(Output.getFilename());
530 
531   C.addCommand(std::make_unique<Command>(
532       JA, *this, ResponseFileSupport::AtFileCurCP(),
533       Args.MakeArgString(TC.GetLinkerPath()), CmdArgs, Inputs, Output));
534 }
535 
536 // BareMetal toolchain allows all sanitizers where the compiler generates valid
537 // code, ignoring all runtime library support issues on the assumption that
538 // baremetal targets typically implement their own runtime support.
539 SanitizerMask BareMetal::getSupportedSanitizers() const {
540   const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
541   const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 ||
542                          getTriple().getArch() == llvm::Triple::aarch64_be;
543   const bool IsRISCV64 = getTriple().getArch() == llvm::Triple::riscv64;
544   SanitizerMask Res = ToolChain::getSupportedSanitizers();
545   Res |= SanitizerKind::Address;
546   Res |= SanitizerKind::KernelAddress;
547   Res |= SanitizerKind::PointerCompare;
548   Res |= SanitizerKind::PointerSubtract;
549   Res |= SanitizerKind::Fuzzer;
550   Res |= SanitizerKind::FuzzerNoLink;
551   Res |= SanitizerKind::Vptr;
552   Res |= SanitizerKind::SafeStack;
553   Res |= SanitizerKind::Thread;
554   Res |= SanitizerKind::Scudo;
555   if (IsX86_64 || IsAArch64 || IsRISCV64) {
556     Res |= SanitizerKind::HWAddress;
557     Res |= SanitizerKind::KernelHWAddress;
558   }
559   return Res;
560 }
561 
562 SmallVector<std::string>
563 BareMetal::getMultilibMacroDefinesStr(llvm::opt::ArgList &Args) const {
564   return MultilibMacroDefines;
565 }
566