Coverage Report

Created: 2022-01-15 10:30

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