xref: /freebsd/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp (revision 56b17de1e8360fe131d425de20b5e75ff3ea897c)
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(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(Flags, Result.SelectedMultilibs);
96   }
97   return false;
98 }
99 
100 BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
101                      const ArgList &Args)
102     : ToolChain(D, Triple, Args) {
103   getProgramPaths().push_back(getDriver().Dir);
104 
105   findMultilibs(D, Triple, Args);
106   SmallString<128> SysRoot(computeSysRoot());
107   if (!SysRoot.empty()) {
108     for (const Multilib &M : getOrderedMultilibs()) {
109       SmallString<128> Dir(SysRoot);
110       llvm::sys::path::append(Dir, M.osSuffix(), "lib");
111       getFilePaths().push_back(std::string(Dir));
112       getLibraryPaths().push_back(std::string(Dir));
113     }
114   }
115 }
116 
117 /// Is the triple {arm,armeb,thumb,thumbeb}-none-none-{eabi,eabihf} ?
118 static bool isARMBareMetal(const llvm::Triple &Triple) {
119   if (Triple.getArch() != llvm::Triple::arm &&
120       Triple.getArch() != llvm::Triple::thumb &&
121       Triple.getArch() != llvm::Triple::armeb &&
122       Triple.getArch() != llvm::Triple::thumbeb)
123     return false;
124 
125   if (Triple.getVendor() != llvm::Triple::UnknownVendor)
126     return false;
127 
128   if (Triple.getOS() != llvm::Triple::UnknownOS)
129     return false;
130 
131   if (Triple.getEnvironment() != llvm::Triple::EABI &&
132       Triple.getEnvironment() != llvm::Triple::EABIHF)
133     return false;
134 
135   return true;
136 }
137 
138 /// Is the triple {aarch64.aarch64_be}-none-elf?
139 static bool isAArch64BareMetal(const llvm::Triple &Triple) {
140   if (Triple.getArch() != llvm::Triple::aarch64 &&
141       Triple.getArch() != llvm::Triple::aarch64_be)
142     return false;
143 
144   if (Triple.getVendor() != llvm::Triple::UnknownVendor)
145     return false;
146 
147   if (Triple.getOS() != llvm::Triple::UnknownOS)
148     return false;
149 
150   return Triple.getEnvironmentName() == "elf";
151 }
152 
153 static bool isRISCVBareMetal(const llvm::Triple &Triple) {
154   if (!Triple.isRISCV())
155     return false;
156 
157   if (Triple.getVendor() != llvm::Triple::UnknownVendor)
158     return false;
159 
160   if (Triple.getOS() != llvm::Triple::UnknownOS)
161     return false;
162 
163   return Triple.getEnvironmentName() == "elf";
164 }
165 
166 /// Is the triple powerpc[64][le]-*-none-eabi?
167 static bool isPPCBareMetal(const llvm::Triple &Triple) {
168   return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS &&
169          Triple.getEnvironment() == llvm::Triple::EABI;
170 }
171 
172 static void findMultilibsFromYAML(const ToolChain &TC, const Driver &D,
173                                   StringRef MultilibPath, const ArgList &Args,
174                                   DetectedMultilibs &Result) {
175   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB =
176       D.getVFS().getBufferForFile(MultilibPath);
177   if (!MB)
178     return;
179   Multilib::flags_list Flags = TC.getMultilibFlags(Args);
180   llvm::ErrorOr<MultilibSet> ErrorOrMultilibSet =
181       MultilibSet::parseYaml(*MB.get());
182   if (ErrorOrMultilibSet.getError())
183     return;
184   Result.Multilibs = ErrorOrMultilibSet.get();
185   if (Result.Multilibs.select(Flags, Result.SelectedMultilibs))
186     return;
187   D.Diag(clang::diag::warn_drv_missing_multilib) << llvm::join(Flags, " ");
188   std::stringstream ss;
189   for (const Multilib &Multilib : Result.Multilibs)
190     ss << "\n" << llvm::join(Multilib.flags(), " ");
191   D.Diag(clang::diag::note_drv_available_multilibs) << ss.str();
192 }
193 
194 static constexpr llvm::StringLiteral MultilibFilename = "multilib.yaml";
195 
196 // Get the sysroot, before multilib takes effect.
197 static std::string computeBaseSysRoot(const Driver &D,
198                                       const llvm::Triple &Triple) {
199   if (!D.SysRoot.empty())
200     return D.SysRoot;
201 
202   SmallString<128> SysRootDir(D.Dir);
203   llvm::sys::path::append(SysRootDir, "..", "lib", "clang-runtimes");
204 
205   SmallString<128> MultilibPath(SysRootDir);
206   llvm::sys::path::append(MultilibPath, MultilibFilename);
207 
208   // New behaviour: if multilib.yaml is found then use clang-runtimes as the
209   // sysroot.
210   if (D.getVFS().exists(MultilibPath))
211     return std::string(SysRootDir);
212 
213   // Otherwise fall back to the old behaviour of appending the target triple.
214   llvm::sys::path::append(SysRootDir, D.getTargetTriple());
215   return std::string(SysRootDir);
216 }
217 
218 void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
219                               const ArgList &Args) {
220   DetectedMultilibs Result;
221   if (isRISCVBareMetal(Triple)) {
222     if (findRISCVMultilibs(D, Triple, Args, Result)) {
223       SelectedMultilibs = Result.SelectedMultilibs;
224       Multilibs = Result.Multilibs;
225     }
226   } else {
227     llvm::SmallString<128> MultilibPath(computeBaseSysRoot(D, Triple));
228     llvm::sys::path::append(MultilibPath, MultilibFilename);
229     findMultilibsFromYAML(*this, D, MultilibPath, Args, Result);
230     SelectedMultilibs = Result.SelectedMultilibs;
231     Multilibs = Result.Multilibs;
232   }
233 }
234 
235 bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
236   return isARMBareMetal(Triple) || isAArch64BareMetal(Triple) ||
237          isRISCVBareMetal(Triple) || isPPCBareMetal(Triple);
238 }
239 
240 Tool *BareMetal::buildLinker() const {
241   return new tools::baremetal::Linker(*this);
242 }
243 
244 Tool *BareMetal::buildStaticLibTool() const {
245   return new tools::baremetal::StaticLibTool(*this);
246 }
247 
248 std::string BareMetal::computeSysRoot() const {
249   return computeBaseSysRoot(getDriver(), getTriple());
250 }
251 
252 BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const {
253   // Get multilibs in reverse order because they're ordered most-specific last.
254   if (!SelectedMultilibs.empty())
255     return llvm::reverse(SelectedMultilibs);
256 
257   // No multilibs selected so return a single default multilib.
258   static const llvm::SmallVector<Multilib> Default = {Multilib()};
259   return llvm::reverse(Default);
260 }
261 
262 void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
263                                           ArgStringList &CC1Args) const {
264   if (DriverArgs.hasArg(options::OPT_nostdinc))
265     return;
266 
267   if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
268     SmallString<128> Dir(getDriver().ResourceDir);
269     llvm::sys::path::append(Dir, "include");
270     addSystemInclude(DriverArgs, CC1Args, Dir.str());
271   }
272 
273   if (DriverArgs.hasArg(options::OPT_nostdlibinc))
274     return;
275 
276   if (std::optional<std::string> Path = getStdlibIncludePath())
277     addSystemInclude(DriverArgs, CC1Args, *Path);
278 
279   const SmallString<128> SysRoot(computeSysRoot());
280   if (!SysRoot.empty()) {
281     for (const Multilib &M : getOrderedMultilibs()) {
282       SmallString<128> Dir(SysRoot);
283       llvm::sys::path::append(Dir, M.includeSuffix());
284       llvm::sys::path::append(Dir, "include");
285       addSystemInclude(DriverArgs, CC1Args, Dir.str());
286     }
287   }
288 }
289 
290 void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
291                                       ArgStringList &CC1Args,
292                                       Action::OffloadKind) const {
293   CC1Args.push_back("-nostdsysteminc");
294 }
295 
296 void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
297                                              ArgStringList &CC1Args) const {
298   if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
299                         options::OPT_nostdincxx))
300     return;
301 
302   const Driver &D = getDriver();
303   std::string Target = getTripleString();
304 
305   auto AddCXXIncludePath = [&](StringRef Path) {
306     std::string Version = detectLibcxxVersion(Path);
307     if (Version.empty())
308       return;
309 
310     {
311       // First the per-target include dir: include/<target>/c++/v1.
312       SmallString<128> TargetDir(Path);
313       llvm::sys::path::append(TargetDir, Target, "c++", Version);
314       addSystemInclude(DriverArgs, CC1Args, TargetDir);
315     }
316 
317     {
318       // Then the generic dir: include/c++/v1.
319       SmallString<128> Dir(Path);
320       llvm::sys::path::append(Dir, "c++", Version);
321       addSystemInclude(DriverArgs, CC1Args, Dir);
322     }
323   };
324 
325   switch (GetCXXStdlibType(DriverArgs)) {
326     case ToolChain::CST_Libcxx: {
327       SmallString<128> P(D.Dir);
328       llvm::sys::path::append(P, "..", "include");
329       AddCXXIncludePath(P);
330       break;
331     }
332     case ToolChain::CST_Libstdcxx:
333       // We only support libc++ toolchain installation.
334       break;
335   }
336 
337   std::string SysRoot(computeSysRoot());
338   if (SysRoot.empty())
339     return;
340 
341   for (const Multilib &M : getOrderedMultilibs()) {
342     SmallString<128> Dir(SysRoot);
343     llvm::sys::path::append(Dir, M.gccSuffix());
344     switch (GetCXXStdlibType(DriverArgs)) {
345     case ToolChain::CST_Libcxx: {
346       // First check sysroot/usr/include/c++/v1 if it exists.
347       SmallString<128> TargetDir(Dir);
348       llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1");
349       if (D.getVFS().exists(TargetDir)) {
350         addSystemInclude(DriverArgs, CC1Args, TargetDir.str());
351         break;
352       }
353       // Add generic path if nothing else succeeded so far.
354       llvm::sys::path::append(Dir, "include", "c++", "v1");
355       addSystemInclude(DriverArgs, CC1Args, Dir.str());
356       break;
357     }
358     case ToolChain::CST_Libstdcxx: {
359       llvm::sys::path::append(Dir, "include", "c++");
360       std::error_code EC;
361       Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
362       // Walk the subdirs, and find the one with the newest gcc version:
363       for (llvm::vfs::directory_iterator
364                LI = D.getVFS().dir_begin(Dir.str(), EC),
365                LE;
366            !EC && LI != LE; LI = LI.increment(EC)) {
367         StringRef VersionText = llvm::sys::path::filename(LI->path());
368         auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
369         if (CandidateVersion.Major == -1)
370           continue;
371         if (CandidateVersion <= Version)
372           continue;
373         Version = CandidateVersion;
374       }
375       if (Version.Major != -1) {
376         llvm::sys::path::append(Dir, Version.Text);
377         addSystemInclude(DriverArgs, CC1Args, Dir.str());
378       }
379       break;
380     }
381     }
382   }
383 }
384 
385 void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args,
386                                     ArgStringList &CmdArgs) const {
387   switch (GetCXXStdlibType(Args)) {
388   case ToolChain::CST_Libcxx:
389     CmdArgs.push_back("-lc++");
390     if (Args.hasArg(options::OPT_fexperimental_library))
391       CmdArgs.push_back("-lc++experimental");
392     CmdArgs.push_back("-lc++abi");
393     break;
394   case ToolChain::CST_Libstdcxx:
395     CmdArgs.push_back("-lstdc++");
396     CmdArgs.push_back("-lsupc++");
397     break;
398   }
399   CmdArgs.push_back("-lunwind");
400 }
401 
402 void BareMetal::AddLinkRuntimeLib(const ArgList &Args,
403                                   ArgStringList &CmdArgs) const {
404   ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args);
405   switch (RLT) {
406   case ToolChain::RLT_CompilerRT: {
407     CmdArgs.push_back(getCompilerRTArgString(Args, "builtins"));
408     return;
409   }
410   case ToolChain::RLT_Libgcc:
411     CmdArgs.push_back("-lgcc");
412     return;
413   }
414   llvm_unreachable("Unhandled RuntimeLibType.");
415 }
416 
417 void baremetal::StaticLibTool::ConstructJob(Compilation &C, const JobAction &JA,
418                                             const InputInfo &Output,
419                                             const InputInfoList &Inputs,
420                                             const ArgList &Args,
421                                             const char *LinkingOutput) const {
422   const Driver &D = getToolChain().getDriver();
423 
424   // Silence warning for "clang -g foo.o -o foo"
425   Args.ClaimAllArgs(options::OPT_g_Group);
426   // and "clang -emit-llvm foo.o -o foo"
427   Args.ClaimAllArgs(options::OPT_emit_llvm);
428   // and for "clang -w foo.o -o foo". Other warning options are already
429   // handled somewhere else.
430   Args.ClaimAllArgs(options::OPT_w);
431   // Silence warnings when linking C code with a C++ '-stdlib' argument.
432   Args.ClaimAllArgs(options::OPT_stdlib_EQ);
433 
434   // ar tool command "llvm-ar <options> <output_file> <input_files>".
435   ArgStringList CmdArgs;
436   // Create and insert file members with a deterministic index.
437   CmdArgs.push_back("rcsD");
438   CmdArgs.push_back(Output.getFilename());
439 
440   for (const auto &II : Inputs) {
441     if (II.isFilename()) {
442       CmdArgs.push_back(II.getFilename());
443     }
444   }
445 
446   // Delete old output archive file if it already exists before generating a new
447   // archive file.
448   const char *OutputFileName = Output.getFilename();
449   if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) {
450     if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) {
451       D.Diag(diag::err_drv_unable_to_remove_file) << EC.message();
452       return;
453     }
454   }
455 
456   const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath());
457   C.addCommand(std::make_unique<Command>(JA, *this,
458                                          ResponseFileSupport::AtFileCurCP(),
459                                          Exec, CmdArgs, Inputs, Output));
460 }
461 
462 void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
463                                      const InputInfo &Output,
464                                      const InputInfoList &Inputs,
465                                      const ArgList &Args,
466                                      const char *LinkingOutput) const {
467   ArgStringList CmdArgs;
468 
469   auto &TC = static_cast<const toolchains::BareMetal &>(getToolChain());
470   const Driver &D = getToolChain().getDriver();
471   const llvm::Triple::ArchType Arch = TC.getArch();
472   const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
473 
474   AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
475 
476   CmdArgs.push_back("-Bstatic");
477 
478   if (TC.getTriple().isRISCV() && Args.hasArg(options::OPT_mno_relax))
479     CmdArgs.push_back("--no-relax");
480 
481   if (Triple.isARM() || Triple.isThumb()) {
482     bool IsBigEndian = arm::isARMBigEndian(Triple, Args);
483     if (IsBigEndian)
484       arm::appendBE8LinkFlag(Args, CmdArgs, Triple);
485     CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL");
486   } else if (Triple.isAArch64()) {
487     CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL");
488   }
489 
490   Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
491                             options::OPT_s, options::OPT_t, options::OPT_r});
492 
493   TC.AddFilePathLibArgs(Args, CmdArgs);
494 
495   for (const auto &LibPath : TC.getLibraryPaths())
496     CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-L", LibPath)));
497 
498   if (TC.ShouldLinkCXXStdlib(Args))
499     TC.AddCXXStdlibLibArgs(Args, CmdArgs);
500 
501   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
502     CmdArgs.push_back("-lc");
503     CmdArgs.push_back("-lm");
504 
505     TC.AddLinkRuntimeLib(Args, CmdArgs);
506   }
507 
508   if (D.isUsingLTO()) {
509     assert(!Inputs.empty() && "Must have at least one input.");
510     // Find the first filename InputInfo object.
511     auto Input = llvm::find_if(
512         Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); });
513     if (Input == Inputs.end())
514       // For a very rare case, all of the inputs to the linker are
515       // InputArg. If that happens, just use the first InputInfo.
516       Input = Inputs.begin();
517 
518     addLTOOptions(TC, Args, CmdArgs, Output, *Input,
519                   D.getLTOMode() == LTOK_Thin);
520   }
521   if (TC.getTriple().isRISCV())
522     CmdArgs.push_back("-X");
523 
524   // The R_ARM_TARGET2 relocation must be treated as R_ARM_REL32 on arm*-*-elf
525   // and arm*-*-eabi (the default is R_ARM_GOT_PREL, used on arm*-*-linux and
526   // arm*-*-*bsd).
527   if (isARMBareMetal(TC.getTriple()))
528     CmdArgs.push_back("--target2=rel");
529 
530   CmdArgs.push_back("-o");
531   CmdArgs.push_back(Output.getFilename());
532 
533   C.addCommand(std::make_unique<Command>(
534       JA, *this, ResponseFileSupport::AtFileCurCP(),
535       Args.MakeArgString(TC.GetLinkerPath()), CmdArgs, Inputs, Output));
536 }
537 
538 // BareMetal toolchain allows all sanitizers where the compiler generates valid
539 // code, ignoring all runtime library support issues on the assumption that
540 // baremetal targets typically implement their own runtime support.
541 SanitizerMask BareMetal::getSupportedSanitizers() const {
542   const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
543   const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 ||
544                          getTriple().getArch() == llvm::Triple::aarch64_be;
545   const bool IsRISCV64 = getTriple().getArch() == llvm::Triple::riscv64;
546   SanitizerMask Res = ToolChain::getSupportedSanitizers();
547   Res |= SanitizerKind::Address;
548   Res |= SanitizerKind::KernelAddress;
549   Res |= SanitizerKind::PointerCompare;
550   Res |= SanitizerKind::PointerSubtract;
551   Res |= SanitizerKind::Fuzzer;
552   Res |= SanitizerKind::FuzzerNoLink;
553   Res |= SanitizerKind::Vptr;
554   Res |= SanitizerKind::SafeStack;
555   Res |= SanitizerKind::Thread;
556   Res |= SanitizerKind::Scudo;
557   if (IsX86_64 || IsAArch64 || IsRISCV64) {
558     Res |= SanitizerKind::HWAddress;
559     Res |= SanitizerKind::KernelHWAddress;
560   }
561   return Res;
562 }
563