106f32e7eSjoerg //===-- BareMetal.cpp - Bare Metal ToolChain --------------------*- C++ -*-===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg
906f32e7eSjoerg #include "BareMetal.h"
1006f32e7eSjoerg
1106f32e7eSjoerg #include "CommonArgs.h"
1206f32e7eSjoerg #include "InputInfo.h"
1306f32e7eSjoerg #include "Gnu.h"
1406f32e7eSjoerg
15*13fbcb42Sjoerg #include "Arch/RISCV.h"
1606f32e7eSjoerg #include "clang/Driver/Compilation.h"
1706f32e7eSjoerg #include "clang/Driver/Driver.h"
1806f32e7eSjoerg #include "clang/Driver/DriverDiagnostic.h"
1906f32e7eSjoerg #include "clang/Driver/Options.h"
2006f32e7eSjoerg #include "llvm/Option/ArgList.h"
2106f32e7eSjoerg #include "llvm/Support/Path.h"
2206f32e7eSjoerg #include "llvm/Support/VirtualFileSystem.h"
2306f32e7eSjoerg #include "llvm/Support/raw_ostream.h"
2406f32e7eSjoerg
2506f32e7eSjoerg using namespace llvm::opt;
2606f32e7eSjoerg using namespace clang;
2706f32e7eSjoerg using namespace clang::driver;
2806f32e7eSjoerg using namespace clang::driver::tools;
2906f32e7eSjoerg using namespace clang::driver::toolchains;
3006f32e7eSjoerg
makeMultilib(StringRef commonSuffix)31*13fbcb42Sjoerg static Multilib makeMultilib(StringRef commonSuffix) {
32*13fbcb42Sjoerg return Multilib(commonSuffix, commonSuffix, commonSuffix);
33*13fbcb42Sjoerg }
34*13fbcb42Sjoerg
findRISCVMultilibs(const Driver & D,const llvm::Triple & TargetTriple,const ArgList & Args,DetectedMultilibs & Result)35*13fbcb42Sjoerg static bool findRISCVMultilibs(const Driver &D,
36*13fbcb42Sjoerg const llvm::Triple &TargetTriple,
37*13fbcb42Sjoerg const ArgList &Args, DetectedMultilibs &Result) {
38*13fbcb42Sjoerg Multilib::flags_list Flags;
39*13fbcb42Sjoerg StringRef Arch = riscv::getRISCVArch(Args, TargetTriple);
40*13fbcb42Sjoerg StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple);
41*13fbcb42Sjoerg
42*13fbcb42Sjoerg if (TargetTriple.getArch() == llvm::Triple::riscv64) {
43*13fbcb42Sjoerg Multilib Imac = makeMultilib("").flag("+march=rv64imac").flag("+mabi=lp64");
44*13fbcb42Sjoerg Multilib Imafdc = makeMultilib("/rv64imafdc/lp64d")
45*13fbcb42Sjoerg .flag("+march=rv64imafdc")
46*13fbcb42Sjoerg .flag("+mabi=lp64d");
47*13fbcb42Sjoerg
48*13fbcb42Sjoerg // Multilib reuse
49*13fbcb42Sjoerg bool UseImafdc =
50*13fbcb42Sjoerg (Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc
51*13fbcb42Sjoerg
52*13fbcb42Sjoerg addMultilibFlag((Arch == "rv64imac"), "march=rv64imac", Flags);
53*13fbcb42Sjoerg addMultilibFlag(UseImafdc, "march=rv64imafdc", Flags);
54*13fbcb42Sjoerg addMultilibFlag(Abi == "lp64", "mabi=lp64", Flags);
55*13fbcb42Sjoerg addMultilibFlag(Abi == "lp64d", "mabi=lp64d", Flags);
56*13fbcb42Sjoerg
57*13fbcb42Sjoerg Result.Multilibs = MultilibSet().Either(Imac, Imafdc);
58*13fbcb42Sjoerg return Result.Multilibs.select(Flags, Result.SelectedMultilib);
59*13fbcb42Sjoerg }
60*13fbcb42Sjoerg if (TargetTriple.getArch() == llvm::Triple::riscv32) {
61*13fbcb42Sjoerg Multilib Imac =
62*13fbcb42Sjoerg makeMultilib("").flag("+march=rv32imac").flag("+mabi=ilp32");
63*13fbcb42Sjoerg Multilib I =
64*13fbcb42Sjoerg makeMultilib("/rv32i/ilp32").flag("+march=rv32i").flag("+mabi=ilp32");
65*13fbcb42Sjoerg Multilib Im =
66*13fbcb42Sjoerg makeMultilib("/rv32im/ilp32").flag("+march=rv32im").flag("+mabi=ilp32");
67*13fbcb42Sjoerg Multilib Iac = makeMultilib("/rv32iac/ilp32")
68*13fbcb42Sjoerg .flag("+march=rv32iac")
69*13fbcb42Sjoerg .flag("+mabi=ilp32");
70*13fbcb42Sjoerg Multilib Imafc = makeMultilib("/rv32imafc/ilp32f")
71*13fbcb42Sjoerg .flag("+march=rv32imafc")
72*13fbcb42Sjoerg .flag("+mabi=ilp32f");
73*13fbcb42Sjoerg
74*13fbcb42Sjoerg // Multilib reuse
75*13fbcb42Sjoerg bool UseI = (Arch == "rv32i") || (Arch == "rv32ic"); // ic => i
76*13fbcb42Sjoerg bool UseIm = (Arch == "rv32im") || (Arch == "rv32imc"); // imc => im
77*13fbcb42Sjoerg bool UseImafc = (Arch == "rv32imafc") || (Arch == "rv32imafdc") ||
78*13fbcb42Sjoerg (Arch == "rv32gc"); // imafdc,gc => imafc
79*13fbcb42Sjoerg
80*13fbcb42Sjoerg addMultilibFlag(UseI, "march=rv32i", Flags);
81*13fbcb42Sjoerg addMultilibFlag(UseIm, "march=rv32im", Flags);
82*13fbcb42Sjoerg addMultilibFlag((Arch == "rv32iac"), "march=rv32iac", Flags);
83*13fbcb42Sjoerg addMultilibFlag((Arch == "rv32imac"), "march=rv32imac", Flags);
84*13fbcb42Sjoerg addMultilibFlag(UseImafc, "march=rv32imafc", Flags);
85*13fbcb42Sjoerg addMultilibFlag(Abi == "ilp32", "mabi=ilp32", Flags);
86*13fbcb42Sjoerg addMultilibFlag(Abi == "ilp32f", "mabi=ilp32f", Flags);
87*13fbcb42Sjoerg
88*13fbcb42Sjoerg Result.Multilibs = MultilibSet().Either(I, Im, Iac, Imac, Imafc);
89*13fbcb42Sjoerg return Result.Multilibs.select(Flags, Result.SelectedMultilib);
90*13fbcb42Sjoerg }
91*13fbcb42Sjoerg return false;
92*13fbcb42Sjoerg }
93*13fbcb42Sjoerg
BareMetal(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)9406f32e7eSjoerg BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
9506f32e7eSjoerg const ArgList &Args)
9606f32e7eSjoerg : ToolChain(D, Triple, Args) {
9706f32e7eSjoerg getProgramPaths().push_back(getDriver().getInstalledDir());
9806f32e7eSjoerg if (getDriver().getInstalledDir() != getDriver().Dir)
9906f32e7eSjoerg getProgramPaths().push_back(getDriver().Dir);
10006f32e7eSjoerg
101*13fbcb42Sjoerg findMultilibs(D, Triple, Args);
102*13fbcb42Sjoerg SmallString<128> SysRoot(computeSysRoot());
103*13fbcb42Sjoerg if (!SysRoot.empty()) {
104*13fbcb42Sjoerg llvm::sys::path::append(SysRoot, "lib");
105*13fbcb42Sjoerg getFilePaths().push_back(std::string(SysRoot));
106*13fbcb42Sjoerg }
107*13fbcb42Sjoerg }
10806f32e7eSjoerg
10906f32e7eSjoerg /// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ?
isARMBareMetal(const llvm::Triple & Triple)11006f32e7eSjoerg static bool isARMBareMetal(const llvm::Triple &Triple) {
11106f32e7eSjoerg if (Triple.getArch() != llvm::Triple::arm &&
11206f32e7eSjoerg Triple.getArch() != llvm::Triple::thumb)
11306f32e7eSjoerg return false;
11406f32e7eSjoerg
11506f32e7eSjoerg if (Triple.getVendor() != llvm::Triple::UnknownVendor)
11606f32e7eSjoerg return false;
11706f32e7eSjoerg
11806f32e7eSjoerg if (Triple.getOS() != llvm::Triple::UnknownOS)
11906f32e7eSjoerg return false;
12006f32e7eSjoerg
12106f32e7eSjoerg if (Triple.getEnvironment() != llvm::Triple::EABI &&
12206f32e7eSjoerg Triple.getEnvironment() != llvm::Triple::EABIHF)
12306f32e7eSjoerg return false;
12406f32e7eSjoerg
12506f32e7eSjoerg return true;
12606f32e7eSjoerg }
12706f32e7eSjoerg
isRISCVBareMetal(const llvm::Triple & Triple)128*13fbcb42Sjoerg static bool isRISCVBareMetal(const llvm::Triple &Triple) {
129*13fbcb42Sjoerg if (Triple.getArch() != llvm::Triple::riscv32 &&
130*13fbcb42Sjoerg Triple.getArch() != llvm::Triple::riscv64)
131*13fbcb42Sjoerg return false;
132*13fbcb42Sjoerg
133*13fbcb42Sjoerg if (Triple.getVendor() != llvm::Triple::UnknownVendor)
134*13fbcb42Sjoerg return false;
135*13fbcb42Sjoerg
136*13fbcb42Sjoerg if (Triple.getOS() != llvm::Triple::UnknownOS)
137*13fbcb42Sjoerg return false;
138*13fbcb42Sjoerg
139*13fbcb42Sjoerg return Triple.getEnvironmentName() == "elf";
140*13fbcb42Sjoerg }
141*13fbcb42Sjoerg
findMultilibs(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)142*13fbcb42Sjoerg void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
143*13fbcb42Sjoerg const ArgList &Args) {
144*13fbcb42Sjoerg DetectedMultilibs Result;
145*13fbcb42Sjoerg if (isRISCVBareMetal(Triple)) {
146*13fbcb42Sjoerg if (findRISCVMultilibs(D, Triple, Args, Result)) {
147*13fbcb42Sjoerg SelectedMultilib = Result.SelectedMultilib;
148*13fbcb42Sjoerg Multilibs = Result.Multilibs;
149*13fbcb42Sjoerg }
150*13fbcb42Sjoerg }
151*13fbcb42Sjoerg }
152*13fbcb42Sjoerg
handlesTarget(const llvm::Triple & Triple)15306f32e7eSjoerg bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
154*13fbcb42Sjoerg return isARMBareMetal(Triple) || isRISCVBareMetal(Triple);
15506f32e7eSjoerg }
15606f32e7eSjoerg
buildLinker() const15706f32e7eSjoerg Tool *BareMetal::buildLinker() const {
15806f32e7eSjoerg return new tools::baremetal::Linker(*this);
15906f32e7eSjoerg }
16006f32e7eSjoerg
getCompilerRTPath() const161*13fbcb42Sjoerg std::string BareMetal::getCompilerRTPath() const { return getRuntimesDir(); }
162*13fbcb42Sjoerg
buildCompilerRTBasename(const llvm::opt::ArgList &,StringRef,FileType,bool) const163*13fbcb42Sjoerg std::string BareMetal::buildCompilerRTBasename(const llvm::opt::ArgList &,
164*13fbcb42Sjoerg StringRef, FileType,
165*13fbcb42Sjoerg bool) const {
166*13fbcb42Sjoerg return ("libclang_rt.builtins-" + getTriple().getArchName() + ".a").str();
167*13fbcb42Sjoerg }
168*13fbcb42Sjoerg
getRuntimesDir() const16906f32e7eSjoerg std::string BareMetal::getRuntimesDir() const {
17006f32e7eSjoerg SmallString<128> Dir(getDriver().ResourceDir);
17106f32e7eSjoerg llvm::sys::path::append(Dir, "lib", "baremetal");
172*13fbcb42Sjoerg Dir += SelectedMultilib.gccSuffix();
173*13fbcb42Sjoerg return std::string(Dir.str());
174*13fbcb42Sjoerg }
175*13fbcb42Sjoerg
computeSysRoot() const176*13fbcb42Sjoerg std::string BareMetal::computeSysRoot() const {
177*13fbcb42Sjoerg if (!getDriver().SysRoot.empty())
178*13fbcb42Sjoerg return getDriver().SysRoot + SelectedMultilib.osSuffix();
179*13fbcb42Sjoerg
180*13fbcb42Sjoerg SmallString<128> SysRootDir;
181*13fbcb42Sjoerg llvm::sys::path::append(SysRootDir, getDriver().Dir, "../lib/clang-runtimes",
182*13fbcb42Sjoerg getDriver().getTargetTriple());
183*13fbcb42Sjoerg
184*13fbcb42Sjoerg SysRootDir += SelectedMultilib.osSuffix();
185*13fbcb42Sjoerg return std::string(SysRootDir);
18606f32e7eSjoerg }
18706f32e7eSjoerg
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const18806f32e7eSjoerg void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
18906f32e7eSjoerg ArgStringList &CC1Args) const {
19006f32e7eSjoerg if (DriverArgs.hasArg(options::OPT_nostdinc))
19106f32e7eSjoerg return;
19206f32e7eSjoerg
19306f32e7eSjoerg if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
19406f32e7eSjoerg SmallString<128> Dir(getDriver().ResourceDir);
19506f32e7eSjoerg llvm::sys::path::append(Dir, "include");
19606f32e7eSjoerg addSystemInclude(DriverArgs, CC1Args, Dir.str());
19706f32e7eSjoerg }
19806f32e7eSjoerg
19906f32e7eSjoerg if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) {
200*13fbcb42Sjoerg SmallString<128> Dir(computeSysRoot());
201*13fbcb42Sjoerg if (!Dir.empty()) {
20206f32e7eSjoerg llvm::sys::path::append(Dir, "include");
20306f32e7eSjoerg addSystemInclude(DriverArgs, CC1Args, Dir.str());
20406f32e7eSjoerg }
20506f32e7eSjoerg }
206*13fbcb42Sjoerg }
20706f32e7eSjoerg
addClangTargetOptions(const ArgList & DriverArgs,ArgStringList & CC1Args,Action::OffloadKind) const20806f32e7eSjoerg void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
20906f32e7eSjoerg ArgStringList &CC1Args,
21006f32e7eSjoerg Action::OffloadKind) const {
21106f32e7eSjoerg CC1Args.push_back("-nostdsysteminc");
21206f32e7eSjoerg }
21306f32e7eSjoerg
AddClangCXXStdlibIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const21406f32e7eSjoerg void BareMetal::AddClangCXXStdlibIncludeArgs(
21506f32e7eSjoerg const ArgList &DriverArgs, ArgStringList &CC1Args) const {
21606f32e7eSjoerg if (DriverArgs.hasArg(options::OPT_nostdinc) ||
21706f32e7eSjoerg DriverArgs.hasArg(options::OPT_nostdlibinc) ||
21806f32e7eSjoerg DriverArgs.hasArg(options::OPT_nostdincxx))
21906f32e7eSjoerg return;
22006f32e7eSjoerg
221*13fbcb42Sjoerg std::string SysRoot(computeSysRoot());
22206f32e7eSjoerg if (SysRoot.empty())
22306f32e7eSjoerg return;
22406f32e7eSjoerg
22506f32e7eSjoerg switch (GetCXXStdlibType(DriverArgs)) {
22606f32e7eSjoerg case ToolChain::CST_Libcxx: {
22706f32e7eSjoerg SmallString<128> Dir(SysRoot);
22806f32e7eSjoerg llvm::sys::path::append(Dir, "include", "c++", "v1");
22906f32e7eSjoerg addSystemInclude(DriverArgs, CC1Args, Dir.str());
23006f32e7eSjoerg break;
23106f32e7eSjoerg }
23206f32e7eSjoerg case ToolChain::CST_Libstdcxx: {
23306f32e7eSjoerg SmallString<128> Dir(SysRoot);
23406f32e7eSjoerg llvm::sys::path::append(Dir, "include", "c++");
23506f32e7eSjoerg std::error_code EC;
23606f32e7eSjoerg Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
23706f32e7eSjoerg // Walk the subdirs, and find the one with the newest gcc version:
23806f32e7eSjoerg for (llvm::vfs::directory_iterator
23906f32e7eSjoerg LI = getDriver().getVFS().dir_begin(Dir.str(), EC),
24006f32e7eSjoerg LE;
24106f32e7eSjoerg !EC && LI != LE; LI = LI.increment(EC)) {
24206f32e7eSjoerg StringRef VersionText = llvm::sys::path::filename(LI->path());
24306f32e7eSjoerg auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
24406f32e7eSjoerg if (CandidateVersion.Major == -1)
24506f32e7eSjoerg continue;
24606f32e7eSjoerg if (CandidateVersion <= Version)
24706f32e7eSjoerg continue;
24806f32e7eSjoerg Version = CandidateVersion;
24906f32e7eSjoerg }
25006f32e7eSjoerg if (Version.Major == -1)
25106f32e7eSjoerg return;
25206f32e7eSjoerg llvm::sys::path::append(Dir, Version.Text);
25306f32e7eSjoerg addSystemInclude(DriverArgs, CC1Args, Dir.str());
25406f32e7eSjoerg break;
25506f32e7eSjoerg }
25606f32e7eSjoerg }
25706f32e7eSjoerg }
25806f32e7eSjoerg
AddCXXStdlibLibArgs(const ArgList & Args,ArgStringList & CmdArgs) const25906f32e7eSjoerg void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args,
26006f32e7eSjoerg ArgStringList &CmdArgs) const {
26106f32e7eSjoerg switch (GetCXXStdlibType(Args)) {
26206f32e7eSjoerg case ToolChain::CST_Libcxx:
26306f32e7eSjoerg CmdArgs.push_back("-lc++");
26406f32e7eSjoerg CmdArgs.push_back("-lc++abi");
26506f32e7eSjoerg break;
26606f32e7eSjoerg case ToolChain::CST_Libstdcxx:
26706f32e7eSjoerg CmdArgs.push_back("-lstdc++");
26806f32e7eSjoerg CmdArgs.push_back("-lsupc++");
26906f32e7eSjoerg break;
27006f32e7eSjoerg }
27106f32e7eSjoerg CmdArgs.push_back("-lunwind");
27206f32e7eSjoerg }
27306f32e7eSjoerg
AddLinkRuntimeLib(const ArgList & Args,ArgStringList & CmdArgs) const27406f32e7eSjoerg void BareMetal::AddLinkRuntimeLib(const ArgList &Args,
27506f32e7eSjoerg ArgStringList &CmdArgs) const {
276*13fbcb42Sjoerg ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args);
277*13fbcb42Sjoerg switch (RLT) {
278*13fbcb42Sjoerg case ToolChain::RLT_CompilerRT:
279*13fbcb42Sjoerg CmdArgs.push_back(
280*13fbcb42Sjoerg Args.MakeArgString("-lclang_rt.builtins-" + getTriple().getArchName()));
281*13fbcb42Sjoerg return;
282*13fbcb42Sjoerg case ToolChain::RLT_Libgcc:
283*13fbcb42Sjoerg CmdArgs.push_back("-lgcc");
284*13fbcb42Sjoerg return;
285*13fbcb42Sjoerg }
286*13fbcb42Sjoerg llvm_unreachable("Unhandled RuntimeLibType.");
28706f32e7eSjoerg }
28806f32e7eSjoerg
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const28906f32e7eSjoerg void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
29006f32e7eSjoerg const InputInfo &Output,
29106f32e7eSjoerg const InputInfoList &Inputs,
29206f32e7eSjoerg const ArgList &Args,
29306f32e7eSjoerg const char *LinkingOutput) const {
29406f32e7eSjoerg ArgStringList CmdArgs;
29506f32e7eSjoerg
29606f32e7eSjoerg auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain());
29706f32e7eSjoerg
29806f32e7eSjoerg AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
29906f32e7eSjoerg
30006f32e7eSjoerg CmdArgs.push_back("-Bstatic");
30106f32e7eSjoerg
30206f32e7eSjoerg Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
30306f32e7eSjoerg options::OPT_e, options::OPT_s, options::OPT_t,
30406f32e7eSjoerg options::OPT_Z_Flag, options::OPT_r});
30506f32e7eSjoerg
306*13fbcb42Sjoerg TC.AddFilePathLibArgs(Args, CmdArgs);
307*13fbcb42Sjoerg
308*13fbcb42Sjoerg CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir()));
309*13fbcb42Sjoerg
31006f32e7eSjoerg if (TC.ShouldLinkCXXStdlib(Args))
31106f32e7eSjoerg TC.AddCXXStdlibLibArgs(Args, CmdArgs);
31206f32e7eSjoerg if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
31306f32e7eSjoerg CmdArgs.push_back("-lc");
31406f32e7eSjoerg CmdArgs.push_back("-lm");
31506f32e7eSjoerg
31606f32e7eSjoerg TC.AddLinkRuntimeLib(Args, CmdArgs);
31706f32e7eSjoerg }
31806f32e7eSjoerg
31906f32e7eSjoerg CmdArgs.push_back("-o");
32006f32e7eSjoerg CmdArgs.push_back(Output.getFilename());
32106f32e7eSjoerg
322*13fbcb42Sjoerg C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
32306f32e7eSjoerg Args.MakeArgString(TC.GetLinkerPath()),
324*13fbcb42Sjoerg CmdArgs, Inputs, Output));
32506f32e7eSjoerg }
326