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