Skip to content

Commit b58f9dd

Browse files
committed
[WIP] Merging RISCVToolChain and BareMetal toolchains
Currently, LLVM has two RISC-V toolchain classes in Clang for baremetal development, creating unnecessary maintenance overhead. This patch extends the BareMetal toolchain to support an existing GCC installation, resolving this issue. The latest patchset preserves the behavior of both toolchain objects with minor differences. If no --sysroot option is passed on the command line or if the GCC installation is invalid, the sysroot will first be formed as per the RISCVToolChain baremetal object. If this path does not exist, the sysroot will be formed as per the BareMetal toolchain object. Additionally, the presence of --gcc-toolchain or --gcc-install-dir will imply that GNU linker is the default linker unless otherwise a differnt linker is passed through `-fuse-ld` flag. RFC - https://discourse.llvm.org/t/merging-riscvtoolchain-and-baremetal-toolchains/75524 change-Id: Ie2cdefd3c95b25770a33319ce2e711c9300efc2e
1 parent 6ce6b1d commit b58f9dd

15 files changed

+298
-436
lines changed

clang/lib/Driver/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ add_clang_library(clangDriver
7474
ToolChains/OHOS.cpp
7575
ToolChains/OpenBSD.cpp
7676
ToolChains/PS4CPU.cpp
77-
ToolChains/RISCVToolchain.cpp
7877
ToolChains/Solaris.cpp
7978
ToolChains/SPIRV.cpp
8079
ToolChains/TCE.cpp

clang/lib/Driver/Driver.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
#include "ToolChains/PPCFreeBSD.h"
4242
#include "ToolChains/PPCLinux.h"
4343
#include "ToolChains/PS4CPU.h"
44-
#include "ToolChains/RISCVToolchain.h"
4544
#include "ToolChains/SPIRV.h"
4645
#include "ToolChains/Solaris.h"
4746
#include "ToolChains/TCE.h"
@@ -6557,11 +6556,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
65576556
break;
65586557
case llvm::Triple::riscv32:
65596558
case llvm::Triple::riscv64:
6560-
if (toolchains::RISCVToolChain::hasGCCToolchain(*this, Args))
6561-
TC =
6562-
std::make_unique<toolchains::RISCVToolChain>(*this, Target, Args);
6563-
else
6564-
TC = std::make_unique<toolchains::BareMetal>(*this, Target, Args);
6559+
TC = std::make_unique<toolchains::BareMetal>(*this, Target, Args);
65656560
break;
65666561
case llvm::Triple::ve:
65676562
TC = std::make_unique<toolchains::VEToolChain>(*this, Target, Args);

clang/lib/Driver/ToolChains/BareMetal.cpp

Lines changed: 197 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ static bool findRISCVMultilibs(const Driver &D,
9797
return false;
9898
}
9999

100-
static std::string computeBaseSysRoot(const Driver &D, bool IncludeTriple) {
100+
static std::string computeInstalledToolchainSysRoot(const Driver &D,
101+
bool IncludeTriple) {
101102
if (!D.SysRoot.empty())
102103
return D.SysRoot;
103104

@@ -110,20 +111,95 @@ static std::string computeBaseSysRoot(const Driver &D, bool IncludeTriple) {
110111
return std::string(SysRootDir);
111112
}
112113

114+
// GCC sysroot here means form sysroot from either --gcc-install-dir, or from
115+
// --gcc-toolchain or if the toolchain is installed alongside clang in
116+
// bin/../<TargetTriple> directory if it is not explicitly specified on the
117+
// command line through `--sysroot` option. libc here will be newlib.
118+
std::string BareMetal::computeGCCSysRoot() const {
119+
if (!getDriver().SysRoot.empty())
120+
return getDriver().SysRoot;
121+
122+
SmallString<128> SysRootDir;
123+
if (GCCInstallation.isValid()) {
124+
StringRef LibDir = GCCInstallation.getParentLibPath();
125+
StringRef TripleStr = GCCInstallation.getTriple().str();
126+
llvm::sys::path::append(SysRootDir, LibDir, "..", TripleStr);
127+
} else {
128+
// Use the triple as provided to the driver. Unlike the parsed triple
129+
// this has not been normalized to always contain every field.
130+
llvm::sys::path::append(SysRootDir, getDriver().Dir, "..",
131+
getDriver().getTargetTriple());
132+
}
133+
134+
if (!llvm::sys::fs::exists(SysRootDir))
135+
return std::string();
136+
137+
return std::string(SysRootDir);
138+
}
139+
140+
std::string BareMetal::computeSysRoot() const {
141+
if (!SysRoot.empty())
142+
return SysRoot;
143+
144+
std::string SysRoot = getDriver().SysRoot;
145+
if (!SysRoot.empty() && llvm::sys::fs::exists(SysRoot))
146+
return SysRoot;
147+
148+
// Verify the GCC installation from -gcc-install-dir, --gcc-toolchain, or
149+
// alongside clang. If valid, form the sysroot. Otherwise, check
150+
// lib/clang-runtimes above the driver.
151+
SysRoot = computeGCCSysRoot();
152+
if (!SysRoot.empty())
153+
return SysRoot;
154+
155+
SysRoot =
156+
computeInstalledToolchainSysRoot(getDriver(), /*IncludeTriple*/ true);
157+
158+
return SysRoot;
159+
}
160+
161+
static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs,
162+
const Multilib &Multilib,
163+
StringRef InstallPath,
164+
ToolChain::path_list &Paths) {
165+
if (const auto &PathsCallback = Multilibs.filePathsCallback())
166+
for (const auto &Path : PathsCallback(Multilib))
167+
addPathIfExists(D, InstallPath + Path, Paths);
168+
}
169+
113170
BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
114171
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));
172+
: Generic_ELF(D, Triple, Args) {
173+
GCCInstallation.init(Triple, Args);
174+
SysRoot = computeSysRoot();
175+
UseLD =
176+
Args.getLastArgValue(options::OPT_fuse_ld_EQ).equals_insensitive("ld");
177+
if (GCCInstallation.isValid()) {
178+
Multilibs = GCCInstallation.getMultilibs();
179+
SelectedMultilibs.assign({GCCInstallation.getMultilib()});
180+
path_list &Paths = getFilePaths();
181+
// Add toolchain/multilib specific file paths.
182+
addMultilibsFilePaths(D, Multilibs, SelectedMultilibs.back(),
183+
GCCInstallation.getInstallPath(), Paths);
184+
getFilePaths().push_back(GCCInstallation.getInstallPath().str());
185+
ToolChain::path_list &PPaths = getProgramPaths();
186+
// Multilib cross-compiler GCC installations put ld in a triple-prefixed
187+
// directory off of the parent of the GCC installation.
188+
PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" +
189+
GCCInstallation.getTriple().str() + "/bin")
190+
.str());
191+
PPaths.push_back((GCCInstallation.getParentLibPath() + "/../bin").str());
192+
getFilePaths().push_back(computeSysRoot() + "/lib");
193+
} else {
194+
getProgramPaths().push_back(getDriver().Dir);
195+
findMultilibs(D, Triple, Args);
196+
if (!SysRoot.empty()) {
197+
for (const Multilib &M : getOrderedMultilibs()) {
198+
SmallString<128> Dir(SysRoot);
199+
llvm::sys::path::append(Dir, M.osSuffix(), "lib");
200+
getFilePaths().push_back(std::string(Dir));
201+
getLibraryPaths().push_back(std::string(Dir));
202+
}
127203
}
128204
}
129205
}
@@ -215,7 +291,7 @@ getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple,
215291
return {};
216292
}
217293
} else {
218-
MultilibPath = computeBaseSysRoot(D, /*IncludeTriple=*/false);
294+
MultilibPath = computeInstalledToolchainSysRoot(D, /*IncludeTriple=*/false);
219295
llvm::sys::path::append(MultilibPath, MultilibFilename);
220296
}
221297
return MultilibPath;
@@ -233,7 +309,7 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
233309
if (D.getVFS().exists(*MultilibPath)) {
234310
// If multilib.yaml is found, update sysroot so it doesn't use a target
235311
// specific suffix
236-
SysRoot = computeBaseSysRoot(D, /*IncludeTriple=*/false);
312+
SysRoot = computeInstalledToolchainSysRoot(D, /*IncludeTriple=*/false);
237313
findMultilibsFromYAML(*this, D, *MultilibPath, Args, Result);
238314
SelectedMultilibs = Result.SelectedMultilibs;
239315
Multilibs = Result.Multilibs;
@@ -258,8 +334,6 @@ Tool *BareMetal::buildStaticLibTool() const {
258334
return new tools::baremetal::StaticLibTool(*this);
259335
}
260336

261-
std::string BareMetal::computeSysRoot() const { return SysRoot; }
262-
263337
BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const {
264338
// Get multilibs in reverse order because they're ordered most-specific last.
265339
if (!SelectedMultilibs.empty())
@@ -270,6 +344,32 @@ BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const {
270344
return llvm::reverse(Default);
271345
}
272346

347+
ToolChain::CXXStdlibType BareMetal::GetDefaultCXXStdlibType() const {
348+
if (getTriple().isRISCV() && GCCInstallation.isValid())
349+
return ToolChain::CST_Libstdcxx;
350+
return ToolChain::CST_Libcxx;
351+
}
352+
353+
ToolChain::RuntimeLibType BareMetal::GetDefaultRuntimeLibType() const {
354+
if (getTriple().isRISCV() && GCCInstallation.isValid())
355+
return ToolChain::RLT_Libgcc;
356+
return ToolChain::RLT_CompilerRT;
357+
}
358+
359+
ToolChain::UnwindLibType
360+
BareMetal::GetUnwindLibType(const llvm::opt::ArgList &Args) const {
361+
if (getTriple().isRISCV())
362+
return ToolChain::UNW_None;
363+
364+
return ToolChain::GetUnwindLibType(Args);
365+
}
366+
367+
const char *BareMetal::getDefaultLinker() const {
368+
if (isUsingLD())
369+
return "ld";
370+
return "ld.lld";
371+
}
372+
273373
void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
274374
ArgStringList &CC1Args) const {
275375
if (DriverArgs.hasArg(options::OPT_nostdinc))
@@ -304,6 +404,19 @@ void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
304404
CC1Args.push_back("-nostdsysteminc");
305405
}
306406

407+
void BareMetal::addLibStdCxxIncludePaths(
408+
const llvm::opt::ArgList &DriverArgs,
409+
llvm::opt::ArgStringList &CC1Args) const {
410+
if (!GCCInstallation.isValid())
411+
return;
412+
const GCCVersion &Version = GCCInstallation.getVersion();
413+
StringRef TripleStr = GCCInstallation.getTriple().str();
414+
const Multilib &Multilib = GCCInstallation.getMultilib();
415+
addLibStdCXXIncludePaths(computeSysRoot() + "/include/c++/" + Version.Text,
416+
TripleStr, Multilib.includeSuffix(), DriverArgs,
417+
CC1Args);
418+
}
419+
307420
void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
308421
ArgStringList &CC1Args) const {
309422
if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
@@ -334,15 +447,15 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
334447
};
335448

336449
switch (GetCXXStdlibType(DriverArgs)) {
337-
case ToolChain::CST_Libcxx: {
338-
SmallString<128> P(D.Dir);
339-
llvm::sys::path::append(P, "..", "include");
340-
AddCXXIncludePath(P);
341-
break;
342-
}
343-
case ToolChain::CST_Libstdcxx:
344-
// We only support libc++ toolchain installation.
345-
break;
450+
case ToolChain::CST_Libcxx: {
451+
SmallString<128> P(D.Dir);
452+
llvm::sys::path::append(P, "..", "include");
453+
AddCXXIncludePath(P);
454+
break;
455+
}
456+
case ToolChain::CST_Libstdcxx:
457+
addLibStdCxxIncludePaths(DriverArgs, CC1Args);
458+
break;
346459
}
347460

348461
std::string SysRoot(computeSysRoot());
@@ -450,12 +563,21 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
450563
const llvm::Triple::ArchType Arch = TC.getArch();
451564
const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
452565

453-
AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
566+
if (!D.SysRoot.empty())
567+
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
454568

455569
CmdArgs.push_back("-Bstatic");
456570

457-
if (TC.getTriple().isRISCV() && Args.hasArg(options::OPT_mno_relax))
458-
CmdArgs.push_back("--no-relax");
571+
if (Triple.isRISCV()) {
572+
if (Args.hasArg(options::OPT_mno_relax))
573+
CmdArgs.push_back("--no-relax");
574+
if (TC.isUsingLD()) {
575+
CmdArgs.push_back("-m");
576+
CmdArgs.push_back(Arch == llvm::Triple::riscv64 ? "elf64lriscv"
577+
: "elf32lriscv");
578+
}
579+
CmdArgs.push_back("-X");
580+
}
459581

460582
if (Triple.isARM() || Triple.isThumb()) {
461583
bool IsBigEndian = arm::isARMBigEndian(Triple, Args);
@@ -466,19 +588,54 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
466588
CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL");
467589
}
468590

469-
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
470-
options::OPT_r)) {
471-
CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt0.o")));
591+
bool WantCRTs =
592+
!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles);
593+
594+
const char *crtbegin, *crtend;
595+
if (WantCRTs) {
596+
if (!Args.hasArg(options::OPT_r))
597+
CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt0.o")));
598+
if (TC.isUsingLD()) {
599+
auto RuntimeLib = TC.GetRuntimeLibType(Args);
600+
if (RuntimeLib == ToolChain::RLT_Libgcc) {
601+
crtbegin = "crtbegin.o";
602+
crtend = "crtend.o";
603+
} else {
604+
assert(RuntimeLib == ToolChain::RLT_CompilerRT);
605+
crtbegin =
606+
TC.getCompilerRTArgString(Args, "crtbegin", ToolChain::FT_Object);
607+
crtend =
608+
TC.getCompilerRTArgString(Args, "crtend", ToolChain::FT_Object);
609+
}
610+
CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(crtbegin)));
611+
}
472612
}
473613

474-
Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
475-
options::OPT_s, options::OPT_t, options::OPT_r});
614+
Args.addAllArgs(CmdArgs,
615+
{options::OPT_L, options::OPT_u, options::OPT_T_Group,
616+
options::OPT_s, options::OPT_t, options::OPT_r});
476617

477618
TC.AddFilePathLibArgs(Args, CmdArgs);
478619

479620
for (const auto &LibPath : TC.getLibraryPaths())
480621
CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-L", LibPath)));
481622

623+
if (D.isUsingLTO()) {
624+
assert(!Inputs.empty() && "Must have at least one input.");
625+
// Find the first filename InputInfo object.
626+
auto Input = llvm::find_if(
627+
Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); });
628+
if (Input == Inputs.end())
629+
// For a very rare case, all of the inputs to the linker are
630+
// InputArg. If that happens, just use the first InputInfo.
631+
Input = Inputs.begin();
632+
633+
addLTOOptions(TC, Args, CmdArgs, Output, *Input,
634+
D.getLTOMode() == LTOK_Thin);
635+
}
636+
637+
AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
638+
482639
if (TC.ShouldLinkCXXStdlib(Args)) {
483640
bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
484641
!Args.hasArg(options::OPT_static);
@@ -491,26 +648,16 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
491648
}
492649

493650
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
651+
CmdArgs.push_back("--start-group");
494652
AddRunTimeLibs(TC, D, CmdArgs, Args);
495-
496653
CmdArgs.push_back("-lc");
654+
if (TC.isUsingLD())
655+
CmdArgs.push_back("-lgloss");
656+
CmdArgs.push_back("--end-group");
497657
}
498658

499-
if (D.isUsingLTO()) {
500-
assert(!Inputs.empty() && "Must have at least one input.");
501-
// Find the first filename InputInfo object.
502-
auto Input = llvm::find_if(
503-
Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); });
504-
if (Input == Inputs.end())
505-
// For a very rare case, all of the inputs to the linker are
506-
// InputArg. If that happens, just use the first InputInfo.
507-
Input = Inputs.begin();
508-
509-
addLTOOptions(TC, Args, CmdArgs, Output, *Input,
510-
D.getLTOMode() == LTOK_Thin);
511-
}
512-
if (TC.getTriple().isRISCV())
513-
CmdArgs.push_back("-X");
659+
if (TC.isUsingLD() && WantCRTs)
660+
CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(crtend)));
514661

515662
// The R_ARM_TARGET2 relocation must be treated as R_ARM_REL32 on arm*-*-elf
516663
// and arm*-*-eabi (the default is R_ARM_GOT_PREL, used on arm*-*-linux and

0 commit comments

Comments
 (0)