clang  14.0.0git
BareMetal.cpp
Go to the documentation of this file.
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/RISCV.h"
17 #include "clang/Driver/Driver.h"
19 #include "clang/Driver/Options.h"
20 #include "llvm/Option/ArgList.h"
21 #include "llvm/Support/Path.h"
22 #include "llvm/Support/VirtualFileSystem.h"
23 #include "llvm/Support/raw_ostream.h"
24 
25 using namespace llvm::opt;
26 using namespace clang;
27 using namespace clang::driver;
28 using namespace clang::driver::tools;
29 using namespace clang::driver::toolchains;
30 
31 static Multilib makeMultilib(StringRef commonSuffix) {
32  return Multilib(commonSuffix, commonSuffix, commonSuffix);
33 }
34 
35 static bool findRISCVMultilibs(const Driver &D,
36  const llvm::Triple &TargetTriple,
37  const ArgList &Args, DetectedMultilibs &Result) {
39  StringRef Arch = riscv::getRISCVArch(Args, TargetTriple);
40  StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple);
41 
42  if (TargetTriple.getArch() == llvm::Triple::riscv64) {
43  Multilib Imac = makeMultilib("").flag("+march=rv64imac").flag("+mabi=lp64");
44  Multilib Imafdc = makeMultilib("/rv64imafdc/lp64d")
45  .flag("+march=rv64imafdc")
46  .flag("+mabi=lp64d");
47 
48  // Multilib reuse
49  bool UseImafdc =
50  (Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc
51 
52  addMultilibFlag((Arch == "rv64imac"), "march=rv64imac", Flags);
53  addMultilibFlag(UseImafdc, "march=rv64imafdc", Flags);
54  addMultilibFlag(Abi == "lp64", "mabi=lp64", Flags);
55  addMultilibFlag(Abi == "lp64d", "mabi=lp64d", Flags);
56 
57  Result.Multilibs = MultilibSet().Either(Imac, Imafdc);
58  return Result.Multilibs.select(Flags, Result.SelectedMultilib);
59  }
60  if (TargetTriple.getArch() == llvm::Triple::riscv32) {
61  Multilib Imac =
62  makeMultilib("").flag("+march=rv32imac").flag("+mabi=ilp32");
63  Multilib I =
64  makeMultilib("/rv32i/ilp32").flag("+march=rv32i").flag("+mabi=ilp32");
65  Multilib Im =
66  makeMultilib("/rv32im/ilp32").flag("+march=rv32im").flag("+mabi=ilp32");
67  Multilib Iac = makeMultilib("/rv32iac/ilp32")
68  .flag("+march=rv32iac")
69  .flag("+mabi=ilp32");
70  Multilib Imafc = makeMultilib("/rv32imafc/ilp32f")
71  .flag("+march=rv32imafc")
72  .flag("+mabi=ilp32f");
73 
74  // Multilib reuse
75  bool UseI = (Arch == "rv32i") || (Arch == "rv32ic"); // ic => i
76  bool UseIm = (Arch == "rv32im") || (Arch == "rv32imc"); // imc => im
77  bool UseImafc = (Arch == "rv32imafc") || (Arch == "rv32imafdc") ||
78  (Arch == "rv32gc"); // imafdc,gc => imafc
79 
80  addMultilibFlag(UseI, "march=rv32i", Flags);
81  addMultilibFlag(UseIm, "march=rv32im", Flags);
82  addMultilibFlag((Arch == "rv32iac"), "march=rv32iac", Flags);
83  addMultilibFlag((Arch == "rv32imac"), "march=rv32imac", Flags);
84  addMultilibFlag(UseImafc, "march=rv32imafc", Flags);
85  addMultilibFlag(Abi == "ilp32", "mabi=ilp32", Flags);
86  addMultilibFlag(Abi == "ilp32f", "mabi=ilp32f", Flags);
87 
88  Result.Multilibs = MultilibSet().Either(I, Im, Iac, Imac, Imafc);
89  return Result.Multilibs.select(Flags, Result.SelectedMultilib);
90  }
91  return false;
92 }
93 
94 BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
95  const ArgList &Args)
96  : ToolChain(D, Triple, Args) {
97  getProgramPaths().push_back(getDriver().getInstalledDir());
98  if (getDriver().getInstalledDir() != getDriver().Dir)
99  getProgramPaths().push_back(getDriver().Dir);
100 
101  findMultilibs(D, Triple, Args);
102  SmallString<128> SysRoot(computeSysRoot());
103  if (!SysRoot.empty()) {
104  llvm::sys::path::append(SysRoot, "lib");
105  getFilePaths().push_back(std::string(SysRoot));
106  }
107 }
108 
109 /// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ?
110 static bool isARMBareMetal(const llvm::Triple &Triple) {
111  if (Triple.getArch() != llvm::Triple::arm &&
112  Triple.getArch() != llvm::Triple::thumb)
113  return false;
114 
115  if (Triple.getVendor() != llvm::Triple::UnknownVendor)
116  return false;
117 
118  if (Triple.getOS() != llvm::Triple::UnknownOS)
119  return false;
120 
121  if (Triple.getEnvironment() != llvm::Triple::EABI &&
122  Triple.getEnvironment() != llvm::Triple::EABIHF)
123  return false;
124 
125  return true;
126 }
127 
128 /// Is the triple aarch64-none-elf?
129 static bool isAArch64BareMetal(const llvm::Triple &Triple) {
130  if (Triple.getArch() != llvm::Triple::aarch64)
131  return false;
132 
133  if (Triple.getVendor() != llvm::Triple::UnknownVendor)
134  return false;
135 
136  if (Triple.getOS() != llvm::Triple::UnknownOS)
137  return false;
138 
139  return Triple.getEnvironmentName() == "elf";
140 }
141 
142 static bool isRISCVBareMetal(const llvm::Triple &Triple) {
143  if (Triple.getArch() != llvm::Triple::riscv32 &&
144  Triple.getArch() != llvm::Triple::riscv64)
145  return false;
146 
147  if (Triple.getVendor() != llvm::Triple::UnknownVendor)
148  return false;
149 
150  if (Triple.getOS() != llvm::Triple::UnknownOS)
151  return false;
152 
153  return Triple.getEnvironmentName() == "elf";
154 }
155 
156 void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
157  const ArgList &Args) {
158  DetectedMultilibs Result;
159  if (isRISCVBareMetal(Triple)) {
160  if (findRISCVMultilibs(D, Triple, Args, Result)) {
161  SelectedMultilib = Result.SelectedMultilib;
162  Multilibs = Result.Multilibs;
163  }
164  }
165 }
166 
167 bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
168  return isARMBareMetal(Triple) || isAArch64BareMetal(Triple) ||
169  isRISCVBareMetal(Triple);
170 }
171 
173  return new tools::baremetal::Linker(*this);
174 }
175 
177 
179  StringRef, FileType,
180  bool) const {
181  return ("libclang_rt.builtins-" + getTriple().getArchName() + ".a").str();
182 }
183 
185  SmallString<128> Dir(getDriver().ResourceDir);
186  llvm::sys::path::append(Dir, "lib", "baremetal");
187  Dir += SelectedMultilib.gccSuffix();
188  return std::string(Dir.str());
189 }
190 
192  if (!getDriver().SysRoot.empty())
194 
195  SmallString<128> SysRootDir;
196  llvm::sys::path::append(SysRootDir, getDriver().Dir, "../lib/clang-runtimes",
197  getDriver().getTargetTriple());
198 
199  SysRootDir += SelectedMultilib.osSuffix();
200  return std::string(SysRootDir);
201 }
202 
203 void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
204  ArgStringList &CC1Args) const {
205  if (DriverArgs.hasArg(options::OPT_nostdinc))
206  return;
207 
208  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
209  SmallString<128> Dir(getDriver().ResourceDir);
210  llvm::sys::path::append(Dir, "include");
211  addSystemInclude(DriverArgs, CC1Args, Dir.str());
212  }
213 
214  if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) {
216  if (!Dir.empty()) {
217  llvm::sys::path::append(Dir, "include");
218  addSystemInclude(DriverArgs, CC1Args, Dir.str());
219  }
220  }
221 }
222 
223 void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
224  ArgStringList &CC1Args,
225  Action::OffloadKind) const {
226  CC1Args.push_back("-nostdsysteminc");
227 }
228 
230  const ArgList &DriverArgs, ArgStringList &CC1Args) const {
231  if (DriverArgs.hasArg(options::OPT_nostdinc) ||
232  DriverArgs.hasArg(options::OPT_nostdlibinc) ||
233  DriverArgs.hasArg(options::OPT_nostdincxx))
234  return;
235 
236  std::string SysRoot(computeSysRoot());
237  if (SysRoot.empty())
238  return;
239 
240  switch (GetCXXStdlibType(DriverArgs)) {
241  case ToolChain::CST_Libcxx: {
242  SmallString<128> Dir(SysRoot);
243  llvm::sys::path::append(Dir, "include", "c++", "v1");
244  addSystemInclude(DriverArgs, CC1Args, Dir.str());
245  break;
246  }
248  SmallString<128> Dir(SysRoot);
249  llvm::sys::path::append(Dir, "include", "c++");
250  std::error_code EC;
251  Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
252  // Walk the subdirs, and find the one with the newest gcc version:
253  for (llvm::vfs::directory_iterator
254  LI = getDriver().getVFS().dir_begin(Dir.str(), EC),
255  LE;
256  !EC && LI != LE; LI = LI.increment(EC)) {
257  StringRef VersionText = llvm::sys::path::filename(LI->path());
258  auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
259  if (CandidateVersion.Major == -1)
260  continue;
261  if (CandidateVersion <= Version)
262  continue;
263  Version = CandidateVersion;
264  }
265  if (Version.Major == -1)
266  return;
267  llvm::sys::path::append(Dir, Version.Text);
268  addSystemInclude(DriverArgs, CC1Args, Dir.str());
269  break;
270  }
271  }
272 }
273 
274 void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args,
275  ArgStringList &CmdArgs) const {
276  switch (GetCXXStdlibType(Args)) {
278  CmdArgs.push_back("-lc++");
279  CmdArgs.push_back("-lc++abi");
280  break;
282  CmdArgs.push_back("-lstdc++");
283  CmdArgs.push_back("-lsupc++");
284  break;
285  }
286  CmdArgs.push_back("-lunwind");
287 }
288 
289 void BareMetal::AddLinkRuntimeLib(const ArgList &Args,
290  ArgStringList &CmdArgs) const {
292  switch (RLT) {
294  CmdArgs.push_back(
295  Args.MakeArgString("-lclang_rt.builtins-" + getTriple().getArchName()));
296  return;
298  CmdArgs.push_back("-lgcc");
299  return;
300  }
301  llvm_unreachable("Unhandled RuntimeLibType.");
302 }
303 
304 void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
305  const InputInfo &Output,
306  const InputInfoList &Inputs,
307  const ArgList &Args,
308  const char *LinkingOutput) const {
309  ArgStringList CmdArgs;
310 
311  auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain());
312 
313  AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
314 
315  CmdArgs.push_back("-Bstatic");
316 
317  Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
318  options::OPT_e, options::OPT_s, options::OPT_t,
319  options::OPT_Z_Flag, options::OPT_r});
320 
321  TC.AddFilePathLibArgs(Args, CmdArgs);
322 
323  CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir()));
324 
325  if (TC.ShouldLinkCXXStdlib(Args))
326  TC.AddCXXStdlibLibArgs(Args, CmdArgs);
327  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
328  CmdArgs.push_back("-lc");
329  CmdArgs.push_back("-lm");
330 
331  TC.AddLinkRuntimeLib(Args, CmdArgs);
332  }
333 
334  CmdArgs.push_back("-o");
335  CmdArgs.push_back(Output.getFilename());
336 
337  C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
338  Args.MakeArgString(TC.GetLinkerPath()),
339  CmdArgs, Inputs, Output));
340 }
clang::driver::toolchains
Definition: AIX.h:55
clang::driver::Multilib::flags_list
std::vector< std::string > flags_list
Definition: Multilib.h:30
makeMultilib
static Multilib makeMultilib(StringRef commonSuffix)
Definition: BareMetal.cpp:31
clang::driver::MultilibSet::Either
MultilibSet & Either(const Multilib &M1, const Multilib &M2)
Add a set of mutually incompatible Multilib segments.
Definition: Multilib.cpp:152
clang::driver::ToolChain::getVFS
llvm::vfs::FileSystem & getVFS() const
Definition: ToolChain.cpp:99
clang::driver::ToolChain::getProgramPaths
path_list & getProgramPaths()
Definition: ToolChain.h:262
Driver.h
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
clang::driver::MultilibSet
Definition: Multilib.h:114
llvm::SmallVector
Definition: LLVM.h:38
clang::driver::tools
Definition: AIX.h:17
clang::driver::ToolChain::getDriver
const Driver & getDriver() const
Definition: ToolChain.h:221
isRISCVBareMetal
static bool isRISCVBareMetal(const llvm::Triple &Triple)
Definition: BareMetal.cpp:142
clang::driver::ToolChain::getArchName
StringRef getArchName() const
Definition: ToolChain.h:238
clang::driver::InputInfo
InputInfo - Wrapper for information about an input source.
Definition: InputInfo.h:22
RISCV.h
clang::driver::ToolChain::RuntimeLibType
RuntimeLibType
Definition: ToolChain.h:100
InputInfo.h
clang::driver::tools::riscv::getRISCVArch
StringRef getRISCVArch(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
Definition: RISCV.cpp:237
clang::driver::tools::AddLinkerInputs
void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const JobAction &JA)
clang::driver::toolchains::Generic_GCC::GCCVersion
Struct to store and manipulate GCC versions.
Definition: Gnu.h:161
clang::driver::ToolChain::getFilePaths
path_list & getFilePaths()
Definition: ToolChain.h:259
clang::driver::tools::baremetal::Linker
Definition: BareMetal.h:83
clang::driver::toolchains::BareMetal::AddClangSystemIncludeArgs
void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override
Add the clang cc1 arguments for system include paths.
Definition: BareMetal.cpp:203
clang::driver::Multilib::gccSuffix
const std::string & gccSuffix() const
Get the detected GCC installation path suffix for the multi-arch target variant.
Definition: Multilib.h:45
clang::driver::Tool
Tool - Information on a specific compilation tool.
Definition: Tool.h:32
Options.h
clang::driver::toolchains::Generic_GCC::GCCVersion::Text
std::string Text
The unparsed text of the version.
Definition: Gnu.h:163
clang::driver::Multilib::osSuffix
const std::string & osSuffix() const
Get the detected os path suffix for the multi-arch target variant.
Definition: Multilib.h:56
clang::interp::LE
bool LE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:239
llvm::opt
Definition: DiagnosticOptions.h:19
DriverDiagnostic.h
clang::driver::ToolChain::RLT_Libgcc
@ RLT_Libgcc
Definition: ToolChain.h:102
BareMetal.h
clang::driver::toolchains::BareMetal::AddClangCXXStdlibIncludeArgs
void AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override
AddClangCXXStdlibIncludeArgs - Add the clang -cc1 level arguments to set the include paths to use for...
Definition: BareMetal.cpp:229
llvm::SmallString< 128 >
clang::driver::ToolChain::getTriple
const llvm::Triple & getTriple() const
Definition: ToolChain.h:223
clang::driver::ToolChain::SelectedMultilib
Multilib SelectedMultilib
Definition: ToolChain.h:182
clang::driver::Driver::SysRoot
std::string SysRoot
sysroot, if present
Definition: Driver.h:151
clang::driver::Multilib
This corresponds to a single GCC Multilib, or a segment of one controlled by a command line flag.
Definition: Multilib.h:28
clang::driver::ToolChain::CST_Libcxx
@ CST_Libcxx
Definition: ToolChain.h:96
findRISCVMultilibs
static bool findRISCVMultilibs(const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args, DetectedMultilibs &Result)
Definition: BareMetal.cpp:35
clang::driver::toolchains::Generic_GCC::GCCVersion::Parse
static GCCVersion Parse(StringRef VersionText)
Parse a GCCVersion object out of a string of text.
Definition: Gnu.cpp:1820
clang::driver::ToolChain::CST_Libstdcxx
@ CST_Libstdcxx
Definition: ToolChain.h:97
clang::driver::toolchains::BareMetal::getCompilerRTPath
std::string getCompilerRTPath() const override
Definition: BareMetal.cpp:176
clang::driver::toolchains::BareMetal::buildCompilerRTBasename
std::string buildCompilerRTBasename(const llvm::opt::ArgList &Args, StringRef Component, FileType Type=ToolChain::FT_Static, bool AddArch=true) const override
Definition: BareMetal.cpp:178
clang::driver::toolchains::BareMetal::buildLinker
Tool * buildLinker() const override
Definition: BareMetal.cpp:172
clang::driver::toolchains::BareMetal::getRuntimesDir
std::string getRuntimesDir() const
Definition: BareMetal.cpp:184
clang::driver::toolchains::BareMetal
Definition: BareMetal.h:22
clang::driver::ToolChain::GetRuntimeLibType
virtual RuntimeLibType GetRuntimeLibType(const llvm::opt::ArgList &Args) const
Definition: ToolChain.cpp:757
Compilation.h
clang::driver::toolchains::BareMetal::findMultilibs
void findMultilibs(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args)
Definition: BareMetal.cpp:156
Gnu.h
clang::driver::ToolChain
ToolChain - Access to tools for a single platform.
Definition: ToolChain.h:91
clang::driver::ToolChain::RLT_CompilerRT
@ RLT_CompilerRT
Definition: ToolChain.h:101
isAArch64BareMetal
static bool isAArch64BareMetal(const llvm::Triple &Triple)
Is the triple aarch64-none-elf?
Definition: BareMetal.cpp:129
clang::driver::Multilib::flag
Multilib & flag(StringRef F)
Add a flag to the flags list Flag must be a flag accepted by the driver with its leading '-' removed,...
Definition: Multilib.h:92
clang::driver::Compilation
Compilation - A set of tasks to perform for a single driver invocation.
Definition: Compilation.h:45
clang::driver::ToolChain::FileType
FileType
Definition: ToolChain.h:123
clang::driver::toolchains::BareMetal::AddCXXStdlibLibArgs
void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override
AddCXXStdlibLibArgs - Add the system specific linker arguments to use for the given C++ standard libr...
Definition: BareMetal.cpp:274
clang::driver::ToolChain::GetCXXStdlibType
virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const
Definition: ToolChain.cpp:819
clang::driver::toolchains::Generic_GCC::GCCVersion::Major
int Major
The parsed major, minor, and patch numbers.
Definition: Gnu.h:166
clang::driver::InputInfo::getFilename
const char * getFilename() const
Definition: InputInfo.h:83
CommonArgs.h
clang
Definition: CalledOnceCheck.h:17
clang::driver::Driver
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition: Driver.h:59
clang::driver::tools::addMultilibFlag
void addMultilibFlag(bool Enabled, const char *const Flag, Multilib::flags_list &Flags)
Flag must be a flag accepted by the driver with its leading '-' removed,
Definition: CommonArgs.cpp:1536
clang::driver::ToolChain::Multilibs
MultilibSet Multilibs
Definition: ToolChain.h:181
clang::driver::DetectedMultilibs
Definition: Gnu.h:21
clang::driver::tools::riscv::getRISCVABI
StringRef getRISCVABI(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
clang::driver::toolchains::BareMetal::computeSysRoot
std::string computeSysRoot() const override
Return the sysroot, possibly searching for a default sysroot using target-specific logic.
Definition: BareMetal.cpp:191
isARMBareMetal
static bool isARMBareMetal(const llvm::Triple &Triple)
Is the triple {arm,thumb}-none-none-{eabi,eabihf} ?
Definition: BareMetal.cpp:110
clang::driver::Action::OffloadKind
OffloadKind
Definition: Action.h:85
clang::driver::toolchains::BareMetal::addClangTargetOptions
void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override
Add options that need to be passed to cc1 for this target.
Definition: BareMetal.cpp:223
clang::driver
Definition: Action.h:31
clang::driver::ResponseFileSupport::None
static constexpr ResponseFileSupport None()
Returns a ResponseFileSupport indicating that response files are not supported.
Definition: Job.h:78
clang::driver::ToolChain::addSystemInclude
static void addSystemInclude(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, const Twine &Path)
Utility function to add a system include directory to CC1 arguments.
Definition: ToolChain.cpp:845
clang::driver::toolchains::BareMetal::handlesTarget
static bool handlesTarget(const llvm::Triple &Triple)
Definition: BareMetal.cpp:167
clang::driver::JobAction
Definition: Action.h:380
clang::driver::toolchains::BareMetal::AddLinkRuntimeLib
void AddLinkRuntimeLib(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const
Definition: BareMetal.cpp:289