Coverage Report

Created: 2020-02-15 09:57

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- WebAssembly.cpp - WebAssembly ToolChain Implementation -*- 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 "WebAssembly.h"
10
#include "CommonArgs.h"
11
#include "clang/Basic/Version.h"
12
#include "clang/Config/config.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/Support/FileSystem.h"
18
#include "llvm/Support/Path.h"
19
#include "llvm/Option/ArgList.h"
20
21
using namespace clang::driver;
22
using namespace clang::driver::tools;
23
using namespace clang::driver::toolchains;
24
using namespace clang;
25
using namespace llvm::opt;
26
27
/// Following the conventions in https://wiki.debian.org/Multiarch/Tuples,
28
/// we remove the vendor field to form the multiarch triple.
29
static std::string getMultiarchTriple(const Driver &D,
30
                                      const llvm::Triple &TargetTriple,
31
19
                                      StringRef SysRoot) {
32
19
    return (TargetTriple.getArchName() + "-" +
33
19
            TargetTriple.getOSAndEnvironmentName()).str();
34
19
}
35
36
25
std::string wasm::Linker::getLinkerPath(const ArgList &Args) const {
37
25
  const ToolChain &ToolChain = getToolChain();
38
25
  if (const Arg* A = Args.getLastArg(options::OPT_fuse_ld_EQ)) {
39
1
    StringRef UseLinker = A->getValue();
40
1
    if (!UseLinker.empty()) {
41
1
      if (llvm::sys::path::is_absolute(UseLinker) &&
42
1
          
llvm::sys::fs::can_execute(UseLinker)0
)
43
0
        return std::string(UseLinker);
44
1
45
1
      // Accept 'lld', and 'ld' as aliases for the default linker
46
1
      if (UseLinker != "lld" && UseLinker != "ld")
47
1
        ToolChain.getDriver().Diag(diag::err_drv_invalid_linker_name)
48
1
            << A->getAsString(Args);
49
1
    }
50
1
  }
51
25
52
25
  return ToolChain.GetProgramPath(ToolChain.getDefaultLinker());
53
25
}
54
55
void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
56
                                const InputInfo &Output,
57
                                const InputInfoList &Inputs,
58
                                const ArgList &Args,
59
25
                                const char *LinkingOutput) const {
60
25
61
25
  const ToolChain &ToolChain = getToolChain();
62
25
  const char *Linker = Args.MakeArgString(getLinkerPath(Args));
63
25
  ArgStringList CmdArgs;
64
25
65
25
  if (Args.hasArg(options::OPT_s))
66
0
    CmdArgs.push_back("--strip-all");
67
25
68
25
  Args.AddAllArgs(CmdArgs, options::OPT_L);
69
25
  Args.AddAllArgs(CmdArgs, options::OPT_u);
70
25
  ToolChain.AddFilePathLibArgs(Args, CmdArgs);
71
25
72
25
  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles))
73
25
    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o")));
74
25
75
25
  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
76
25
77
25
  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
78
25
    if (ToolChain.ShouldLinkCXXStdlib(Args))
79
7
      ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
80
25
81
25
    if (Args.hasArg(options::OPT_pthread)) {
82
5
      CmdArgs.push_back("-lpthread");
83
5
      CmdArgs.push_back("--shared-memory");
84
5
    }
85
25
86
25
    CmdArgs.push_back("-lc");
87
25
    AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args);
88
25
  }
89
25
90
25
  CmdArgs.push_back("-o");
91
25
  CmdArgs.push_back(Output.getFilename());
92
25
93
25
  C.addCommand(std::make_unique<Command>(JA, *this, Linker, CmdArgs, Inputs));
94
25
95
25
  // When optimizing, if wasm-opt is available, run it.
96
25
  if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
97
5
    auto WasmOptPath = getToolChain().GetProgramPath("wasm-opt");
98
5
    if (WasmOptPath != "wasm-opt") {
99
0
      StringRef OOpt = "s";
100
0
      if (A->getOption().matches(options::OPT_O4) ||
101
0
          A->getOption().matches(options::OPT_Ofast))
102
0
        OOpt = "4";
103
0
      else if (A->getOption().matches(options::OPT_O0))
104
0
        OOpt = "0";
105
0
      else if (A->getOption().matches(options::OPT_O))
106
0
        OOpt = A->getValue();
107
0
108
0
      if (OOpt != "0") {
109
0
        const char *WasmOpt = Args.MakeArgString(WasmOptPath);
110
0
        ArgStringList CmdArgs;
111
0
        CmdArgs.push_back(Output.getFilename());
112
0
        CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt));
113
0
        CmdArgs.push_back("-o");
114
0
        CmdArgs.push_back(Output.getFilename());
115
0
        C.addCommand(std::make_unique<Command>(JA, *this, WasmOpt, CmdArgs, Inputs));
116
0
      }
117
0
    }
118
5
  }
119
25
}
120
121
/// Given a base library directory, append path components to form the
122
/// LTO directory.
123
1
static std::string AppendLTOLibDir(const std::string &Dir) {
124
1
    // The version allows the path to be keyed to the specific version of
125
1
    // LLVM in used, as the bitcode format is not stable.
126
1
    return Dir + "/llvm-lto/" LLVM_VERSION_STRING;
127
1
}
128
129
WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple,
130
                         const llvm::opt::ArgList &Args)
131
61
    : ToolChain(D, Triple, Args) {
132
61
133
61
  assert(Triple.isArch32Bit() != Triple.isArch64Bit());
134
61
135
61
  getProgramPaths().push_back(getDriver().getInstalledDir());
136
61
137
61
  auto SysRoot = getDriver().SysRoot;
138
61
  if (getTriple().getOS() == llvm::Triple::UnknownOS) {
139
53
    // Theoretically an "unknown" OS should mean no standard libraries, however
140
53
    // it could also mean that a custom set of libraries is in use, so just add
141
53
    // /lib to the search path. Disable multiarch in this case, to discourage
142
53
    // paths containing "unknown" from acquiring meanings.
143
53
    getFilePaths().push_back(SysRoot + "/lib");
144
53
  } else {
145
8
    const std::string MultiarchTriple =
146
8
        getMultiarchTriple(getDriver(), Triple, SysRoot);
147
8
    if (D.isUsingLTO()) {
148
1
      // For LTO, enable use of lto-enabled sysroot libraries too, if available.
149
1
      // Note that the directory is keyed to the LLVM revision, as LLVM's
150
1
      // bitcode format is not stable.
151
1
      auto Dir = AppendLTOLibDir(SysRoot + "/lib/" + MultiarchTriple);
152
1
      getFilePaths().push_back(Dir);
153
1
    }
154
8
    getFilePaths().push_back(SysRoot + "/lib/" + MultiarchTriple);
155
8
  }
156
61
}
157
158
61
bool WebAssembly::IsMathErrnoDefault() const { return false; }
159
160
61
bool WebAssembly::IsObjCNonFragileABIDefault() const { return true; }
161
162
0
bool WebAssembly::UseObjCMixedDispatch() const { return true; }
163
164
61
bool WebAssembly::isPICDefault() const { return false; }
165
166
61
bool WebAssembly::isPIEDefault() const { return false; }
167
168
61
bool WebAssembly::isPICDefaultForced() const { return false; }
169
170
304
bool WebAssembly::IsIntegratedAssemblerDefault() const { return true; }
171
172
0
bool WebAssembly::hasBlocksRuntime() const { return false; }
173
174
// TODO: Support profiling.
175
61
bool WebAssembly::SupportsProfiling() const { return false; }
176
177
25
bool WebAssembly::HasNativeLLVMSupport() const { return true; }
178
179
void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs,
180
                                        ArgStringList &CC1Args,
181
61
                                        Action::OffloadKind) const {
182
61
  if (!DriverArgs.hasFlag(clang::driver::options::OPT_fuse_init_array,
183
61
                          options::OPT_fno_use_init_array, true))
184
0
    CC1Args.push_back("-fno-use-init-array");
185
61
186
61
  // '-pthread' implies atomics, bulk-memory, mutable-globals, and sign-ext
187
61
  if (DriverArgs.hasFlag(options::OPT_pthread, options::OPT_no_pthread,
188
61
                         false)) {
189
9
    if (DriverArgs.hasFlag(options::OPT_mno_atomics, options::OPT_matomics,
190
9
                           false))
191
1
      getDriver().Diag(diag::err_drv_argument_not_allowed_with)
192
1
          << "-pthread"
193
1
          << "-mno-atomics";
194
9
    if (DriverArgs.hasFlag(options::OPT_mno_bulk_memory,
195
9
                           options::OPT_mbulk_memory, false))
196
1
      getDriver().Diag(diag::err_drv_argument_not_allowed_with)
197
1
          << "-pthread"
198
1
          << "-mno-bulk-memory";
199
9
    if (DriverArgs.hasFlag(options::OPT_mno_mutable_globals,
200
9
                           options::OPT_mmutable_globals, false))
201
1
      getDriver().Diag(diag::err_drv_argument_not_allowed_with)
202
1
          << "-pthread"
203
1
          << "-mno-mutable-globals";
204
9
    if (DriverArgs.hasFlag(options::OPT_mno_sign_ext, options::OPT_msign_ext,
205
9
                           false))
206
1
      getDriver().Diag(diag::err_drv_argument_not_allowed_with)
207
1
          << "-pthread"
208
1
          << "-mno-sign-ext";
209
9
    CC1Args.push_back("-target-feature");
210
9
    CC1Args.push_back("+atomics");
211
9
    CC1Args.push_back("-target-feature");
212
9
    CC1Args.push_back("+bulk-memory");
213
9
    CC1Args.push_back("-target-feature");
214
9
    CC1Args.push_back("+mutable-globals");
215
9
    CC1Args.push_back("-target-feature");
216
9
    CC1Args.push_back("+sign-ext");
217
9
  }
218
61
219
61
  if (DriverArgs.getLastArg(options::OPT_fwasm_exceptions)) {
220
4
    // '-fwasm-exceptions' is not compatible with '-mno-exception-handling'
221
4
    if (DriverArgs.hasFlag(options::OPT_mno_exception_handing,
222
4
                           options::OPT_mexception_handing, false))
223
1
      getDriver().Diag(diag::err_drv_argument_not_allowed_with)
224
1
          << "-fwasm-exceptions"
225
1
          << "-mno-exception-handling";
226
4
    // '-fwasm-exceptions' is not compatible with '-mno-reference-types'
227
4
    if (DriverArgs.hasFlag(options::OPT_mno_reference_types,
228
4
                           options::OPT_mexception_handing, false))
229
1
      getDriver().Diag(diag::err_drv_argument_not_allowed_with)
230
1
          << "-fwasm-exceptions"
231
1
          << "-mno-reference-types";
232
4
    // '-fwasm-exceptions' is not compatible with
233
4
    // '-mllvm -enable-emscripten-cxx-exceptions'
234
4
    for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) {
235
1
      if (StringRef(A->getValue(0)) == "-enable-emscripten-cxx-exceptions")
236
1
        getDriver().Diag(diag::err_drv_argument_not_allowed_with)
237
1
            << "-fwasm-exceptions"
238
1
            << "-mllvm -enable-emscripten-cxx-exceptions";
239
1
    }
240
4
    // '-fwasm-exceptions' implies exception-handling and reference-types
241
4
    CC1Args.push_back("-target-feature");
242
4
    CC1Args.push_back("+exception-handling");
243
4
    CC1Args.push_back("-target-feature");
244
4
    CC1Args.push_back("+reference-types");
245
4
  }
246
61
}
247
248
50
ToolChain::RuntimeLibType WebAssembly::GetDefaultRuntimeLibType() const {
249
50
  return ToolChain::RLT_CompilerRT;
250
50
}
251
252
ToolChain::CXXStdlibType
253
7
WebAssembly::GetCXXStdlibType(const ArgList &Args) const {
254
7
  if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
255
5
    StringRef Value = A->getValue();
256
5
    if (Value != "libc++")
257
5
      getDriver().Diag(diag::err_drv_invalid_stdlib_name)
258
5
          << A->getAsString(Args);
259
5
  }
260
7
  return ToolChain::CST_Libcxx;
261
7
}
262
263
void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
264
61
                                            ArgStringList &CC1Args) const {
265
61
  if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
266
0
    return;
267
61
268
61
  const Driver &D = getDriver();
269
61
270
61
  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
271
61
    SmallString<128> P(D.ResourceDir);
272
61
    llvm::sys::path::append(P, "include");
273
61
    addSystemInclude(DriverArgs, CC1Args, P);
274
61
  }
275
61
276
61
  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
277
0
    return;
278
61
279
61
  // Check for configure-time C include directories.
280
61
  StringRef CIncludeDirs(C_INCLUDE_DIRS);
281
61
  if (CIncludeDirs != "") {
282
0
    SmallVector<StringRef, 5> dirs;
283
0
    CIncludeDirs.split(dirs, ":");
284
0
    for (StringRef dir : dirs) {
285
0
      StringRef Prefix =
286
0
          llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : "";
287
0
      addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
288
0
    }
289
0
    return;
290
0
  }
291
61
292
61
  if (getTriple().getOS() != llvm::Triple::UnknownOS) {
293
8
    const std::string MultiarchTriple =
294
8
        getMultiarchTriple(D, getTriple(), D.SysRoot);
295
8
    addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include/" + MultiarchTriple);
296
8
  }
297
61
  addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include");
298
61
}
299
300
void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
301
13
                                               ArgStringList &CC1Args) const {
302
13
  if (!DriverArgs.hasArg(options::OPT_nostdlibinc) &&
303
13
      !DriverArgs.hasArg(options::OPT_nostdincxx)) {
304
13
    if (getTriple().getOS() != llvm::Triple::UnknownOS) {
305
3
      const std::string MultiarchTriple =
306
3
          getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot);
307
3
      addSystemInclude(DriverArgs, CC1Args,
308
3
                       getDriver().SysRoot + "/include/" + MultiarchTriple +
309
3
                           "/c++/v1");
310
3
    }
311
13
    addSystemInclude(DriverArgs, CC1Args,
312
13
                     getDriver().SysRoot + "/include/c++/v1");
313
13
  }
314
13
}
315
316
void WebAssembly::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
317
7
                                      llvm::opt::ArgStringList &CmdArgs) const {
318
7
319
7
  switch (GetCXXStdlibType(Args)) {
320
7
  case ToolChain::CST_Libcxx:
321
7
    CmdArgs.push_back("-lc++");
322
7
    CmdArgs.push_back("-lc++abi");
323
7
    break;
324
0
  case ToolChain::CST_Libstdcxx:
325
0
    llvm_unreachable("invalid stdlib name");
326
7
  }
327
7
}
328
329
61
SanitizerMask WebAssembly::getSupportedSanitizers() const {
330
61
  SanitizerMask Res = ToolChain::getSupportedSanitizers();
331
61
  if (getTriple().isOSEmscripten()) {
332
1
    Res |= SanitizerKind::Vptr | SanitizerKind::Leak | SanitizerKind::Address;
333
1
  }
334
61
  return Res;
335
61
}
336
337
25
Tool *WebAssembly::buildLinker() const {
338
25
  return new tools::wasm::Linker(*this);
339
25
}