1e5dd7070Spatrick //===--- WebAssembly.cpp - Implement WebAssembly target feature support ---===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file implements WebAssembly TargetInfo objects.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick
13e5dd7070Spatrick #include "WebAssembly.h"
14e5dd7070Spatrick #include "Targets.h"
15e5dd7070Spatrick #include "clang/Basic/Builtins.h"
16e5dd7070Spatrick #include "clang/Basic/Diagnostic.h"
17e5dd7070Spatrick #include "clang/Basic/TargetBuiltins.h"
18e5dd7070Spatrick #include "llvm/ADT/StringSwitch.h"
19e5dd7070Spatrick
20e5dd7070Spatrick using namespace clang;
21e5dd7070Spatrick using namespace clang::targets;
22e5dd7070Spatrick
23*12c85518Srobert static constexpr Builtin::Info BuiltinInfo[] = {
24e5dd7070Spatrick #define BUILTIN(ID, TYPE, ATTRS) \
25*12c85518Srobert {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
26e5dd7070Spatrick #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
27*12c85518Srobert {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
28e5dd7070Spatrick #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
29*12c85518Srobert {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES},
30e5dd7070Spatrick #include "clang/Basic/BuiltinsWebAssembly.def"
31e5dd7070Spatrick };
32e5dd7070Spatrick
33e5dd7070Spatrick static constexpr llvm::StringLiteral ValidCPUNames[] = {
34e5dd7070Spatrick {"mvp"}, {"bleeding-edge"}, {"generic"}};
35e5dd7070Spatrick
getABI() const36ec727ea7Spatrick StringRef WebAssemblyTargetInfo::getABI() const { return ABI; }
37ec727ea7Spatrick
setABI(const std::string & Name)38ec727ea7Spatrick bool WebAssemblyTargetInfo::setABI(const std::string &Name) {
39ec727ea7Spatrick if (Name != "mvp" && Name != "experimental-mv")
40ec727ea7Spatrick return false;
41ec727ea7Spatrick
42ec727ea7Spatrick ABI = Name;
43ec727ea7Spatrick return true;
44ec727ea7Spatrick }
45ec727ea7Spatrick
hasFeature(StringRef Feature) const46e5dd7070Spatrick bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
47e5dd7070Spatrick return llvm::StringSwitch<bool>(Feature)
48e5dd7070Spatrick .Case("simd128", SIMDLevel >= SIMD128)
49*12c85518Srobert .Case("relaxed-simd", SIMDLevel >= RelaxedSIMD)
50e5dd7070Spatrick .Case("nontrapping-fptoint", HasNontrappingFPToInt)
51e5dd7070Spatrick .Case("sign-ext", HasSignExt)
52e5dd7070Spatrick .Case("exception-handling", HasExceptionHandling)
53e5dd7070Spatrick .Case("bulk-memory", HasBulkMemory)
54e5dd7070Spatrick .Case("atomics", HasAtomics)
55e5dd7070Spatrick .Case("mutable-globals", HasMutableGlobals)
56e5dd7070Spatrick .Case("multivalue", HasMultivalue)
57e5dd7070Spatrick .Case("tail-call", HasTailCall)
58ec727ea7Spatrick .Case("reference-types", HasReferenceTypes)
59*12c85518Srobert .Case("extended-const", HasExtendedConst)
60e5dd7070Spatrick .Default(false);
61e5dd7070Spatrick }
62e5dd7070Spatrick
isValidCPUName(StringRef Name) const63e5dd7070Spatrick bool WebAssemblyTargetInfo::isValidCPUName(StringRef Name) const {
64*12c85518Srobert return llvm::is_contained(ValidCPUNames, Name);
65e5dd7070Spatrick }
66e5dd7070Spatrick
fillValidCPUList(SmallVectorImpl<StringRef> & Values) const67e5dd7070Spatrick void WebAssemblyTargetInfo::fillValidCPUList(
68e5dd7070Spatrick SmallVectorImpl<StringRef> &Values) const {
69e5dd7070Spatrick Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames));
70e5dd7070Spatrick }
71e5dd7070Spatrick
getTargetDefines(const LangOptions & Opts,MacroBuilder & Builder) const72e5dd7070Spatrick void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts,
73e5dd7070Spatrick MacroBuilder &Builder) const {
74e5dd7070Spatrick defineCPUMacros(Builder, "wasm", /*Tuning=*/false);
75e5dd7070Spatrick if (SIMDLevel >= SIMD128)
76e5dd7070Spatrick Builder.defineMacro("__wasm_simd128__");
77*12c85518Srobert if (SIMDLevel >= RelaxedSIMD)
78*12c85518Srobert Builder.defineMacro("__wasm_relaxed_simd__");
79e5dd7070Spatrick if (HasNontrappingFPToInt)
80e5dd7070Spatrick Builder.defineMacro("__wasm_nontrapping_fptoint__");
81e5dd7070Spatrick if (HasSignExt)
82e5dd7070Spatrick Builder.defineMacro("__wasm_sign_ext__");
83e5dd7070Spatrick if (HasExceptionHandling)
84e5dd7070Spatrick Builder.defineMacro("__wasm_exception_handling__");
85e5dd7070Spatrick if (HasBulkMemory)
86e5dd7070Spatrick Builder.defineMacro("__wasm_bulk_memory__");
87e5dd7070Spatrick if (HasAtomics)
88e5dd7070Spatrick Builder.defineMacro("__wasm_atomics__");
89e5dd7070Spatrick if (HasMutableGlobals)
90e5dd7070Spatrick Builder.defineMacro("__wasm_mutable_globals__");
91e5dd7070Spatrick if (HasMultivalue)
92e5dd7070Spatrick Builder.defineMacro("__wasm_multivalue__");
93e5dd7070Spatrick if (HasTailCall)
94e5dd7070Spatrick Builder.defineMacro("__wasm_tail_call__");
95ec727ea7Spatrick if (HasReferenceTypes)
96ec727ea7Spatrick Builder.defineMacro("__wasm_reference_types__");
97*12c85518Srobert if (HasExtendedConst)
98*12c85518Srobert Builder.defineMacro("__wasm_extended_const__");
99*12c85518Srobert
100*12c85518Srobert Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
101*12c85518Srobert Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
102*12c85518Srobert Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
103*12c85518Srobert Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
104e5dd7070Spatrick }
105e5dd7070Spatrick
setSIMDLevel(llvm::StringMap<bool> & Features,SIMDEnum Level,bool Enabled)106e5dd7070Spatrick void WebAssemblyTargetInfo::setSIMDLevel(llvm::StringMap<bool> &Features,
107ec727ea7Spatrick SIMDEnum Level, bool Enabled) {
108ec727ea7Spatrick if (Enabled) {
109e5dd7070Spatrick switch (Level) {
110*12c85518Srobert case RelaxedSIMD:
111*12c85518Srobert Features["relaxed-simd"] = true;
112*12c85518Srobert [[fallthrough]];
113e5dd7070Spatrick case SIMD128:
114e5dd7070Spatrick Features["simd128"] = true;
115*12c85518Srobert [[fallthrough]];
116e5dd7070Spatrick case NoSIMD:
117e5dd7070Spatrick break;
118e5dd7070Spatrick }
119ec727ea7Spatrick return;
120ec727ea7Spatrick }
121ec727ea7Spatrick
122ec727ea7Spatrick switch (Level) {
123ec727ea7Spatrick case NoSIMD:
124ec727ea7Spatrick case SIMD128:
125ec727ea7Spatrick Features["simd128"] = false;
126*12c85518Srobert [[fallthrough]];
127*12c85518Srobert case RelaxedSIMD:
128*12c85518Srobert Features["relaxed-simd"] = false;
129ec727ea7Spatrick break;
130ec727ea7Spatrick }
131ec727ea7Spatrick }
132ec727ea7Spatrick
setFeatureEnabled(llvm::StringMap<bool> & Features,StringRef Name,bool Enabled) const133ec727ea7Spatrick void WebAssemblyTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
134ec727ea7Spatrick StringRef Name,
135ec727ea7Spatrick bool Enabled) const {
136ec727ea7Spatrick if (Name == "simd128")
137ec727ea7Spatrick setSIMDLevel(Features, SIMD128, Enabled);
138*12c85518Srobert else if (Name == "relaxed-simd")
139*12c85518Srobert setSIMDLevel(Features, RelaxedSIMD, Enabled);
140ec727ea7Spatrick else
141ec727ea7Spatrick Features[Name] = Enabled;
142e5dd7070Spatrick }
143e5dd7070Spatrick
initFeatureMap(llvm::StringMap<bool> & Features,DiagnosticsEngine & Diags,StringRef CPU,const std::vector<std::string> & FeaturesVec) const144e5dd7070Spatrick bool WebAssemblyTargetInfo::initFeatureMap(
145e5dd7070Spatrick llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
146e5dd7070Spatrick const std::vector<std::string> &FeaturesVec) const {
147e5dd7070Spatrick if (CPU == "bleeding-edge") {
148e5dd7070Spatrick Features["nontrapping-fptoint"] = true;
149e5dd7070Spatrick Features["sign-ext"] = true;
150e5dd7070Spatrick Features["bulk-memory"] = true;
151e5dd7070Spatrick Features["atomics"] = true;
152e5dd7070Spatrick Features["mutable-globals"] = true;
153e5dd7070Spatrick Features["tail-call"] = true;
154ec727ea7Spatrick setSIMDLevel(Features, SIMD128, true);
155*12c85518Srobert } else if (CPU == "generic") {
156*12c85518Srobert Features["sign-ext"] = true;
157*12c85518Srobert Features["mutable-globals"] = true;
158ec727ea7Spatrick }
159e5dd7070Spatrick
160e5dd7070Spatrick return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
161e5dd7070Spatrick }
162e5dd7070Spatrick
handleTargetFeatures(std::vector<std::string> & Features,DiagnosticsEngine & Diags)163e5dd7070Spatrick bool WebAssemblyTargetInfo::handleTargetFeatures(
164e5dd7070Spatrick std::vector<std::string> &Features, DiagnosticsEngine &Diags) {
165e5dd7070Spatrick for (const auto &Feature : Features) {
166e5dd7070Spatrick if (Feature == "+simd128") {
167e5dd7070Spatrick SIMDLevel = std::max(SIMDLevel, SIMD128);
168e5dd7070Spatrick continue;
169e5dd7070Spatrick }
170e5dd7070Spatrick if (Feature == "-simd128") {
171e5dd7070Spatrick SIMDLevel = std::min(SIMDLevel, SIMDEnum(SIMD128 - 1));
172e5dd7070Spatrick continue;
173e5dd7070Spatrick }
174*12c85518Srobert if (Feature == "+relaxed-simd") {
175*12c85518Srobert SIMDLevel = std::max(SIMDLevel, RelaxedSIMD);
176*12c85518Srobert continue;
177*12c85518Srobert }
178*12c85518Srobert if (Feature == "-relaxed-simd") {
179*12c85518Srobert SIMDLevel = std::min(SIMDLevel, SIMDEnum(RelaxedSIMD - 1));
180*12c85518Srobert continue;
181*12c85518Srobert }
182e5dd7070Spatrick if (Feature == "+nontrapping-fptoint") {
183e5dd7070Spatrick HasNontrappingFPToInt = true;
184e5dd7070Spatrick continue;
185e5dd7070Spatrick }
186e5dd7070Spatrick if (Feature == "-nontrapping-fptoint") {
187e5dd7070Spatrick HasNontrappingFPToInt = false;
188e5dd7070Spatrick continue;
189e5dd7070Spatrick }
190e5dd7070Spatrick if (Feature == "+sign-ext") {
191e5dd7070Spatrick HasSignExt = true;
192e5dd7070Spatrick continue;
193e5dd7070Spatrick }
194e5dd7070Spatrick if (Feature == "-sign-ext") {
195e5dd7070Spatrick HasSignExt = false;
196e5dd7070Spatrick continue;
197e5dd7070Spatrick }
198e5dd7070Spatrick if (Feature == "+exception-handling") {
199e5dd7070Spatrick HasExceptionHandling = true;
200e5dd7070Spatrick continue;
201e5dd7070Spatrick }
202e5dd7070Spatrick if (Feature == "-exception-handling") {
203e5dd7070Spatrick HasExceptionHandling = false;
204e5dd7070Spatrick continue;
205e5dd7070Spatrick }
206e5dd7070Spatrick if (Feature == "+bulk-memory") {
207e5dd7070Spatrick HasBulkMemory = true;
208e5dd7070Spatrick continue;
209e5dd7070Spatrick }
210e5dd7070Spatrick if (Feature == "-bulk-memory") {
211e5dd7070Spatrick HasBulkMemory = false;
212e5dd7070Spatrick continue;
213e5dd7070Spatrick }
214e5dd7070Spatrick if (Feature == "+atomics") {
215e5dd7070Spatrick HasAtomics = true;
216e5dd7070Spatrick continue;
217e5dd7070Spatrick }
218e5dd7070Spatrick if (Feature == "-atomics") {
219e5dd7070Spatrick HasAtomics = false;
220e5dd7070Spatrick continue;
221e5dd7070Spatrick }
222e5dd7070Spatrick if (Feature == "+mutable-globals") {
223e5dd7070Spatrick HasMutableGlobals = true;
224e5dd7070Spatrick continue;
225e5dd7070Spatrick }
226e5dd7070Spatrick if (Feature == "-mutable-globals") {
227e5dd7070Spatrick HasMutableGlobals = false;
228e5dd7070Spatrick continue;
229e5dd7070Spatrick }
230e5dd7070Spatrick if (Feature == "+multivalue") {
231e5dd7070Spatrick HasMultivalue = true;
232e5dd7070Spatrick continue;
233e5dd7070Spatrick }
234e5dd7070Spatrick if (Feature == "-multivalue") {
235e5dd7070Spatrick HasMultivalue = false;
236e5dd7070Spatrick continue;
237e5dd7070Spatrick }
238e5dd7070Spatrick if (Feature == "+tail-call") {
239e5dd7070Spatrick HasTailCall = true;
240e5dd7070Spatrick continue;
241e5dd7070Spatrick }
242e5dd7070Spatrick if (Feature == "-tail-call") {
243e5dd7070Spatrick HasTailCall = false;
244e5dd7070Spatrick continue;
245e5dd7070Spatrick }
246ec727ea7Spatrick if (Feature == "+reference-types") {
247ec727ea7Spatrick HasReferenceTypes = true;
248ec727ea7Spatrick continue;
249ec727ea7Spatrick }
250ec727ea7Spatrick if (Feature == "-reference-types") {
251ec727ea7Spatrick HasReferenceTypes = false;
252ec727ea7Spatrick continue;
253ec727ea7Spatrick }
254*12c85518Srobert if (Feature == "+extended-const") {
255*12c85518Srobert HasExtendedConst = true;
256*12c85518Srobert continue;
257*12c85518Srobert }
258*12c85518Srobert if (Feature == "-extended-const") {
259*12c85518Srobert HasExtendedConst = false;
260*12c85518Srobert continue;
261*12c85518Srobert }
262e5dd7070Spatrick
263e5dd7070Spatrick Diags.Report(diag::err_opt_not_valid_with_opt)
264e5dd7070Spatrick << Feature << "-target-feature";
265e5dd7070Spatrick return false;
266e5dd7070Spatrick }
267e5dd7070Spatrick return true;
268e5dd7070Spatrick }
269e5dd7070Spatrick
getTargetBuiltins() const270e5dd7070Spatrick ArrayRef<Builtin::Info> WebAssemblyTargetInfo::getTargetBuiltins() const {
271*12c85518Srobert return llvm::ArrayRef(BuiltinInfo, clang::WebAssembly::LastTSBuiltin -
272e5dd7070Spatrick Builtin::FirstTSBuiltin);
273e5dd7070Spatrick }
274e5dd7070Spatrick
adjust(DiagnosticsEngine & Diags,LangOptions & Opts)275a9ac8606Spatrick void WebAssemblyTargetInfo::adjust(DiagnosticsEngine &Diags,
276a9ac8606Spatrick LangOptions &Opts) {
277*12c85518Srobert TargetInfo::adjust(Diags, Opts);
278*12c85518Srobert // Turn off POSIXThreads and ThreadModel so that we don't predefine _REENTRANT
279*12c85518Srobert // or __STDCPP_THREADS__ if we will eventually end up stripping atomics
280*12c85518Srobert // because they are unsupported.
281*12c85518Srobert if (!HasAtomics || !HasBulkMemory) {
282a9ac8606Spatrick Opts.POSIXThreads = false;
283a9ac8606Spatrick Opts.setThreadModel(LangOptions::ThreadModelKind::Single);
284*12c85518Srobert Opts.ThreadsafeStatics = false;
285a9ac8606Spatrick }
286a9ac8606Spatrick }
287a9ac8606Spatrick
getTargetDefines(const LangOptions & Opts,MacroBuilder & Builder) const288e5dd7070Spatrick void WebAssembly32TargetInfo::getTargetDefines(const LangOptions &Opts,
289e5dd7070Spatrick MacroBuilder &Builder) const {
290e5dd7070Spatrick WebAssemblyTargetInfo::getTargetDefines(Opts, Builder);
291e5dd7070Spatrick defineCPUMacros(Builder, "wasm32", /*Tuning=*/false);
292e5dd7070Spatrick }
293e5dd7070Spatrick
getTargetDefines(const LangOptions & Opts,MacroBuilder & Builder) const294e5dd7070Spatrick void WebAssembly64TargetInfo::getTargetDefines(const LangOptions &Opts,
295e5dd7070Spatrick MacroBuilder &Builder) const {
296e5dd7070Spatrick WebAssemblyTargetInfo::getTargetDefines(Opts, Builder);
297e5dd7070Spatrick defineCPUMacros(Builder, "wasm64", /*Tuning=*/false);
298e5dd7070Spatrick }
299