BareMetal.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. //===-- BareMetal.cpp - Bare Metal ToolChain --------------------*- 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. #include "BareMetal.h"
  9. #include "CommonArgs.h"
  10. #include "Gnu.h"
  11. #include "clang/Driver/InputInfo.h"
  12. #include "Arch/RISCV.h"
  13. #include "clang/Driver/Compilation.h"
  14. #include "clang/Driver/Driver.h"
  15. #include "clang/Driver/DriverDiagnostic.h"
  16. #include "clang/Driver/Options.h"
  17. #include "llvm/Option/ArgList.h"
  18. #include "llvm/Support/Path.h"
  19. #include "llvm/Support/VirtualFileSystem.h"
  20. #include "llvm/Support/raw_ostream.h"
  21. using namespace llvm::opt;
  22. using namespace clang;
  23. using namespace clang::driver;
  24. using namespace clang::driver::tools;
  25. using namespace clang::driver::toolchains;
  26. static Multilib makeMultilib(StringRef commonSuffix) {
  27. return Multilib(commonSuffix, commonSuffix, commonSuffix);
  28. }
  29. static bool findRISCVMultilibs(const Driver &D,
  30. const llvm::Triple &TargetTriple,
  31. const ArgList &Args, DetectedMultilibs &Result) {
  32. Multilib::flags_list Flags;
  33. StringRef Arch = riscv::getRISCVArch(Args, TargetTriple);
  34. StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple);
  35. if (TargetTriple.getArch() == llvm::Triple::riscv64) {
  36. Multilib Imac = makeMultilib("").flag("+march=rv64imac").flag("+mabi=lp64");
  37. Multilib Imafdc = makeMultilib("/rv64imafdc/lp64d")
  38. .flag("+march=rv64imafdc")
  39. .flag("+mabi=lp64d");
  40. // Multilib reuse
  41. bool UseImafdc =
  42. (Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc
  43. addMultilibFlag((Arch == "rv64imac"), "march=rv64imac", Flags);
  44. addMultilibFlag(UseImafdc, "march=rv64imafdc", Flags);
  45. addMultilibFlag(Abi == "lp64", "mabi=lp64", Flags);
  46. addMultilibFlag(Abi == "lp64d", "mabi=lp64d", Flags);
  47. Result.Multilibs = MultilibSet().Either(Imac, Imafdc);
  48. return Result.Multilibs.select(Flags, Result.SelectedMultilib);
  49. }
  50. if (TargetTriple.getArch() == llvm::Triple::riscv32) {
  51. Multilib Imac =
  52. makeMultilib("").flag("+march=rv32imac").flag("+mabi=ilp32");
  53. Multilib I =
  54. makeMultilib("/rv32i/ilp32").flag("+march=rv32i").flag("+mabi=ilp32");
  55. Multilib Im =
  56. makeMultilib("/rv32im/ilp32").flag("+march=rv32im").flag("+mabi=ilp32");
  57. Multilib Iac = makeMultilib("/rv32iac/ilp32")
  58. .flag("+march=rv32iac")
  59. .flag("+mabi=ilp32");
  60. Multilib Imafc = makeMultilib("/rv32imafc/ilp32f")
  61. .flag("+march=rv32imafc")
  62. .flag("+mabi=ilp32f");
  63. // Multilib reuse
  64. bool UseI = (Arch == "rv32i") || (Arch == "rv32ic"); // ic => i
  65. bool UseIm = (Arch == "rv32im") || (Arch == "rv32imc"); // imc => im
  66. bool UseImafc = (Arch == "rv32imafc") || (Arch == "rv32imafdc") ||
  67. (Arch == "rv32gc"); // imafdc,gc => imafc
  68. addMultilibFlag(UseI, "march=rv32i", Flags);
  69. addMultilibFlag(UseIm, "march=rv32im", Flags);
  70. addMultilibFlag((Arch == "rv32iac"), "march=rv32iac", Flags);
  71. addMultilibFlag((Arch == "rv32imac"), "march=rv32imac", Flags);
  72. addMultilibFlag(UseImafc, "march=rv32imafc", Flags);
  73. addMultilibFlag(Abi == "ilp32", "mabi=ilp32", Flags);
  74. addMultilibFlag(Abi == "ilp32f", "mabi=ilp32f", Flags);
  75. Result.Multilibs = MultilibSet().Either(I, Im, Iac, Imac, Imafc);
  76. return Result.Multilibs.select(Flags, Result.SelectedMultilib);
  77. }
  78. return false;
  79. }
  80. BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
  81. const ArgList &Args)
  82. : ToolChain(D, Triple, Args) {
  83. getProgramPaths().push_back(getDriver().getInstalledDir());
  84. if (getDriver().getInstalledDir() != getDriver().Dir)
  85. getProgramPaths().push_back(getDriver().Dir);
  86. findMultilibs(D, Triple, Args);
  87. SmallString<128> SysRoot(computeSysRoot());
  88. if (!SysRoot.empty()) {
  89. llvm::sys::path::append(SysRoot, "lib");
  90. getFilePaths().push_back(std::string(SysRoot));
  91. }
  92. }
  93. /// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ?
  94. static bool isARMBareMetal(const llvm::Triple &Triple) {
  95. if (Triple.getArch() != llvm::Triple::arm &&
  96. Triple.getArch() != llvm::Triple::thumb)
  97. return false;
  98. if (Triple.getVendor() != llvm::Triple::UnknownVendor)
  99. return false;
  100. if (Triple.getOS() != llvm::Triple::UnknownOS)
  101. return false;
  102. if (Triple.getEnvironment() != llvm::Triple::EABI &&
  103. Triple.getEnvironment() != llvm::Triple::EABIHF)
  104. return false;
  105. return true;
  106. }
  107. /// Is the triple aarch64-none-elf?
  108. static bool isAArch64BareMetal(const llvm::Triple &Triple) {
  109. if (Triple.getArch() != llvm::Triple::aarch64)
  110. return false;
  111. if (Triple.getVendor() != llvm::Triple::UnknownVendor)
  112. return false;
  113. if (Triple.getOS() != llvm::Triple::UnknownOS)
  114. return false;
  115. return Triple.getEnvironmentName() == "elf";
  116. }
  117. static bool isRISCVBareMetal(const llvm::Triple &Triple) {
  118. if (Triple.getArch() != llvm::Triple::riscv32 &&
  119. Triple.getArch() != llvm::Triple::riscv64)
  120. return false;
  121. if (Triple.getVendor() != llvm::Triple::UnknownVendor)
  122. return false;
  123. if (Triple.getOS() != llvm::Triple::UnknownOS)
  124. return false;
  125. return Triple.getEnvironmentName() == "elf";
  126. }
  127. void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
  128. const ArgList &Args) {
  129. DetectedMultilibs Result;
  130. if (isRISCVBareMetal(Triple)) {
  131. if (findRISCVMultilibs(D, Triple, Args, Result)) {
  132. SelectedMultilib = Result.SelectedMultilib;
  133. Multilibs = Result.Multilibs;
  134. }
  135. }
  136. }
  137. bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
  138. return isARMBareMetal(Triple) || isAArch64BareMetal(Triple) ||
  139. isRISCVBareMetal(Triple);
  140. }
  141. Tool *BareMetal::buildLinker() const {
  142. return new tools::baremetal::Linker(*this);
  143. }
  144. std::string BareMetal::getCompilerRTPath() const { return getRuntimesDir(); }
  145. std::string BareMetal::buildCompilerRTBasename(const llvm::opt::ArgList &,
  146. StringRef, FileType,
  147. bool) const {
  148. return ("libclang_rt.builtins-" + getTriple().getArchName() + ".a").str();
  149. }
  150. std::string BareMetal::getRuntimesDir() const {
  151. SmallString<128> Dir(getDriver().ResourceDir);
  152. llvm::sys::path::append(Dir, "lib", "baremetal");
  153. Dir += SelectedMultilib.gccSuffix();
  154. return std::string(Dir.str());
  155. }
  156. std::string BareMetal::computeSysRoot() const {
  157. if (!getDriver().SysRoot.empty())
  158. return getDriver().SysRoot + SelectedMultilib.osSuffix();
  159. SmallString<128> SysRootDir;
  160. llvm::sys::path::append(SysRootDir, getDriver().Dir, "../lib/clang-runtimes",
  161. getDriver().getTargetTriple());
  162. SysRootDir += SelectedMultilib.osSuffix();
  163. return std::string(SysRootDir);
  164. }
  165. void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
  166. ArgStringList &CC1Args) const {
  167. if (DriverArgs.hasArg(options::OPT_nostdinc))
  168. return;
  169. if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
  170. SmallString<128> Dir(getDriver().ResourceDir);
  171. llvm::sys::path::append(Dir, "include");
  172. addSystemInclude(DriverArgs, CC1Args, Dir.str());
  173. }
  174. if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) {
  175. SmallString<128> Dir(computeSysRoot());
  176. if (!Dir.empty()) {
  177. llvm::sys::path::append(Dir, "include");
  178. addSystemInclude(DriverArgs, CC1Args, Dir.str());
  179. }
  180. }
  181. }
  182. void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
  183. ArgStringList &CC1Args,
  184. Action::OffloadKind) const {
  185. CC1Args.push_back("-nostdsysteminc");
  186. }
  187. void BareMetal::AddClangCXXStdlibIncludeArgs(
  188. const ArgList &DriverArgs, ArgStringList &CC1Args) const {
  189. if (DriverArgs.hasArg(options::OPT_nostdinc) ||
  190. DriverArgs.hasArg(options::OPT_nostdlibinc) ||
  191. DriverArgs.hasArg(options::OPT_nostdincxx))
  192. return;
  193. std::string SysRoot(computeSysRoot());
  194. if (SysRoot.empty())
  195. return;
  196. switch (GetCXXStdlibType(DriverArgs)) {
  197. case ToolChain::CST_Libcxx: {
  198. SmallString<128> Dir(SysRoot);
  199. llvm::sys::path::append(Dir, "include", "c++", "v1");
  200. addSystemInclude(DriverArgs, CC1Args, Dir.str());
  201. break;
  202. }
  203. case ToolChain::CST_Libstdcxx: {
  204. SmallString<128> Dir(SysRoot);
  205. llvm::sys::path::append(Dir, "include", "c++");
  206. std::error_code EC;
  207. Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
  208. // Walk the subdirs, and find the one with the newest gcc version:
  209. for (llvm::vfs::directory_iterator
  210. LI = getDriver().getVFS().dir_begin(Dir.str(), EC),
  211. LE;
  212. !EC && LI != LE; LI = LI.increment(EC)) {
  213. StringRef VersionText = llvm::sys::path::filename(LI->path());
  214. auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
  215. if (CandidateVersion.Major == -1)
  216. continue;
  217. if (CandidateVersion <= Version)
  218. continue;
  219. Version = CandidateVersion;
  220. }
  221. if (Version.Major == -1)
  222. return;
  223. llvm::sys::path::append(Dir, Version.Text);
  224. addSystemInclude(DriverArgs, CC1Args, Dir.str());
  225. break;
  226. }
  227. }
  228. }
  229. void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args,
  230. ArgStringList &CmdArgs) const {
  231. switch (GetCXXStdlibType(Args)) {
  232. case ToolChain::CST_Libcxx:
  233. CmdArgs.push_back("-lc++");
  234. CmdArgs.push_back("-lc++abi");
  235. break;
  236. case ToolChain::CST_Libstdcxx:
  237. CmdArgs.push_back("-lstdc++");
  238. CmdArgs.push_back("-lsupc++");
  239. break;
  240. }
  241. CmdArgs.push_back("-lunwind");
  242. }
  243. void BareMetal::AddLinkRuntimeLib(const ArgList &Args,
  244. ArgStringList &CmdArgs) const {
  245. ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args);
  246. switch (RLT) {
  247. case ToolChain::RLT_CompilerRT:
  248. CmdArgs.push_back(
  249. Args.MakeArgString("-lclang_rt.builtins-" + getTriple().getArchName()));
  250. return;
  251. case ToolChain::RLT_Libgcc:
  252. CmdArgs.push_back("-lgcc");
  253. return;
  254. }
  255. llvm_unreachable("Unhandled RuntimeLibType.");
  256. }
  257. void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
  258. const InputInfo &Output,
  259. const InputInfoList &Inputs,
  260. const ArgList &Args,
  261. const char *LinkingOutput) const {
  262. ArgStringList CmdArgs;
  263. auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain());
  264. AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
  265. CmdArgs.push_back("-Bstatic");
  266. Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
  267. options::OPT_e, options::OPT_s, options::OPT_t,
  268. options::OPT_Z_Flag, options::OPT_r});
  269. TC.AddFilePathLibArgs(Args, CmdArgs);
  270. CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir()));
  271. if (TC.ShouldLinkCXXStdlib(Args))
  272. TC.AddCXXStdlibLibArgs(Args, CmdArgs);
  273. if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
  274. CmdArgs.push_back("-lc");
  275. CmdArgs.push_back("-lm");
  276. TC.AddLinkRuntimeLib(Args, CmdArgs);
  277. }
  278. CmdArgs.push_back("-o");
  279. CmdArgs.push_back(Output.getFilename());
  280. C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
  281. Args.MakeArgString(TC.GetLinkerPath()),
  282. CmdArgs, Inputs, Output));
  283. }