blob: a2a9dff79e5208c37f3134d8786e4612ca4b1f85 [file] [log] [blame]
David L. Jonesf561aba2017-03-08 01:02:16 +00001//===--- WebAssembly.cpp - WebAssembly ToolChain Implementation -*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
David L. Jonesf561aba2017-03-08 01:02:16 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "WebAssembly.h"
10#include "CommonArgs.h"
Dan Gohman81282892019-11-20 15:25:43 -080011#include "clang/Basic/Version.h"
Sam Clegg818dd862019-06-13 09:42:43 +000012#include "clang/Config/config.h"
David L. Jonesf561aba2017-03-08 01:02:16 +000013#include "clang/Driver/Compilation.h"
14#include "clang/Driver/Driver.h"
Sam Cleggffbfc0f2018-01-12 17:54:49 +000015#include "clang/Driver/DriverDiagnostic.h"
David L. Jonesf561aba2017-03-08 01:02:16 +000016#include "clang/Driver/Options.h"
Sam Cleggfc5ddee2019-03-28 17:45:18 +000017#include "llvm/Support/FileSystem.h"
18#include "llvm/Support/Path.h"
David L. Jonesf561aba2017-03-08 01:02:16 +000019#include "llvm/Option/ArgList.h"
20
21using namespace clang::driver;
22using namespace clang::driver::tools;
23using namespace clang::driver::toolchains;
24using namespace clang;
25using namespace llvm::opt;
26
Dan Gohman055a6f02019-01-15 06:58:16 +000027/// Following the conventions in https://wiki.debian.org/Multiarch/Tuples,
28/// we remove the vendor field to form the multiarch triple.
29static std::string getMultiarchTriple(const Driver &D,
30 const llvm::Triple &TargetTriple,
31 StringRef SysRoot) {
32 return (TargetTriple.getArchName() + "-" +
33 TargetTriple.getOSAndEnvironmentName()).str();
34}
35
Sam Cleggfc5ddee2019-03-28 17:45:18 +000036std::string wasm::Linker::getLinkerPath(const ArgList &Args) const {
37 const ToolChain &ToolChain = getToolChain();
38 if (const Arg* A = Args.getLastArg(options::OPT_fuse_ld_EQ)) {
39 StringRef UseLinker = A->getValue();
40 if (!UseLinker.empty()) {
41 if (llvm::sys::path::is_absolute(UseLinker) &&
42 llvm::sys::fs::can_execute(UseLinker))
43 return UseLinker;
44
45 // Accept 'lld', and 'ld' as aliases for the default linker
46 if (UseLinker != "lld" && UseLinker != "ld")
47 ToolChain.getDriver().Diag(diag::err_drv_invalid_linker_name)
48 << A->getAsString(Args);
49 }
50 }
51
52 return ToolChain.GetProgramPath(ToolChain.getDefaultLinker());
53}
54
David L. Jonesf561aba2017-03-08 01:02:16 +000055void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
56 const InputInfo &Output,
57 const InputInfoList &Inputs,
58 const ArgList &Args,
59 const char *LinkingOutput) const {
60
61 const ToolChain &ToolChain = getToolChain();
Sam Cleggfc5ddee2019-03-28 17:45:18 +000062 const char *Linker = Args.MakeArgString(getLinkerPath(Args));
David L. Jonesf561aba2017-03-08 01:02:16 +000063 ArgStringList CmdArgs;
David L. Jonesf561aba2017-03-08 01:02:16 +000064
David L. Jonesf561aba2017-03-08 01:02:16 +000065 if (Args.hasArg(options::OPT_s))
66 CmdArgs.push_back("--strip-all");
David L. Jonesf561aba2017-03-08 01:02:16 +000067
68 Args.AddAllArgs(CmdArgs, options::OPT_L);
Sam Cleggd09a3562017-12-02 23:11:13 +000069 Args.AddAllArgs(CmdArgs, options::OPT_u);
David L. Jonesf561aba2017-03-08 01:02:16 +000070 ToolChain.AddFilePathLibArgs(Args, CmdArgs);
71
Sam Clegg471d7af2017-10-27 18:10:19 +000072 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles))
73 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o")));
74
David L. Jonesf561aba2017-03-08 01:02:16 +000075 AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
76
77 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
Nico Weber0ee47d92017-07-25 18:02:57 +000078 if (ToolChain.ShouldLinkCXXStdlib(Args))
David L. Jonesf561aba2017-03-08 01:02:16 +000079 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
80
Thomas Lively80ff58e2019-03-22 22:25:37 +000081 if (Args.hasArg(options::OPT_pthread)) {
David L. Jonesf561aba2017-03-08 01:02:16 +000082 CmdArgs.push_back("-lpthread");
Thomas Lively80ff58e2019-03-22 22:25:37 +000083 CmdArgs.push_back("--shared-memory");
84 }
David L. Jonesf561aba2017-03-08 01:02:16 +000085
86 CmdArgs.push_back("-lc");
Sam Clegga08631e2017-10-27 00:26:07 +000087 AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args);
David L. Jonesf561aba2017-03-08 01:02:16 +000088 }
89
David L. Jonesf561aba2017-03-08 01:02:16 +000090 CmdArgs.push_back("-o");
91 CmdArgs.push_back(Output.getFilename());
92
Jonas Devlieghere2b3d49b2019-08-14 23:04:18 +000093 C.addCommand(std::make_unique<Command>(JA, *this, Linker, CmdArgs, Inputs));
Dan Gohman81282892019-11-20 15:25:43 -080094
95 // When optimizing, if wasm-opt is in the PATH, run wasm-opt.
96 if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
97 if (llvm::ErrorOr<std::string> WasmOptPath =
98 llvm::sys::findProgramByName("wasm-opt")) {
99 StringRef OOpt = "s";
100 if (A->getOption().matches(options::OPT_O4) ||
101 A->getOption().matches(options::OPT_Ofast))
102 OOpt = "4";
103 else if (A->getOption().matches(options::OPT_O0))
104 OOpt = "0";
105 else if (A->getOption().matches(options::OPT_O))
106 OOpt = A->getValue();
107
108 if (OOpt != "0") {
109 const char *WasmOpt = Args.MakeArgString(*WasmOptPath);
110 ArgStringList CmdArgs;
111 CmdArgs.push_back(Output.getFilename());
112 CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt));
113 CmdArgs.push_back("-o");
114 CmdArgs.push_back(Output.getFilename());
115 C.addCommand(std::make_unique<Command>(JA, *this, WasmOpt, CmdArgs, Inputs));
116 }
117 }
118 }
David L. Jonesf561aba2017-03-08 01:02:16 +0000119}
120
121WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple,
122 const llvm::opt::ArgList &Args)
Heejin Ahn4fa8dd92018-08-31 20:57:00 +0000123 : ToolChain(D, Triple, Args) {
David L. Jonesf561aba2017-03-08 01:02:16 +0000124
125 assert(Triple.isArch32Bit() != Triple.isArch64Bit());
Sam Clegg27ea1562017-05-09 17:47:50 +0000126
127 getProgramPaths().push_back(getDriver().getInstalledDir());
128
Dan Gohman055a6f02019-01-15 06:58:16 +0000129 if (getTriple().getOS() == llvm::Triple::UnknownOS) {
130 // Theoretically an "unknown" OS should mean no standard libraries, however
131 // it could also mean that a custom set of libraries is in use, so just add
132 // /lib to the search path. Disable multiarch in this case, to discourage
133 // paths containing "unknown" from acquiring meanings.
134 getFilePaths().push_back(getDriver().SysRoot + "/lib");
135 } else {
136 const std::string MultiarchTriple =
137 getMultiarchTriple(getDriver(), Triple, getDriver().SysRoot);
Dan Gohman81282892019-11-20 15:25:43 -0800138 if (D.isUsingLTO()) {
139 auto LLVMRevision = getLLVMRevision();
140 if (!LLVMRevision.empty()) {
141 // For LTO, enable use of lto-enabled sysroot libraries too, if available.
142 // Note that the directory is keyed to the LLVM revision, as LLVM's
143 // bitcode format is not stable.
144 getFilePaths().push_back(getDriver().SysRoot + "/lib/" + MultiarchTriple +
145 "/llvm-lto/" + LLVMRevision);
146 }
147 }
Dan Gohman055a6f02019-01-15 06:58:16 +0000148 getFilePaths().push_back(getDriver().SysRoot + "/lib/" + MultiarchTriple);
149 }
David L. Jonesf561aba2017-03-08 01:02:16 +0000150}
151
152bool WebAssembly::IsMathErrnoDefault() const { return false; }
153
154bool WebAssembly::IsObjCNonFragileABIDefault() const { return true; }
155
156bool WebAssembly::UseObjCMixedDispatch() const { return true; }
157
158bool WebAssembly::isPICDefault() const { return false; }
159
160bool WebAssembly::isPIEDefault() const { return false; }
161
162bool WebAssembly::isPICDefaultForced() const { return false; }
163
164bool WebAssembly::IsIntegratedAssemblerDefault() const { return true; }
165
David L. Jonesf561aba2017-03-08 01:02:16 +0000166bool WebAssembly::hasBlocksRuntime() const { return false; }
167
168// TODO: Support profiling.
169bool WebAssembly::SupportsProfiling() const { return false; }
170
171bool WebAssembly::HasNativeLLVMSupport() const { return true; }
172
173void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs,
Gheorghe-Teodor Berceaf0f29602017-07-06 16:22:21 +0000174 ArgStringList &CC1Args,
175 Action::OffloadKind) const {
David L. Jonesf561aba2017-03-08 01:02:16 +0000176 if (DriverArgs.hasFlag(clang::driver::options::OPT_fuse_init_array,
177 options::OPT_fno_use_init_array, true))
178 CC1Args.push_back("-fuse-init-array");
Heejin Ahn9d5a0892019-02-11 22:47:50 +0000179
Thomas Lively807ceca2019-10-18 04:34:26 +0000180 // '-pthread' implies atomics, bulk-memory, mutable-globals, and sign-ext
Thomas Livelyf3b4f992019-02-28 18:39:08 +0000181 if (DriverArgs.hasFlag(options::OPT_pthread, options::OPT_no_pthread,
182 false)) {
183 if (DriverArgs.hasFlag(options::OPT_mno_atomics, options::OPT_matomics,
184 false))
185 getDriver().Diag(diag::err_drv_argument_not_allowed_with)
186 << "-pthread"
187 << "-mno-atomics";
Thomas Livelydb8e3642019-07-12 18:23:13 +0000188 if (DriverArgs.hasFlag(options::OPT_mno_bulk_memory,
189 options::OPT_mbulk_memory, false))
190 getDriver().Diag(diag::err_drv_argument_not_allowed_with)
191 << "-pthread"
192 << "-mno-bulk-memory";
193 if (DriverArgs.hasFlag(options::OPT_mno_mutable_globals,
194 options::OPT_mmutable_globals, false))
195 getDriver().Diag(diag::err_drv_argument_not_allowed_with)
196 << "-pthread"
197 << "-mno-mutable-globals";
Thomas Lively807ceca2019-10-18 04:34:26 +0000198 if (DriverArgs.hasFlag(options::OPT_mno_sign_ext, options::OPT_msign_ext,
199 false))
200 getDriver().Diag(diag::err_drv_argument_not_allowed_with)
201 << "-pthread"
202 << "-mno-sign-ext";
Heejin Ahn9d5a0892019-02-11 22:47:50 +0000203 CC1Args.push_back("-target-feature");
204 CC1Args.push_back("+atomics");
Thomas Livelydb8e3642019-07-12 18:23:13 +0000205 CC1Args.push_back("-target-feature");
206 CC1Args.push_back("+bulk-memory");
207 CC1Args.push_back("-target-feature");
208 CC1Args.push_back("+mutable-globals");
Thomas Lively807ceca2019-10-18 04:34:26 +0000209 CC1Args.push_back("-target-feature");
210 CC1Args.push_back("+sign-ext");
Heejin Ahn9d5a0892019-02-11 22:47:50 +0000211 }
Heejin Ahne8b2b882019-09-12 04:01:37 +0000212
213 if (DriverArgs.getLastArg(options::OPT_fwasm_exceptions)) {
214 // '-fwasm-exceptions' is not compatible with '-mno-exception-handling'
215 if (DriverArgs.hasFlag(options::OPT_mno_exception_handing,
216 options::OPT_mexception_handing, false))
217 getDriver().Diag(diag::err_drv_argument_not_allowed_with)
218 << "-fwasm-exceptions"
219 << "-mno-exception-handling";
Heejin Ahn70ee4302019-11-04 16:04:15 -0800220 // '-fwasm-exceptions' is not compatible with '-mno-reference-types'
221 if (DriverArgs.hasFlag(options::OPT_mno_reference_types,
222 options::OPT_mexception_handing, false))
223 getDriver().Diag(diag::err_drv_argument_not_allowed_with)
224 << "-fwasm-exceptions"
225 << "-mno-reference-types";
Heejin Ahne8b2b882019-09-12 04:01:37 +0000226 // '-fwasm-exceptions' is not compatible with
227 // '-mllvm -enable-emscripten-cxx-exceptions'
228 for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) {
229 if (StringRef(A->getValue(0)) == "-enable-emscripten-cxx-exceptions")
230 getDriver().Diag(diag::err_drv_argument_not_allowed_with)
231 << "-fwasm-exceptions"
232 << "-mllvm -enable-emscripten-cxx-exceptions";
233 }
Heejin Ahn70ee4302019-11-04 16:04:15 -0800234 // '-fwasm-exceptions' implies exception-handling and reference-types
Heejin Ahne8b2b882019-09-12 04:01:37 +0000235 CC1Args.push_back("-target-feature");
236 CC1Args.push_back("+exception-handling");
Heejin Ahn70ee4302019-11-04 16:04:15 -0800237 CC1Args.push_back("-target-feature");
238 CC1Args.push_back("+reference-types");
Heejin Ahne8b2b882019-09-12 04:01:37 +0000239 }
David L. Jonesf561aba2017-03-08 01:02:16 +0000240}
241
242ToolChain::RuntimeLibType WebAssembly::GetDefaultRuntimeLibType() const {
243 return ToolChain::RLT_CompilerRT;
244}
245
Heejin Ahn4fa8dd92018-08-31 20:57:00 +0000246ToolChain::CXXStdlibType
247WebAssembly::GetCXXStdlibType(const ArgList &Args) const {
Sam Cleggffbfc0f2018-01-12 17:54:49 +0000248 if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
249 StringRef Value = A->getValue();
250 if (Value != "libc++")
251 getDriver().Diag(diag::err_drv_invalid_stdlib_name)
252 << A->getAsString(Args);
253 }
David L. Jonesf561aba2017-03-08 01:02:16 +0000254 return ToolChain::CST_Libcxx;
255}
256
257void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
258 ArgStringList &CC1Args) const {
Sam Clegg818dd862019-06-13 09:42:43 +0000259 if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
260 return;
261
262 const Driver &D = getDriver();
263
264 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
265 SmallString<128> P(D.ResourceDir);
266 llvm::sys::path::append(P, "include");
267 addSystemInclude(DriverArgs, CC1Args, P);
Dan Gohman055a6f02019-01-15 06:58:16 +0000268 }
Sam Clegg818dd862019-06-13 09:42:43 +0000269
270 if (DriverArgs.hasArg(options::OPT_nostdlibinc))
271 return;
272
273 // Check for configure-time C include directories.
274 StringRef CIncludeDirs(C_INCLUDE_DIRS);
275 if (CIncludeDirs != "") {
276 SmallVector<StringRef, 5> dirs;
277 CIncludeDirs.split(dirs, ":");
278 for (StringRef dir : dirs) {
279 StringRef Prefix =
280 llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : "";
281 addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
282 }
283 return;
284 }
285
286 if (getTriple().getOS() != llvm::Triple::UnknownOS) {
287 const std::string MultiarchTriple =
288 getMultiarchTriple(D, getTriple(), D.SysRoot);
289 addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include/" + MultiarchTriple);
290 }
291 addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include");
David L. Jonesf561aba2017-03-08 01:02:16 +0000292}
293
294void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
295 ArgStringList &CC1Args) const {
296 if (!DriverArgs.hasArg(options::OPT_nostdlibinc) &&
Dan Gohman055a6f02019-01-15 06:58:16 +0000297 !DriverArgs.hasArg(options::OPT_nostdincxx)) {
298 if (getTriple().getOS() != llvm::Triple::UnknownOS) {
299 const std::string MultiarchTriple =
300 getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot);
301 addSystemInclude(DriverArgs, CC1Args,
Sam Clegg818dd862019-06-13 09:42:43 +0000302 getDriver().SysRoot + "/include/" + MultiarchTriple +
303 "/c++/v1");
Dan Gohman055a6f02019-01-15 06:58:16 +0000304 }
David L. Jonesf561aba2017-03-08 01:02:16 +0000305 addSystemInclude(DriverArgs, CC1Args,
306 getDriver().SysRoot + "/include/c++/v1");
Dan Gohman055a6f02019-01-15 06:58:16 +0000307 }
David L. Jonesf561aba2017-03-08 01:02:16 +0000308}
309
Sam Cleggffbfc0f2018-01-12 17:54:49 +0000310void WebAssembly::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
311 llvm::opt::ArgStringList &CmdArgs) const {
312
313 switch (GetCXXStdlibType(Args)) {
314 case ToolChain::CST_Libcxx:
315 CmdArgs.push_back("-lc++");
316 CmdArgs.push_back("-lc++abi");
317 break;
318 case ToolChain::CST_Libstdcxx:
319 llvm_unreachable("invalid stdlib name");
320 }
321}
322
Thomas Lively5458cd42019-05-29 18:31:50 +0000323SanitizerMask WebAssembly::getSupportedSanitizers() const {
324 SanitizerMask Res = ToolChain::getSupportedSanitizers();
325 if (getTriple().isOSEmscripten()) {
Guanzhong Chen9aad9972019-06-26 20:16:14 +0000326 Res |= SanitizerKind::Vptr | SanitizerKind::Leak | SanitizerKind::Address;
Thomas Lively5458cd42019-05-29 18:31:50 +0000327 }
328 return Res;
329}
330
David L. Jonesf561aba2017-03-08 01:02:16 +0000331Tool *WebAssembly::buildLinker() const {
332 return new tools::wasm::Linker(*this);
333}