1e5dd7070Spatrick //===--- RISCVToolchain.cpp - RISCV ToolChain Implementations ---*- 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 "RISCVToolchain.h"
10e5dd7070Spatrick #include "CommonArgs.h"
11e5dd7070Spatrick #include "clang/Driver/Compilation.h"
12a9ac8606Spatrick #include "clang/Driver/InputInfo.h"
13e5dd7070Spatrick #include "clang/Driver/Options.h"
14e5dd7070Spatrick #include "llvm/Option/ArgList.h"
15e5dd7070Spatrick #include "llvm/Support/FileSystem.h"
16e5dd7070Spatrick #include "llvm/Support/Path.h"
17e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
18e5dd7070Spatrick
19e5dd7070Spatrick using namespace clang::driver;
20e5dd7070Spatrick using namespace clang::driver::toolchains;
21e5dd7070Spatrick using namespace clang::driver::tools;
22e5dd7070Spatrick using namespace clang;
23e5dd7070Spatrick using namespace llvm::opt;
24e5dd7070Spatrick
addMultilibsFilePaths(const Driver & D,const MultilibSet & Multilibs,const Multilib & Multilib,StringRef InstallPath,ToolChain::path_list & Paths)25e5dd7070Spatrick static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs,
26e5dd7070Spatrick const Multilib &Multilib,
27e5dd7070Spatrick StringRef InstallPath,
28e5dd7070Spatrick ToolChain::path_list &Paths) {
29e5dd7070Spatrick if (const auto &PathsCallback = Multilibs.filePathsCallback())
30e5dd7070Spatrick for (const auto &Path : PathsCallback(Multilib))
31e5dd7070Spatrick addPathIfExists(D, InstallPath + Path, Paths);
32e5dd7070Spatrick }
33e5dd7070Spatrick
34a9ac8606Spatrick // This function tests whether a gcc installation is present either
35a9ac8606Spatrick // through gcc-toolchain argument or in the same prefix where clang
36a9ac8606Spatrick // is installed. This helps decide whether to instantiate this toolchain
37a9ac8606Spatrick // or Baremetal toolchain.
hasGCCToolchain(const Driver & D,const llvm::opt::ArgList & Args)38a9ac8606Spatrick bool RISCVToolChain::hasGCCToolchain(const Driver &D,
39a9ac8606Spatrick const llvm::opt::ArgList &Args) {
40a9ac8606Spatrick if (Args.getLastArg(options::OPT_gcc_toolchain))
41a9ac8606Spatrick return true;
42a9ac8606Spatrick
43a9ac8606Spatrick SmallString<128> GCCDir;
44a9ac8606Spatrick llvm::sys::path::append(GCCDir, D.Dir, "..", D.getTargetTriple(),
45a9ac8606Spatrick "lib/crt0.o");
46a9ac8606Spatrick return llvm::sys::fs::exists(GCCDir);
47a9ac8606Spatrick }
48a9ac8606Spatrick
49e5dd7070Spatrick /// RISCV Toolchain
RISCVToolChain(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)50e5dd7070Spatrick RISCVToolChain::RISCVToolChain(const Driver &D, const llvm::Triple &Triple,
51e5dd7070Spatrick const ArgList &Args)
52e5dd7070Spatrick : Generic_ELF(D, Triple, Args) {
53e5dd7070Spatrick GCCInstallation.init(Triple, Args);
54e5dd7070Spatrick if (GCCInstallation.isValid()) {
55e5dd7070Spatrick Multilibs = GCCInstallation.getMultilibs();
56e5dd7070Spatrick SelectedMultilib = GCCInstallation.getMultilib();
57e5dd7070Spatrick path_list &Paths = getFilePaths();
58e5dd7070Spatrick // Add toolchain/multilib specific file paths.
59e5dd7070Spatrick addMultilibsFilePaths(D, Multilibs, SelectedMultilib,
60e5dd7070Spatrick GCCInstallation.getInstallPath(), Paths);
61e5dd7070Spatrick getFilePaths().push_back(GCCInstallation.getInstallPath().str());
62e5dd7070Spatrick ToolChain::path_list &PPaths = getProgramPaths();
63e5dd7070Spatrick // Multilib cross-compiler GCC installations put ld in a triple-prefixed
64e5dd7070Spatrick // directory off of the parent of the GCC installation.
65e5dd7070Spatrick PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" +
66e5dd7070Spatrick GCCInstallation.getTriple().str() + "/bin")
67e5dd7070Spatrick .str());
68e5dd7070Spatrick PPaths.push_back((GCCInstallation.getParentLibPath() + "/../bin").str());
69e5dd7070Spatrick } else {
70e5dd7070Spatrick getProgramPaths().push_back(D.Dir);
71e5dd7070Spatrick }
72e5dd7070Spatrick getFilePaths().push_back(computeSysRoot() + "/lib");
73e5dd7070Spatrick }
74e5dd7070Spatrick
buildLinker() const75e5dd7070Spatrick Tool *RISCVToolChain::buildLinker() const {
76e5dd7070Spatrick return new tools::RISCV::Linker(*this);
77e5dd7070Spatrick }
78e5dd7070Spatrick
GetDefaultRuntimeLibType() const79e5dd7070Spatrick ToolChain::RuntimeLibType RISCVToolChain::GetDefaultRuntimeLibType() const {
80e5dd7070Spatrick return GCCInstallation.isValid() ?
81e5dd7070Spatrick ToolChain::RLT_Libgcc : ToolChain::RLT_CompilerRT;
82e5dd7070Spatrick }
83e5dd7070Spatrick
84e5dd7070Spatrick ToolChain::UnwindLibType
GetUnwindLibType(const llvm::opt::ArgList & Args) const85e5dd7070Spatrick RISCVToolChain::GetUnwindLibType(const llvm::opt::ArgList &Args) const {
86e5dd7070Spatrick return ToolChain::UNW_None;
87e5dd7070Spatrick }
88e5dd7070Spatrick
addClangTargetOptions(const llvm::opt::ArgList & DriverArgs,llvm::opt::ArgStringList & CC1Args,Action::OffloadKind) const89e5dd7070Spatrick void RISCVToolChain::addClangTargetOptions(
90e5dd7070Spatrick const llvm::opt::ArgList &DriverArgs,
91e5dd7070Spatrick llvm::opt::ArgStringList &CC1Args,
92e5dd7070Spatrick Action::OffloadKind) const {
93e5dd7070Spatrick CC1Args.push_back("-nostdsysteminc");
94e5dd7070Spatrick }
95e5dd7070Spatrick
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const96e5dd7070Spatrick void RISCVToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
97e5dd7070Spatrick ArgStringList &CC1Args) const {
98e5dd7070Spatrick if (DriverArgs.hasArg(options::OPT_nostdinc))
99e5dd7070Spatrick return;
100e5dd7070Spatrick
101*12c85518Srobert if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
102*12c85518Srobert SmallString<128> Dir(getDriver().ResourceDir);
103*12c85518Srobert llvm::sys::path::append(Dir, "include");
104*12c85518Srobert addSystemInclude(DriverArgs, CC1Args, Dir.str());
105*12c85518Srobert }
106*12c85518Srobert
107e5dd7070Spatrick if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) {
108e5dd7070Spatrick SmallString<128> Dir(computeSysRoot());
109e5dd7070Spatrick llvm::sys::path::append(Dir, "include");
110e5dd7070Spatrick addSystemInclude(DriverArgs, CC1Args, Dir.str());
111e5dd7070Spatrick }
112e5dd7070Spatrick }
113e5dd7070Spatrick
addLibStdCxxIncludePaths(const llvm::opt::ArgList & DriverArgs,llvm::opt::ArgStringList & CC1Args) const114e5dd7070Spatrick void RISCVToolChain::addLibStdCxxIncludePaths(
115e5dd7070Spatrick const llvm::opt::ArgList &DriverArgs,
116e5dd7070Spatrick llvm::opt::ArgStringList &CC1Args) const {
117e5dd7070Spatrick const GCCVersion &Version = GCCInstallation.getVersion();
118e5dd7070Spatrick StringRef TripleStr = GCCInstallation.getTriple().str();
119e5dd7070Spatrick const Multilib &Multilib = GCCInstallation.getMultilib();
120e5dd7070Spatrick addLibStdCXXIncludePaths(computeSysRoot() + "/include/c++/" + Version.Text,
121a9ac8606Spatrick TripleStr, Multilib.includeSuffix(), DriverArgs,
122a9ac8606Spatrick CC1Args);
123e5dd7070Spatrick }
124e5dd7070Spatrick
computeSysRoot() const125e5dd7070Spatrick std::string RISCVToolChain::computeSysRoot() const {
126e5dd7070Spatrick if (!getDriver().SysRoot.empty())
127e5dd7070Spatrick return getDriver().SysRoot;
128e5dd7070Spatrick
129e5dd7070Spatrick SmallString<128> SysRootDir;
130e5dd7070Spatrick if (GCCInstallation.isValid()) {
131e5dd7070Spatrick StringRef LibDir = GCCInstallation.getParentLibPath();
132e5dd7070Spatrick StringRef TripleStr = GCCInstallation.getTriple().str();
133e5dd7070Spatrick llvm::sys::path::append(SysRootDir, LibDir, "..", TripleStr);
134e5dd7070Spatrick } else {
135e5dd7070Spatrick // Use the triple as provided to the driver. Unlike the parsed triple
136e5dd7070Spatrick // this has not been normalized to always contain every field.
137e5dd7070Spatrick llvm::sys::path::append(SysRootDir, getDriver().Dir, "..",
138e5dd7070Spatrick getDriver().getTargetTriple());
139e5dd7070Spatrick }
140e5dd7070Spatrick
141e5dd7070Spatrick if (!llvm::sys::fs::exists(SysRootDir))
142e5dd7070Spatrick return std::string();
143e5dd7070Spatrick
144ec727ea7Spatrick return std::string(SysRootDir.str());
145e5dd7070Spatrick }
146e5dd7070Spatrick
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const147e5dd7070Spatrick void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA,
148e5dd7070Spatrick const InputInfo &Output,
149e5dd7070Spatrick const InputInfoList &Inputs,
150e5dd7070Spatrick const ArgList &Args,
151e5dd7070Spatrick const char *LinkingOutput) const {
152e5dd7070Spatrick const ToolChain &ToolChain = getToolChain();
153e5dd7070Spatrick const Driver &D = ToolChain.getDriver();
154e5dd7070Spatrick ArgStringList CmdArgs;
155e5dd7070Spatrick
156e5dd7070Spatrick if (!D.SysRoot.empty())
157e5dd7070Spatrick CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
158e5dd7070Spatrick
159e5dd7070Spatrick bool IsRV64 = ToolChain.getArch() == llvm::Triple::riscv64;
160e5dd7070Spatrick CmdArgs.push_back("-m");
161e5dd7070Spatrick if (IsRV64) {
162e5dd7070Spatrick CmdArgs.push_back("elf64lriscv");
163e5dd7070Spatrick } else {
164e5dd7070Spatrick CmdArgs.push_back("elf32lriscv");
165e5dd7070Spatrick }
166*12c85518Srobert CmdArgs.push_back("-X");
167e5dd7070Spatrick
168ec727ea7Spatrick std::string Linker = getToolChain().GetLinkerPath();
169e5dd7070Spatrick
170e5dd7070Spatrick bool WantCRTs =
171e5dd7070Spatrick !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles);
172e5dd7070Spatrick
173e5dd7070Spatrick const char *crtbegin, *crtend;
174e5dd7070Spatrick auto RuntimeLib = ToolChain.GetRuntimeLibType(Args);
175e5dd7070Spatrick if (RuntimeLib == ToolChain::RLT_Libgcc) {
176e5dd7070Spatrick crtbegin = "crtbegin.o";
177e5dd7070Spatrick crtend = "crtend.o";
178e5dd7070Spatrick } else {
179e5dd7070Spatrick assert (RuntimeLib == ToolChain::RLT_CompilerRT);
180e5dd7070Spatrick crtbegin = ToolChain.getCompilerRTArgString(Args, "crtbegin",
181e5dd7070Spatrick ToolChain::FT_Object);
182e5dd7070Spatrick crtend = ToolChain.getCompilerRTArgString(Args, "crtend",
183e5dd7070Spatrick ToolChain::FT_Object);
184e5dd7070Spatrick }
185e5dd7070Spatrick
186e5dd7070Spatrick if (WantCRTs) {
187e5dd7070Spatrick CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
188e5dd7070Spatrick CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
189e5dd7070Spatrick }
190e5dd7070Spatrick
191a9ac8606Spatrick AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
192a9ac8606Spatrick
193e5dd7070Spatrick Args.AddAllArgs(CmdArgs, options::OPT_L);
194a9ac8606Spatrick Args.AddAllArgs(CmdArgs, options::OPT_u);
195e5dd7070Spatrick ToolChain.AddFilePathLibArgs(Args, CmdArgs);
196e5dd7070Spatrick Args.AddAllArgs(CmdArgs,
197e5dd7070Spatrick {options::OPT_T_Group, options::OPT_e, options::OPT_s,
198e5dd7070Spatrick options::OPT_t, options::OPT_Z_Flag, options::OPT_r});
199e5dd7070Spatrick
200e5dd7070Spatrick // TODO: add C++ includes and libs if compiling C++.
201e5dd7070Spatrick
202e5dd7070Spatrick if (!Args.hasArg(options::OPT_nostdlib) &&
203e5dd7070Spatrick !Args.hasArg(options::OPT_nodefaultlibs)) {
204*12c85518Srobert if (D.CCCIsCXX()) {
205e5dd7070Spatrick if (ToolChain.ShouldLinkCXXStdlib(Args))
206e5dd7070Spatrick ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
207*12c85518Srobert CmdArgs.push_back("-lm");
208*12c85518Srobert }
209e5dd7070Spatrick CmdArgs.push_back("--start-group");
210e5dd7070Spatrick CmdArgs.push_back("-lc");
211e5dd7070Spatrick CmdArgs.push_back("-lgloss");
212e5dd7070Spatrick CmdArgs.push_back("--end-group");
213e5dd7070Spatrick AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args);
214e5dd7070Spatrick }
215e5dd7070Spatrick
216e5dd7070Spatrick if (WantCRTs)
217e5dd7070Spatrick CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
218e5dd7070Spatrick
219e5dd7070Spatrick CmdArgs.push_back("-o");
220e5dd7070Spatrick CmdArgs.push_back(Output.getFilename());
221a9ac8606Spatrick C.addCommand(std::make_unique<Command>(
222a9ac8606Spatrick JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Linker),
223a9ac8606Spatrick CmdArgs, Inputs, Output));
224e5dd7070Spatrick }
225e5dd7070Spatrick // RISCV tools end.
226