Skip to content

Commit b74795d

Browse files
committed
[RISCV] 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
1 parent 3740fac commit b74795d

12 files changed

+316
-113
lines changed

clang/lib/Driver/Driver.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6521,11 +6521,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
65216521
break;
65226522
case llvm::Triple::riscv32:
65236523
case llvm::Triple::riscv64:
6524-
if (toolchains::RISCVToolChain::hasGCCToolchain(*this, Args))
6525-
TC =
6526-
std::make_unique<toolchains::RISCVToolChain>(*this, Target, Args);
6527-
else
6528-
TC = std::make_unique<toolchains::BareMetal>(*this, Target, Args);
6524+
TC = std::make_unique<toolchains::BareMetal>(*this, Target, Args);
65296525
break;
65306526
case llvm::Triple::ve:
65316527
TC = std::make_unique<toolchains::VEToolChain>(*this, Target, Args);

clang/lib/Driver/ToolChains/BareMetal.cpp

Lines changed: 190 additions & 36 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
}
@@ -236,7 +312,7 @@ getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple,
236312
return {};
237313
}
238314
} else {
239-
MultilibPath = computeBaseSysRoot(D, /*IncludeTriple=*/false);
315+
MultilibPath = computeInstalledToolchainSysRoot(D, /*IncludeTriple=*/false);
240316
llvm::sys::path::append(MultilibPath, MultilibFilename);
241317
}
242318
return MultilibPath;
@@ -254,7 +330,7 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
254330
if (D.getVFS().exists(*MultilibPath)) {
255331
// If multilib.yaml is found, update sysroot so it doesn't use a target
256332
// specific suffix
257-
SysRoot = computeBaseSysRoot(D, /*IncludeTriple=*/false);
333+
SysRoot = computeInstalledToolchainSysRoot(D, /*IncludeTriple=*/false);
258334
findMultilibsFromYAML(*this, D, *MultilibPath, Args, Result);
259335
SelectedMultilibs = Result.SelectedMultilibs;
260336
Multilibs = Result.Multilibs;
@@ -279,8 +355,6 @@ Tool *BareMetal::buildStaticLibTool() const {
279355
return new tools::baremetal::StaticLibTool(*this);
280356
}
281357

282-
std::string BareMetal::computeSysRoot() const { return SysRoot; }
283-
284358
BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const {
285359
// Get multilibs in reverse order because they're ordered most-specific last.
286360
if (!SelectedMultilibs.empty())
@@ -291,6 +365,36 @@ BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const {
291365
return llvm::reverse(Default);
292366
}
293367

368+
ToolChain::CXXStdlibType BareMetal::GetDefaultCXXStdlibType() const {
369+
if (getTriple().isRISCV()) {
370+
return GCCInstallation.isValid() ? ToolChain::CST_Libstdcxx
371+
: ToolChain::CST_Libcxx;
372+
}
373+
return ToolChain::CST_Libcxx;
374+
}
375+
376+
ToolChain::RuntimeLibType BareMetal::GetDefaultRuntimeLibType() const {
377+
if (getTriple().isRISCV()) {
378+
return GCCInstallation.isValid() ? ToolChain::RLT_Libgcc
379+
: ToolChain::RLT_CompilerRT;
380+
}
381+
return ToolChain::RLT_CompilerRT;
382+
}
383+
384+
ToolChain::UnwindLibType
385+
BareMetal::GetUnwindLibType(const llvm::opt::ArgList &Args) const {
386+
if (getTriple().isRISCV())
387+
return ToolChain::UNW_None;
388+
389+
return ToolChain::GetUnwindLibType(Args);
390+
}
391+
392+
const char *BareMetal::getDefaultLinker() const {
393+
if (isUsingLD())
394+
return "ld";
395+
return "ld.lld";
396+
}
397+
294398
void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
295399
ArgStringList &CC1Args) const {
296400
if (DriverArgs.hasArg(options::OPT_nostdinc))
@@ -325,6 +429,19 @@ void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
325429
CC1Args.push_back("-nostdsysteminc");
326430
}
327431

432+
void BareMetal::addLibStdCxxIncludePaths(
433+
const llvm::opt::ArgList &DriverArgs,
434+
llvm::opt::ArgStringList &CC1Args) const {
435+
if (GCCInstallation.isValid()) {
436+
const GCCVersion &Version = GCCInstallation.getVersion();
437+
StringRef TripleStr = GCCInstallation.getTriple().str();
438+
const Multilib &Multilib = GCCInstallation.getMultilib();
439+
addLibStdCXXIncludePaths(computeSysRoot() + "/include/c++/" + Version.Text,
440+
TripleStr, Multilib.includeSuffix(), DriverArgs,
441+
CC1Args);
442+
}
443+
}
444+
328445
void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
329446
ArgStringList &CC1Args) const {
330447
if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
@@ -355,15 +472,15 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
355472
};
356473

357474
switch (GetCXXStdlibType(DriverArgs)) {
358-
case ToolChain::CST_Libcxx: {
359-
SmallString<128> P(D.Dir);
360-
llvm::sys::path::append(P, "..", "include");
361-
AddCXXIncludePath(P);
362-
break;
363-
}
364-
case ToolChain::CST_Libstdcxx:
365-
// We only support libc++ toolchain installation.
366-
break;
475+
case ToolChain::CST_Libcxx: {
476+
SmallString<128> P(D.Dir);
477+
llvm::sys::path::append(P, "..", "include");
478+
AddCXXIncludePath(P);
479+
break;
480+
}
481+
case ToolChain::CST_Libstdcxx:
482+
addLibStdCxxIncludePaths(DriverArgs, CC1Args);
483+
break;
367484
}
368485

369486
std::string SysRoot(computeSysRoot());
@@ -428,6 +545,10 @@ void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args,
428545
CmdArgs.push_back("-lsupc++");
429546
break;
430547
}
548+
549+
if (getTriple().isRISCV() && GCCInstallation.isValid())
550+
return;
551+
431552
CmdArgs.push_back("-lunwind");
432553
}
433554

@@ -503,12 +624,22 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
503624
const llvm::Triple::ArchType Arch = TC.getArch();
504625
const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
505626

506-
AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
627+
if (!D.SysRoot.empty())
628+
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
507629

630+
Args.addAllArgs(CmdArgs, {options::OPT_u});
508631
CmdArgs.push_back("-Bstatic");
509632

510-
if (TC.getTriple().isRISCV() && Args.hasArg(options::OPT_mno_relax))
511-
CmdArgs.push_back("--no-relax");
633+
if (TC.getTriple().isRISCV()) {
634+
if (Args.hasArg(options::OPT_mno_relax))
635+
CmdArgs.push_back("--no-relax");
636+
if (TC.isUsingLD()) {
637+
CmdArgs.push_back("-m");
638+
CmdArgs.push_back(TC.getArch() == llvm::Triple::riscv64 ? "elf64lriscv"
639+
: "elf32lriscv");
640+
}
641+
CmdArgs.push_back("-X");
642+
}
512643

513644
if (Triple.isARM() || Triple.isThumb()) {
514645
bool IsBigEndian = arm::isARMBigEndian(Triple, Args);
@@ -519,9 +650,24 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
519650
CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL");
520651
}
521652

522-
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
523-
options::OPT_r)) {
524-
CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt0.o")));
653+
bool WantCRTs =
654+
!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles);
655+
656+
const char *crtbegin, *crtend;
657+
if (WantCRTs) {
658+
if (!Args.hasArg(options::OPT_r))
659+
CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt0.o")));
660+
auto RuntimeLib = TC.GetRuntimeLibType(Args);
661+
if (RuntimeLib == ToolChain::RLT_Libgcc) {
662+
crtbegin = "crtbegin.o";
663+
crtend = "crtend.o";
664+
} else {
665+
assert(RuntimeLib == ToolChain::RLT_CompilerRT);
666+
crtbegin =
667+
TC.getCompilerRTArgString(Args, "crtbegin", ToolChain::FT_Object);
668+
crtend = TC.getCompilerRTArgString(Args, "crtend", ToolChain::FT_Object);
669+
}
670+
CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(crtbegin)));
525671
}
526672

527673
Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
@@ -536,12 +682,20 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
536682
TC.AddCXXStdlibLibArgs(Args, CmdArgs);
537683

538684
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
539-
CmdArgs.push_back("-lc");
540685
CmdArgs.push_back("-lm");
541-
686+
if (TC.isUsingLD())
687+
CmdArgs.push_back("--start-group");
688+
CmdArgs.push_back("-lc");
689+
if (TC.isUsingLD()) {
690+
CmdArgs.push_back("-lgloss");
691+
CmdArgs.push_back("--end-group");
692+
}
542693
TC.AddLinkRuntimeLib(Args, CmdArgs);
543694
}
544695

696+
if (WantCRTs)
697+
CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(crtend)));
698+
545699
if (D.isUsingLTO()) {
546700
assert(!Inputs.empty() && "Must have at least one input.");
547701
// Find the first filename InputInfo object.
@@ -555,8 +709,8 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
555709
addLTOOptions(TC, Args, CmdArgs, Output, *Input,
556710
D.getLTOMode() == LTOK_Thin);
557711
}
558-
if (TC.getTriple().isRISCV())
559-
CmdArgs.push_back("-X");
712+
713+
AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
560714

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

0 commit comments

Comments
 (0)