xref: /openbsd-src/gnu/llvm/clang/lib/Driver/ToolChains/RISCVToolchain.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
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