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