Skip to content

Commit b1bd1ee

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 b1bd1ee

12 files changed

+314
-112
lines changed

clang/lib/Driver/Driver.cpp

-4
Original file line numberDiff line numberDiff line change
@@ -6521,10 +6521,6 @@ 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
65286524
TC = std::make_unique<toolchains::BareMetal>(*this, Target, Args);
65296525
break;
65306526
case llvm::Triple::ve:

clang/lib/Driver/ToolChains/BareMetal.cpp

+189-36
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,94 @@ 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 command
117+
// 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 = Args.getLastArgValue(options::OPT_fuse_ld_EQ).equals_insensitive("ld");
176+
if (GCCInstallation.isValid()) {
177+
Multilibs = GCCInstallation.getMultilibs();
178+
SelectedMultilibs.assign({GCCInstallation.getMultilib()});
179+
path_list &Paths = getFilePaths();
180+
// Add toolchain/multilib specific file paths.
181+
addMultilibsFilePaths(D, Multilibs, SelectedMultilibs.back(),
182+
GCCInstallation.getInstallPath(), Paths);
183+
getFilePaths().push_back(GCCInstallation.getInstallPath().str());
184+
ToolChain::path_list &PPaths = getProgramPaths();
185+
// Multilib cross-compiler GCC installations put ld in a triple-prefixed
186+
// directory off of the parent of the GCC installation.
187+
PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" +
188+
GCCInstallation.getTriple().str() + "/bin")
189+
.str());
190+
PPaths.push_back((GCCInstallation.getParentLibPath() + "/../bin").str());
191+
getFilePaths().push_back(computeSysRoot() + "/lib");
192+
} else {
193+
getProgramPaths().push_back(getDriver().Dir);
194+
findMultilibs(D, Triple, Args);
195+
if (!SysRoot.empty()) {
196+
for (const Multilib &M : getOrderedMultilibs()) {
197+
SmallString<128> Dir(SysRoot);
198+
llvm::sys::path::append(Dir, M.osSuffix(), "lib");
199+
getFilePaths().push_back(std::string(Dir));
200+
getLibraryPaths().push_back(std::string(Dir));
201+
}
127202
}
128203
}
129204
}
@@ -236,7 +311,7 @@ getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple,
236311
return {};
237312
}
238313
} else {
239-
MultilibPath = computeBaseSysRoot(D, /*IncludeTriple=*/false);
314+
MultilibPath = computeInstalledToolchainSysRoot(D, /*IncludeTriple=*/false);
240315
llvm::sys::path::append(MultilibPath, MultilibFilename);
241316
}
242317
return MultilibPath;
@@ -254,7 +329,7 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
254329
if (D.getVFS().exists(*MultilibPath)) {
255330
// If multilib.yaml is found, update sysroot so it doesn't use a target
256331
// specific suffix
257-
SysRoot = computeBaseSysRoot(D, /*IncludeTriple=*/false);
332+
SysRoot = computeInstalledToolchainSysRoot(D, /*IncludeTriple=*/false);
258333
findMultilibsFromYAML(*this, D, *MultilibPath, Args, Result);
259334
SelectedMultilibs = Result.SelectedMultilibs;
260335
Multilibs = Result.Multilibs;
@@ -279,8 +354,6 @@ Tool *BareMetal::buildStaticLibTool() const {
279354
return new tools::baremetal::StaticLibTool(*this);
280355
}
281356

282-
std::string BareMetal::computeSysRoot() const { return SysRoot; }
283-
284357
BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const {
285358
// Get multilibs in reverse order because they're ordered most-specific last.
286359
if (!SelectedMultilibs.empty())
@@ -291,6 +364,36 @@ BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const {
291364
return llvm::reverse(Default);
292365
}
293366

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

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

357473
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;
474+
case ToolChain::CST_Libcxx: {
475+
SmallString<128> P(D.Dir);
476+
llvm::sys::path::append(P, "..", "include");
477+
AddCXXIncludePath(P);
478+
break;
479+
}
480+
case ToolChain::CST_Libstdcxx:
481+
addLibStdCxxIncludePaths(DriverArgs, CC1Args);
482+
break;
367483
}
368484

369485
std::string SysRoot(computeSysRoot());
@@ -428,6 +544,10 @@ void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args,
428544
CmdArgs.push_back("-lsupc++");
429545
break;
430546
}
547+
548+
if (getTriple().isRISCV() && GCCInstallation.isValid())
549+
return;
550+
431551
CmdArgs.push_back("-lunwind");
432552
}
433553

@@ -503,12 +623,22 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
503623
const llvm::Triple::ArchType Arch = TC.getArch();
504624
const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
505625

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

629+
Args.addAllArgs(CmdArgs, {options::OPT_u});
508630
CmdArgs.push_back("-Bstatic");
509631

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

513643
if (Triple.isARM() || Triple.isThumb()) {
514644
bool IsBigEndian = arm::isARMBigEndian(Triple, Args);
@@ -519,9 +649,24 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
519649
CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL");
520650
}
521651

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

527672
Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
@@ -536,12 +681,20 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
536681
TC.AddCXXStdlibLibArgs(Args, CmdArgs);
537682

538683
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
539-
CmdArgs.push_back("-lc");
540684
CmdArgs.push_back("-lm");
541-
685+
if (TC.isUsingLD())
686+
CmdArgs.push_back("--start-group");
687+
CmdArgs.push_back("-lc");
688+
if (TC.isUsingLD()) {
689+
CmdArgs.push_back("-lgloss");
690+
CmdArgs.push_back("--end-group");
691+
}
542692
TC.AddLinkRuntimeLib(Args, CmdArgs);
543693
}
544694

695+
if (WantCRTs)
696+
CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(crtend)));
697+
545698
if (D.isUsingLTO()) {
546699
assert(!Inputs.empty() && "Must have at least one input.");
547700
// Find the first filename InputInfo object.
@@ -555,8 +708,8 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
555708
addLTOOptions(TC, Args, CmdArgs, Output, *Input,
556709
D.getLTOMode() == LTOK_Thin);
557710
}
558-
if (TC.getTriple().isRISCV())
559-
CmdArgs.push_back("-X");
711+
712+
AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
560713

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

0 commit comments

Comments
 (0)