1e5dd7070Spatrick //===-- BareMetal.cpp - Bare Metal ToolChain --------------------*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick
9e5dd7070Spatrick #include "BareMetal.h"
10e5dd7070Spatrick
11e5dd7070Spatrick #include "CommonArgs.h"
12e5dd7070Spatrick #include "Gnu.h"
13a9ac8606Spatrick #include "clang/Driver/InputInfo.h"
14e5dd7070Spatrick
15a9ac8606Spatrick #include "Arch/RISCV.h"
16e5dd7070Spatrick #include "clang/Driver/Compilation.h"
17e5dd7070Spatrick #include "clang/Driver/Driver.h"
18e5dd7070Spatrick #include "clang/Driver/DriverDiagnostic.h"
19e5dd7070Spatrick #include "clang/Driver/Options.h"
20e5dd7070Spatrick #include "llvm/Option/ArgList.h"
21e5dd7070Spatrick #include "llvm/Support/Path.h"
22e5dd7070Spatrick #include "llvm/Support/VirtualFileSystem.h"
23e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
24e5dd7070Spatrick
25e5dd7070Spatrick using namespace llvm::opt;
26e5dd7070Spatrick using namespace clang;
27e5dd7070Spatrick using namespace clang::driver;
28e5dd7070Spatrick using namespace clang::driver::tools;
29e5dd7070Spatrick using namespace clang::driver::toolchains;
30e5dd7070Spatrick
makeMultilib(StringRef commonSuffix)31a9ac8606Spatrick static Multilib makeMultilib(StringRef commonSuffix) {
32a9ac8606Spatrick return Multilib(commonSuffix, commonSuffix, commonSuffix);
33a9ac8606Spatrick }
34a9ac8606Spatrick
findRISCVMultilibs(const Driver & D,const llvm::Triple & TargetTriple,const ArgList & Args,DetectedMultilibs & Result)35a9ac8606Spatrick static bool findRISCVMultilibs(const Driver &D,
36a9ac8606Spatrick const llvm::Triple &TargetTriple,
37a9ac8606Spatrick const ArgList &Args, DetectedMultilibs &Result) {
38a9ac8606Spatrick Multilib::flags_list Flags;
39a9ac8606Spatrick StringRef Arch = riscv::getRISCVArch(Args, TargetTriple);
40a9ac8606Spatrick StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple);
41a9ac8606Spatrick
42*12c85518Srobert if (TargetTriple.isRISCV64()) {
43a9ac8606Spatrick Multilib Imac = makeMultilib("").flag("+march=rv64imac").flag("+mabi=lp64");
44a9ac8606Spatrick Multilib Imafdc = makeMultilib("/rv64imafdc/lp64d")
45a9ac8606Spatrick .flag("+march=rv64imafdc")
46a9ac8606Spatrick .flag("+mabi=lp64d");
47a9ac8606Spatrick
48a9ac8606Spatrick // Multilib reuse
49a9ac8606Spatrick bool UseImafdc =
50a9ac8606Spatrick (Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc
51a9ac8606Spatrick
52a9ac8606Spatrick addMultilibFlag((Arch == "rv64imac"), "march=rv64imac", Flags);
53a9ac8606Spatrick addMultilibFlag(UseImafdc, "march=rv64imafdc", Flags);
54a9ac8606Spatrick addMultilibFlag(Abi == "lp64", "mabi=lp64", Flags);
55a9ac8606Spatrick addMultilibFlag(Abi == "lp64d", "mabi=lp64d", Flags);
56a9ac8606Spatrick
57a9ac8606Spatrick Result.Multilibs = MultilibSet().Either(Imac, Imafdc);
58a9ac8606Spatrick return Result.Multilibs.select(Flags, Result.SelectedMultilib);
59a9ac8606Spatrick }
60*12c85518Srobert if (TargetTriple.isRISCV32()) {
61a9ac8606Spatrick Multilib Imac =
62a9ac8606Spatrick makeMultilib("").flag("+march=rv32imac").flag("+mabi=ilp32");
63a9ac8606Spatrick Multilib I =
64a9ac8606Spatrick makeMultilib("/rv32i/ilp32").flag("+march=rv32i").flag("+mabi=ilp32");
65a9ac8606Spatrick Multilib Im =
66a9ac8606Spatrick makeMultilib("/rv32im/ilp32").flag("+march=rv32im").flag("+mabi=ilp32");
67a9ac8606Spatrick Multilib Iac = makeMultilib("/rv32iac/ilp32")
68a9ac8606Spatrick .flag("+march=rv32iac")
69a9ac8606Spatrick .flag("+mabi=ilp32");
70a9ac8606Spatrick Multilib Imafc = makeMultilib("/rv32imafc/ilp32f")
71a9ac8606Spatrick .flag("+march=rv32imafc")
72a9ac8606Spatrick .flag("+mabi=ilp32f");
73a9ac8606Spatrick
74a9ac8606Spatrick // Multilib reuse
75a9ac8606Spatrick bool UseI = (Arch == "rv32i") || (Arch == "rv32ic"); // ic => i
76a9ac8606Spatrick bool UseIm = (Arch == "rv32im") || (Arch == "rv32imc"); // imc => im
77a9ac8606Spatrick bool UseImafc = (Arch == "rv32imafc") || (Arch == "rv32imafdc") ||
78a9ac8606Spatrick (Arch == "rv32gc"); // imafdc,gc => imafc
79a9ac8606Spatrick
80a9ac8606Spatrick addMultilibFlag(UseI, "march=rv32i", Flags);
81a9ac8606Spatrick addMultilibFlag(UseIm, "march=rv32im", Flags);
82a9ac8606Spatrick addMultilibFlag((Arch == "rv32iac"), "march=rv32iac", Flags);
83a9ac8606Spatrick addMultilibFlag((Arch == "rv32imac"), "march=rv32imac", Flags);
84a9ac8606Spatrick addMultilibFlag(UseImafc, "march=rv32imafc", Flags);
85a9ac8606Spatrick addMultilibFlag(Abi == "ilp32", "mabi=ilp32", Flags);
86a9ac8606Spatrick addMultilibFlag(Abi == "ilp32f", "mabi=ilp32f", Flags);
87a9ac8606Spatrick
88a9ac8606Spatrick Result.Multilibs = MultilibSet().Either(I, Im, Iac, Imac, Imafc);
89a9ac8606Spatrick return Result.Multilibs.select(Flags, Result.SelectedMultilib);
90a9ac8606Spatrick }
91a9ac8606Spatrick return false;
92a9ac8606Spatrick }
93a9ac8606Spatrick
BareMetal(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)94e5dd7070Spatrick BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
95e5dd7070Spatrick const ArgList &Args)
96e5dd7070Spatrick : ToolChain(D, Triple, Args) {
97e5dd7070Spatrick getProgramPaths().push_back(getDriver().getInstalledDir());
98e5dd7070Spatrick if (getDriver().getInstalledDir() != getDriver().Dir)
99e5dd7070Spatrick getProgramPaths().push_back(getDriver().Dir);
100e5dd7070Spatrick
101a9ac8606Spatrick findMultilibs(D, Triple, Args);
102a9ac8606Spatrick SmallString<128> SysRoot(computeSysRoot());
103a9ac8606Spatrick if (!SysRoot.empty()) {
104a9ac8606Spatrick llvm::sys::path::append(SysRoot, "lib");
105a9ac8606Spatrick getFilePaths().push_back(std::string(SysRoot));
106*12c85518Srobert getLibraryPaths().push_back(std::string(SysRoot));
107a9ac8606Spatrick }
108a9ac8606Spatrick }
109e5dd7070Spatrick
110e5dd7070Spatrick /// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ?
isARMBareMetal(const llvm::Triple & Triple)111e5dd7070Spatrick static bool isARMBareMetal(const llvm::Triple &Triple) {
112e5dd7070Spatrick if (Triple.getArch() != llvm::Triple::arm &&
113e5dd7070Spatrick Triple.getArch() != llvm::Triple::thumb)
114e5dd7070Spatrick return false;
115e5dd7070Spatrick
116e5dd7070Spatrick if (Triple.getVendor() != llvm::Triple::UnknownVendor)
117e5dd7070Spatrick return false;
118e5dd7070Spatrick
119e5dd7070Spatrick if (Triple.getOS() != llvm::Triple::UnknownOS)
120e5dd7070Spatrick return false;
121e5dd7070Spatrick
122e5dd7070Spatrick if (Triple.getEnvironment() != llvm::Triple::EABI &&
123e5dd7070Spatrick Triple.getEnvironment() != llvm::Triple::EABIHF)
124e5dd7070Spatrick return false;
125e5dd7070Spatrick
126e5dd7070Spatrick return true;
127e5dd7070Spatrick }
128e5dd7070Spatrick
129*12c85518Srobert /// Is the triple aarch64-none-elf?
isAArch64BareMetal(const llvm::Triple & Triple)130*12c85518Srobert static bool isAArch64BareMetal(const llvm::Triple &Triple) {
131*12c85518Srobert if (Triple.getArch() != llvm::Triple::aarch64)
132*12c85518Srobert return false;
133*12c85518Srobert
134*12c85518Srobert if (Triple.getVendor() != llvm::Triple::UnknownVendor)
135*12c85518Srobert return false;
136*12c85518Srobert
137*12c85518Srobert if (Triple.getOS() != llvm::Triple::UnknownOS)
138*12c85518Srobert return false;
139*12c85518Srobert
140*12c85518Srobert return Triple.getEnvironmentName() == "elf";
141*12c85518Srobert }
142*12c85518Srobert
isRISCVBareMetal(const llvm::Triple & Triple)143a9ac8606Spatrick static bool isRISCVBareMetal(const llvm::Triple &Triple) {
144*12c85518Srobert if (!Triple.isRISCV())
145a9ac8606Spatrick return false;
146a9ac8606Spatrick
147a9ac8606Spatrick if (Triple.getVendor() != llvm::Triple::UnknownVendor)
148a9ac8606Spatrick return false;
149a9ac8606Spatrick
150a9ac8606Spatrick if (Triple.getOS() != llvm::Triple::UnknownOS)
151a9ac8606Spatrick return false;
152a9ac8606Spatrick
153a9ac8606Spatrick return Triple.getEnvironmentName() == "elf";
154a9ac8606Spatrick }
155a9ac8606Spatrick
findMultilibs(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)156a9ac8606Spatrick void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
157a9ac8606Spatrick const ArgList &Args) {
158a9ac8606Spatrick DetectedMultilibs Result;
159a9ac8606Spatrick if (isRISCVBareMetal(Triple)) {
160a9ac8606Spatrick if (findRISCVMultilibs(D, Triple, Args, Result)) {
161a9ac8606Spatrick SelectedMultilib = Result.SelectedMultilib;
162a9ac8606Spatrick Multilibs = Result.Multilibs;
163a9ac8606Spatrick }
164a9ac8606Spatrick }
165a9ac8606Spatrick }
166a9ac8606Spatrick
handlesTarget(const llvm::Triple & Triple)167e5dd7070Spatrick bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
168*12c85518Srobert return isARMBareMetal(Triple) || isAArch64BareMetal(Triple) ||
169*12c85518Srobert isRISCVBareMetal(Triple);
170e5dd7070Spatrick }
171e5dd7070Spatrick
buildLinker() const172e5dd7070Spatrick Tool *BareMetal::buildLinker() const {
173e5dd7070Spatrick return new tools::baremetal::Linker(*this);
174e5dd7070Spatrick }
175e5dd7070Spatrick
computeSysRoot() const176a9ac8606Spatrick std::string BareMetal::computeSysRoot() const {
177a9ac8606Spatrick if (!getDriver().SysRoot.empty())
178a9ac8606Spatrick return getDriver().SysRoot + SelectedMultilib.osSuffix();
179a9ac8606Spatrick
180a9ac8606Spatrick SmallString<128> SysRootDir;
181a9ac8606Spatrick llvm::sys::path::append(SysRootDir, getDriver().Dir, "../lib/clang-runtimes",
182a9ac8606Spatrick getDriver().getTargetTriple());
183a9ac8606Spatrick
184a9ac8606Spatrick SysRootDir += SelectedMultilib.osSuffix();
185a9ac8606Spatrick return std::string(SysRootDir);
186a9ac8606Spatrick }
187a9ac8606Spatrick
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const188e5dd7070Spatrick void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
189e5dd7070Spatrick ArgStringList &CC1Args) const {
190e5dd7070Spatrick if (DriverArgs.hasArg(options::OPT_nostdinc))
191e5dd7070Spatrick return;
192e5dd7070Spatrick
193e5dd7070Spatrick if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
194e5dd7070Spatrick SmallString<128> Dir(getDriver().ResourceDir);
195e5dd7070Spatrick llvm::sys::path::append(Dir, "include");
196e5dd7070Spatrick addSystemInclude(DriverArgs, CC1Args, Dir.str());
197e5dd7070Spatrick }
198e5dd7070Spatrick
199e5dd7070Spatrick if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) {
200a9ac8606Spatrick SmallString<128> Dir(computeSysRoot());
201a9ac8606Spatrick if (!Dir.empty()) {
202e5dd7070Spatrick llvm::sys::path::append(Dir, "include");
203e5dd7070Spatrick addSystemInclude(DriverArgs, CC1Args, Dir.str());
204e5dd7070Spatrick }
205e5dd7070Spatrick }
206a9ac8606Spatrick }
207e5dd7070Spatrick
addClangTargetOptions(const ArgList & DriverArgs,ArgStringList & CC1Args,Action::OffloadKind) const208e5dd7070Spatrick void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
209e5dd7070Spatrick ArgStringList &CC1Args,
210e5dd7070Spatrick Action::OffloadKind) const {
211e5dd7070Spatrick CC1Args.push_back("-nostdsysteminc");
212e5dd7070Spatrick }
213e5dd7070Spatrick
AddClangCXXStdlibIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const214*12c85518Srobert void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
215*12c85518Srobert ArgStringList &CC1Args) const {
216e5dd7070Spatrick if (DriverArgs.hasArg(options::OPT_nostdinc) ||
217e5dd7070Spatrick DriverArgs.hasArg(options::OPT_nostdlibinc) ||
218e5dd7070Spatrick DriverArgs.hasArg(options::OPT_nostdincxx))
219e5dd7070Spatrick return;
220e5dd7070Spatrick
221*12c85518Srobert const Driver &D = getDriver();
222a9ac8606Spatrick std::string SysRoot(computeSysRoot());
223e5dd7070Spatrick if (SysRoot.empty())
224e5dd7070Spatrick return;
225e5dd7070Spatrick
226e5dd7070Spatrick switch (GetCXXStdlibType(DriverArgs)) {
227e5dd7070Spatrick case ToolChain::CST_Libcxx: {
228*12c85518Srobert // First check sysroot/usr/include/c++/v1 if it exists.
229*12c85518Srobert SmallString<128> TargetDir(SysRoot);
230*12c85518Srobert llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1");
231*12c85518Srobert if (D.getVFS().exists(TargetDir)) {
232*12c85518Srobert addSystemInclude(DriverArgs, CC1Args, TargetDir.str());
233*12c85518Srobert break;
234*12c85518Srobert }
235*12c85518Srobert // Add generic path if nothing else succeeded so far.
236e5dd7070Spatrick SmallString<128> Dir(SysRoot);
237e5dd7070Spatrick llvm::sys::path::append(Dir, "include", "c++", "v1");
238e5dd7070Spatrick addSystemInclude(DriverArgs, CC1Args, Dir.str());
239e5dd7070Spatrick break;
240e5dd7070Spatrick }
241e5dd7070Spatrick case ToolChain::CST_Libstdcxx: {
242e5dd7070Spatrick SmallString<128> Dir(SysRoot);
243e5dd7070Spatrick llvm::sys::path::append(Dir, "include", "c++");
244e5dd7070Spatrick std::error_code EC;
245e5dd7070Spatrick Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
246e5dd7070Spatrick // Walk the subdirs, and find the one with the newest gcc version:
247*12c85518Srobert for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(Dir.str(), EC),
248e5dd7070Spatrick LE;
249e5dd7070Spatrick !EC && LI != LE; LI = LI.increment(EC)) {
250e5dd7070Spatrick StringRef VersionText = llvm::sys::path::filename(LI->path());
251e5dd7070Spatrick auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
252e5dd7070Spatrick if (CandidateVersion.Major == -1)
253e5dd7070Spatrick continue;
254e5dd7070Spatrick if (CandidateVersion <= Version)
255e5dd7070Spatrick continue;
256e5dd7070Spatrick Version = CandidateVersion;
257e5dd7070Spatrick }
258e5dd7070Spatrick if (Version.Major == -1)
259e5dd7070Spatrick return;
260e5dd7070Spatrick llvm::sys::path::append(Dir, Version.Text);
261e5dd7070Spatrick addSystemInclude(DriverArgs, CC1Args, Dir.str());
262e5dd7070Spatrick break;
263e5dd7070Spatrick }
264e5dd7070Spatrick }
265e5dd7070Spatrick }
266e5dd7070Spatrick
AddCXXStdlibLibArgs(const ArgList & Args,ArgStringList & CmdArgs) const267e5dd7070Spatrick void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args,
268e5dd7070Spatrick ArgStringList &CmdArgs) const {
269e5dd7070Spatrick switch (GetCXXStdlibType(Args)) {
270e5dd7070Spatrick case ToolChain::CST_Libcxx:
271e5dd7070Spatrick CmdArgs.push_back("-lc++");
272*12c85518Srobert if (Args.hasArg(options::OPT_fexperimental_library))
273*12c85518Srobert CmdArgs.push_back("-lc++experimental");
274e5dd7070Spatrick CmdArgs.push_back("-lc++abi");
275e5dd7070Spatrick break;
276e5dd7070Spatrick case ToolChain::CST_Libstdcxx:
277e5dd7070Spatrick CmdArgs.push_back("-lstdc++");
278e5dd7070Spatrick CmdArgs.push_back("-lsupc++");
279e5dd7070Spatrick break;
280e5dd7070Spatrick }
281e5dd7070Spatrick CmdArgs.push_back("-lunwind");
282e5dd7070Spatrick }
283e5dd7070Spatrick
AddLinkRuntimeLib(const ArgList & Args,ArgStringList & CmdArgs) const284e5dd7070Spatrick void BareMetal::AddLinkRuntimeLib(const ArgList &Args,
285e5dd7070Spatrick ArgStringList &CmdArgs) const {
286a9ac8606Spatrick ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args);
287a9ac8606Spatrick switch (RLT) {
288*12c85518Srobert case ToolChain::RLT_CompilerRT: {
289*12c85518Srobert const std::string FileName = getCompilerRT(Args, "builtins");
290*12c85518Srobert llvm::StringRef BaseName = llvm::sys::path::filename(FileName);
291*12c85518Srobert BaseName.consume_front("lib");
292*12c85518Srobert BaseName.consume_back(".a");
293*12c85518Srobert CmdArgs.push_back(Args.MakeArgString("-l" + BaseName));
294a9ac8606Spatrick return;
295*12c85518Srobert }
296a9ac8606Spatrick case ToolChain::RLT_Libgcc:
297a9ac8606Spatrick CmdArgs.push_back("-lgcc");
298a9ac8606Spatrick return;
299a9ac8606Spatrick }
300a9ac8606Spatrick llvm_unreachable("Unhandled RuntimeLibType.");
301e5dd7070Spatrick }
302e5dd7070Spatrick
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const303e5dd7070Spatrick void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
304e5dd7070Spatrick const InputInfo &Output,
305e5dd7070Spatrick const InputInfoList &Inputs,
306e5dd7070Spatrick const ArgList &Args,
307e5dd7070Spatrick const char *LinkingOutput) const {
308e5dd7070Spatrick ArgStringList CmdArgs;
309e5dd7070Spatrick
310e5dd7070Spatrick auto &TC = static_cast<const toolchains::BareMetal &>(getToolChain());
311e5dd7070Spatrick
312e5dd7070Spatrick AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
313e5dd7070Spatrick
314e5dd7070Spatrick CmdArgs.push_back("-Bstatic");
315e5dd7070Spatrick
316e5dd7070Spatrick Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
317e5dd7070Spatrick options::OPT_e, options::OPT_s, options::OPT_t,
318e5dd7070Spatrick options::OPT_Z_Flag, options::OPT_r});
319e5dd7070Spatrick
320a9ac8606Spatrick TC.AddFilePathLibArgs(Args, CmdArgs);
321a9ac8606Spatrick
322*12c85518Srobert for (const auto &LibPath : TC.getLibraryPaths())
323*12c85518Srobert CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-L", LibPath)));
324*12c85518Srobert
325*12c85518Srobert const std::string FileName = TC.getCompilerRT(Args, "builtins");
326*12c85518Srobert llvm::SmallString<128> PathBuf{FileName};
327*12c85518Srobert llvm::sys::path::remove_filename(PathBuf);
328*12c85518Srobert CmdArgs.push_back(Args.MakeArgString("-L" + PathBuf));
329a9ac8606Spatrick
330e5dd7070Spatrick if (TC.ShouldLinkCXXStdlib(Args))
331e5dd7070Spatrick TC.AddCXXStdlibLibArgs(Args, CmdArgs);
332*12c85518Srobert
333e5dd7070Spatrick if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
334e5dd7070Spatrick CmdArgs.push_back("-lc");
335e5dd7070Spatrick CmdArgs.push_back("-lm");
336e5dd7070Spatrick
337e5dd7070Spatrick TC.AddLinkRuntimeLib(Args, CmdArgs);
338e5dd7070Spatrick }
339e5dd7070Spatrick
340e5dd7070Spatrick CmdArgs.push_back("-o");
341e5dd7070Spatrick CmdArgs.push_back(Output.getFilename());
342e5dd7070Spatrick
343ec727ea7Spatrick C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
344e5dd7070Spatrick Args.MakeArgString(TC.GetLinkerPath()),
345a9ac8606Spatrick CmdArgs, Inputs, Output));
346e5dd7070Spatrick }
347