10b57cec5SDimitry Andric //===--- WebAssembly.cpp - Implement WebAssembly target feature support ---===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements WebAssembly TargetInfo objects.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "WebAssembly.h"
140b57cec5SDimitry Andric #include "Targets.h"
150b57cec5SDimitry Andric #include "clang/Basic/Builtins.h"
160b57cec5SDimitry Andric #include "clang/Basic/Diagnostic.h"
170b57cec5SDimitry Andric #include "clang/Basic/TargetBuiltins.h"
180b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric using namespace clang;
210b57cec5SDimitry Andric using namespace clang::targets;
220b57cec5SDimitry Andric
23bdd1243dSDimitry Andric static constexpr Builtin::Info BuiltinInfo[] = {
240b57cec5SDimitry Andric #define BUILTIN(ID, TYPE, ATTRS) \
25bdd1243dSDimitry Andric {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
260b57cec5SDimitry Andric #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
27bdd1243dSDimitry Andric {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
280b57cec5SDimitry Andric #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
29bdd1243dSDimitry Andric {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES},
300b57cec5SDimitry Andric #include "clang/Basic/BuiltinsWebAssembly.def"
310b57cec5SDimitry Andric };
320b57cec5SDimitry Andric
330b57cec5SDimitry Andric static constexpr llvm::StringLiteral ValidCPUNames[] = {
340b57cec5SDimitry Andric {"mvp"}, {"bleeding-edge"}, {"generic"}};
350b57cec5SDimitry Andric
getABI() const365ffd83dbSDimitry Andric StringRef WebAssemblyTargetInfo::getABI() const { return ABI; }
375ffd83dbSDimitry Andric
setABI(const std::string & Name)385ffd83dbSDimitry Andric bool WebAssemblyTargetInfo::setABI(const std::string &Name) {
395ffd83dbSDimitry Andric if (Name != "mvp" && Name != "experimental-mv")
405ffd83dbSDimitry Andric return false;
415ffd83dbSDimitry Andric
425ffd83dbSDimitry Andric ABI = Name;
435ffd83dbSDimitry Andric return true;
445ffd83dbSDimitry Andric }
455ffd83dbSDimitry Andric
hasFeature(StringRef Feature) const460b57cec5SDimitry Andric bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
470b57cec5SDimitry Andric return llvm::StringSwitch<bool>(Feature)
480b57cec5SDimitry Andric .Case("atomics", HasAtomics)
49*0fca6ea1SDimitry Andric .Case("bulk-memory", HasBulkMemory)
50*0fca6ea1SDimitry Andric .Case("exception-handling", HasExceptionHandling)
5181ad6265SDimitry Andric .Case("extended-const", HasExtendedConst)
52*0fca6ea1SDimitry Andric .Case("half-precision", HasHalfPrecision)
535f757f3fSDimitry Andric .Case("multimemory", HasMultiMemory)
54*0fca6ea1SDimitry Andric .Case("multivalue", HasMultivalue)
55*0fca6ea1SDimitry Andric .Case("mutable-globals", HasMutableGlobals)
56*0fca6ea1SDimitry Andric .Case("nontrapping-fptoint", HasNontrappingFPToInt)
57*0fca6ea1SDimitry Andric .Case("reference-types", HasReferenceTypes)
58*0fca6ea1SDimitry Andric .Case("relaxed-simd", SIMDLevel >= RelaxedSIMD)
59*0fca6ea1SDimitry Andric .Case("sign-ext", HasSignExt)
60*0fca6ea1SDimitry Andric .Case("simd128", SIMDLevel >= SIMD128)
61*0fca6ea1SDimitry Andric .Case("tail-call", HasTailCall)
620b57cec5SDimitry Andric .Default(false);
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric
isValidCPUName(StringRef Name) const650b57cec5SDimitry Andric bool WebAssemblyTargetInfo::isValidCPUName(StringRef Name) const {
66349cc55cSDimitry Andric return llvm::is_contained(ValidCPUNames, Name);
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric
fillValidCPUList(SmallVectorImpl<StringRef> & Values) const690b57cec5SDimitry Andric void WebAssemblyTargetInfo::fillValidCPUList(
700b57cec5SDimitry Andric SmallVectorImpl<StringRef> &Values) const {
710b57cec5SDimitry Andric Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames));
720b57cec5SDimitry Andric }
730b57cec5SDimitry Andric
getTargetDefines(const LangOptions & Opts,MacroBuilder & Builder) const740b57cec5SDimitry Andric void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts,
750b57cec5SDimitry Andric MacroBuilder &Builder) const {
760b57cec5SDimitry Andric defineCPUMacros(Builder, "wasm", /*Tuning=*/false);
770b57cec5SDimitry Andric if (HasAtomics)
780b57cec5SDimitry Andric Builder.defineMacro("__wasm_atomics__");
79*0fca6ea1SDimitry Andric if (HasBulkMemory)
80*0fca6ea1SDimitry Andric Builder.defineMacro("__wasm_bulk_memory__");
81*0fca6ea1SDimitry Andric if (HasExceptionHandling)
82*0fca6ea1SDimitry Andric Builder.defineMacro("__wasm_exception_handling__");
8381ad6265SDimitry Andric if (HasExtendedConst)
8481ad6265SDimitry Andric Builder.defineMacro("__wasm_extended_const__");
855f757f3fSDimitry Andric if (HasMultiMemory)
865f757f3fSDimitry Andric Builder.defineMacro("__wasm_multimemory__");
87*0fca6ea1SDimitry Andric if (HasHalfPrecision)
88*0fca6ea1SDimitry Andric Builder.defineMacro("__wasm_half_precision__");
89*0fca6ea1SDimitry Andric if (HasMultivalue)
90*0fca6ea1SDimitry Andric Builder.defineMacro("__wasm_multivalue__");
91*0fca6ea1SDimitry Andric if (HasMutableGlobals)
92*0fca6ea1SDimitry Andric Builder.defineMacro("__wasm_mutable_globals__");
93*0fca6ea1SDimitry Andric if (HasNontrappingFPToInt)
94*0fca6ea1SDimitry Andric Builder.defineMacro("__wasm_nontrapping_fptoint__");
95*0fca6ea1SDimitry Andric if (HasReferenceTypes)
96*0fca6ea1SDimitry Andric Builder.defineMacro("__wasm_reference_types__");
97*0fca6ea1SDimitry Andric if (SIMDLevel >= RelaxedSIMD)
98*0fca6ea1SDimitry Andric Builder.defineMacro("__wasm_relaxed_simd__");
99*0fca6ea1SDimitry Andric if (HasSignExt)
100*0fca6ea1SDimitry Andric Builder.defineMacro("__wasm_sign_ext__");
101*0fca6ea1SDimitry Andric if (SIMDLevel >= SIMD128)
102*0fca6ea1SDimitry Andric Builder.defineMacro("__wasm_simd128__");
103*0fca6ea1SDimitry Andric if (HasTailCall)
104*0fca6ea1SDimitry Andric Builder.defineMacro("__wasm_tail_call__");
105bdd1243dSDimitry Andric
106bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
107bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
108bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
109bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
1100b57cec5SDimitry Andric }
1110b57cec5SDimitry Andric
setSIMDLevel(llvm::StringMap<bool> & Features,SIMDEnum Level,bool Enabled)1120b57cec5SDimitry Andric void WebAssemblyTargetInfo::setSIMDLevel(llvm::StringMap<bool> &Features,
11375b4d546SDimitry Andric SIMDEnum Level, bool Enabled) {
11475b4d546SDimitry Andric if (Enabled) {
1150b57cec5SDimitry Andric switch (Level) {
116349cc55cSDimitry Andric case RelaxedSIMD:
117349cc55cSDimitry Andric Features["relaxed-simd"] = true;
118bdd1243dSDimitry Andric [[fallthrough]];
1190b57cec5SDimitry Andric case SIMD128:
1200b57cec5SDimitry Andric Features["simd128"] = true;
121bdd1243dSDimitry Andric [[fallthrough]];
1220b57cec5SDimitry Andric case NoSIMD:
1230b57cec5SDimitry Andric break;
1240b57cec5SDimitry Andric }
12575b4d546SDimitry Andric return;
12675b4d546SDimitry Andric }
12775b4d546SDimitry Andric
12875b4d546SDimitry Andric switch (Level) {
12975b4d546SDimitry Andric case NoSIMD:
13075b4d546SDimitry Andric case SIMD128:
13175b4d546SDimitry Andric Features["simd128"] = false;
132bdd1243dSDimitry Andric [[fallthrough]];
133349cc55cSDimitry Andric case RelaxedSIMD:
134349cc55cSDimitry Andric Features["relaxed-simd"] = false;
13575b4d546SDimitry Andric break;
13675b4d546SDimitry Andric }
13775b4d546SDimitry Andric }
13875b4d546SDimitry Andric
setFeatureEnabled(llvm::StringMap<bool> & Features,StringRef Name,bool Enabled) const13975b4d546SDimitry Andric void WebAssemblyTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
14075b4d546SDimitry Andric StringRef Name,
14175b4d546SDimitry Andric bool Enabled) const {
14275b4d546SDimitry Andric if (Name == "simd128")
14375b4d546SDimitry Andric setSIMDLevel(Features, SIMD128, Enabled);
144349cc55cSDimitry Andric else if (Name == "relaxed-simd")
145349cc55cSDimitry Andric setSIMDLevel(Features, RelaxedSIMD, Enabled);
14675b4d546SDimitry Andric else
14775b4d546SDimitry Andric Features[Name] = Enabled;
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric
initFeatureMap(llvm::StringMap<bool> & Features,DiagnosticsEngine & Diags,StringRef CPU,const std::vector<std::string> & FeaturesVec) const1500b57cec5SDimitry Andric bool WebAssemblyTargetInfo::initFeatureMap(
1510b57cec5SDimitry Andric llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
1520b57cec5SDimitry Andric const std::vector<std::string> &FeaturesVec) const {
153*0fca6ea1SDimitry Andric auto addGenericFeatures = [&]() {
154*0fca6ea1SDimitry Andric Features["multivalue"] = true;
1550b57cec5SDimitry Andric Features["mutable-globals"] = true;
15606c3fb27SDimitry Andric Features["reference-types"] = true;
157bdd1243dSDimitry Andric Features["sign-ext"] = true;
158*0fca6ea1SDimitry Andric };
159*0fca6ea1SDimitry Andric auto addBleedingEdgeFeatures = [&]() {
160*0fca6ea1SDimitry Andric addGenericFeatures();
161*0fca6ea1SDimitry Andric Features["atomics"] = true;
162*0fca6ea1SDimitry Andric Features["bulk-memory"] = true;
163*0fca6ea1SDimitry Andric Features["exception-handling"] = true;
164*0fca6ea1SDimitry Andric Features["extended-const"] = true;
165*0fca6ea1SDimitry Andric Features["half-precision"] = true;
166*0fca6ea1SDimitry Andric Features["multimemory"] = true;
167*0fca6ea1SDimitry Andric Features["nontrapping-fptoint"] = true;
168*0fca6ea1SDimitry Andric Features["tail-call"] = true;
169*0fca6ea1SDimitry Andric setSIMDLevel(Features, RelaxedSIMD, true);
170*0fca6ea1SDimitry Andric };
171*0fca6ea1SDimitry Andric if (CPU == "generic") {
172*0fca6ea1SDimitry Andric addGenericFeatures();
173*0fca6ea1SDimitry Andric } else if (CPU == "bleeding-edge") {
174*0fca6ea1SDimitry Andric addBleedingEdgeFeatures();
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric
1770b57cec5SDimitry Andric return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric
handleTargetFeatures(std::vector<std::string> & Features,DiagnosticsEngine & Diags)1800b57cec5SDimitry Andric bool WebAssemblyTargetInfo::handleTargetFeatures(
1810b57cec5SDimitry Andric std::vector<std::string> &Features, DiagnosticsEngine &Diags) {
1820b57cec5SDimitry Andric for (const auto &Feature : Features) {
183*0fca6ea1SDimitry Andric if (Feature == "+atomics") {
184*0fca6ea1SDimitry Andric HasAtomics = true;
1850b57cec5SDimitry Andric continue;
1860b57cec5SDimitry Andric }
187*0fca6ea1SDimitry Andric if (Feature == "-atomics") {
188*0fca6ea1SDimitry Andric HasAtomics = false;
1890b57cec5SDimitry Andric continue;
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric if (Feature == "+bulk-memory") {
1920b57cec5SDimitry Andric HasBulkMemory = true;
1930b57cec5SDimitry Andric continue;
1940b57cec5SDimitry Andric }
1950b57cec5SDimitry Andric if (Feature == "-bulk-memory") {
1960b57cec5SDimitry Andric HasBulkMemory = false;
1970b57cec5SDimitry Andric continue;
1980b57cec5SDimitry Andric }
199*0fca6ea1SDimitry Andric if (Feature == "+exception-handling") {
200*0fca6ea1SDimitry Andric HasExceptionHandling = true;
2010b57cec5SDimitry Andric continue;
2020b57cec5SDimitry Andric }
203*0fca6ea1SDimitry Andric if (Feature == "-exception-handling") {
204*0fca6ea1SDimitry Andric HasExceptionHandling = false;
2055ffd83dbSDimitry Andric continue;
2065ffd83dbSDimitry Andric }
20781ad6265SDimitry Andric if (Feature == "+extended-const") {
20881ad6265SDimitry Andric HasExtendedConst = true;
20981ad6265SDimitry Andric continue;
21081ad6265SDimitry Andric }
21181ad6265SDimitry Andric if (Feature == "-extended-const") {
21281ad6265SDimitry Andric HasExtendedConst = false;
21381ad6265SDimitry Andric continue;
21481ad6265SDimitry Andric }
215*0fca6ea1SDimitry Andric if (Feature == "+half-precision") {
216*0fca6ea1SDimitry Andric SIMDLevel = std::max(SIMDLevel, SIMD128);
217*0fca6ea1SDimitry Andric HasHalfPrecision = true;
218*0fca6ea1SDimitry Andric continue;
219*0fca6ea1SDimitry Andric }
220*0fca6ea1SDimitry Andric if (Feature == "-half-precision") {
221*0fca6ea1SDimitry Andric HasHalfPrecision = false;
222*0fca6ea1SDimitry Andric continue;
223*0fca6ea1SDimitry Andric }
2245f757f3fSDimitry Andric if (Feature == "+multimemory") {
2255f757f3fSDimitry Andric HasMultiMemory = true;
2265f757f3fSDimitry Andric continue;
2275f757f3fSDimitry Andric }
2285f757f3fSDimitry Andric if (Feature == "-multimemory") {
2295f757f3fSDimitry Andric HasMultiMemory = false;
2305f757f3fSDimitry Andric continue;
2315f757f3fSDimitry Andric }
232*0fca6ea1SDimitry Andric if (Feature == "+multivalue") {
233*0fca6ea1SDimitry Andric HasMultivalue = true;
234*0fca6ea1SDimitry Andric continue;
235*0fca6ea1SDimitry Andric }
236*0fca6ea1SDimitry Andric if (Feature == "-multivalue") {
237*0fca6ea1SDimitry Andric HasMultivalue = false;
238*0fca6ea1SDimitry Andric continue;
239*0fca6ea1SDimitry Andric }
240*0fca6ea1SDimitry Andric if (Feature == "+mutable-globals") {
241*0fca6ea1SDimitry Andric HasMutableGlobals = true;
242*0fca6ea1SDimitry Andric continue;
243*0fca6ea1SDimitry Andric }
244*0fca6ea1SDimitry Andric if (Feature == "-mutable-globals") {
245*0fca6ea1SDimitry Andric HasMutableGlobals = false;
246*0fca6ea1SDimitry Andric continue;
247*0fca6ea1SDimitry Andric }
248*0fca6ea1SDimitry Andric if (Feature == "+nontrapping-fptoint") {
249*0fca6ea1SDimitry Andric HasNontrappingFPToInt = true;
250*0fca6ea1SDimitry Andric continue;
251*0fca6ea1SDimitry Andric }
252*0fca6ea1SDimitry Andric if (Feature == "-nontrapping-fptoint") {
253*0fca6ea1SDimitry Andric HasNontrappingFPToInt = false;
254*0fca6ea1SDimitry Andric continue;
255*0fca6ea1SDimitry Andric }
256*0fca6ea1SDimitry Andric if (Feature == "+reference-types") {
257*0fca6ea1SDimitry Andric HasReferenceTypes = true;
258*0fca6ea1SDimitry Andric continue;
259*0fca6ea1SDimitry Andric }
260*0fca6ea1SDimitry Andric if (Feature == "-reference-types") {
261*0fca6ea1SDimitry Andric HasReferenceTypes = false;
262*0fca6ea1SDimitry Andric continue;
263*0fca6ea1SDimitry Andric }
264*0fca6ea1SDimitry Andric if (Feature == "+relaxed-simd") {
265*0fca6ea1SDimitry Andric SIMDLevel = std::max(SIMDLevel, RelaxedSIMD);
266*0fca6ea1SDimitry Andric continue;
267*0fca6ea1SDimitry Andric }
268*0fca6ea1SDimitry Andric if (Feature == "-relaxed-simd") {
269*0fca6ea1SDimitry Andric SIMDLevel = std::min(SIMDLevel, SIMDEnum(RelaxedSIMD - 1));
270*0fca6ea1SDimitry Andric continue;
271*0fca6ea1SDimitry Andric }
272*0fca6ea1SDimitry Andric if (Feature == "+sign-ext") {
273*0fca6ea1SDimitry Andric HasSignExt = true;
274*0fca6ea1SDimitry Andric continue;
275*0fca6ea1SDimitry Andric }
276*0fca6ea1SDimitry Andric if (Feature == "-sign-ext") {
277*0fca6ea1SDimitry Andric HasSignExt = false;
278*0fca6ea1SDimitry Andric continue;
279*0fca6ea1SDimitry Andric }
280*0fca6ea1SDimitry Andric if (Feature == "+simd128") {
281*0fca6ea1SDimitry Andric SIMDLevel = std::max(SIMDLevel, SIMD128);
282*0fca6ea1SDimitry Andric continue;
283*0fca6ea1SDimitry Andric }
284*0fca6ea1SDimitry Andric if (Feature == "-simd128") {
285*0fca6ea1SDimitry Andric SIMDLevel = std::min(SIMDLevel, SIMDEnum(SIMD128 - 1));
286*0fca6ea1SDimitry Andric continue;
287*0fca6ea1SDimitry Andric }
288*0fca6ea1SDimitry Andric if (Feature == "+tail-call") {
289*0fca6ea1SDimitry Andric HasTailCall = true;
290*0fca6ea1SDimitry Andric continue;
291*0fca6ea1SDimitry Andric }
292*0fca6ea1SDimitry Andric if (Feature == "-tail-call") {
293*0fca6ea1SDimitry Andric HasTailCall = false;
294*0fca6ea1SDimitry Andric continue;
295*0fca6ea1SDimitry Andric }
2960b57cec5SDimitry Andric
2970b57cec5SDimitry Andric Diags.Report(diag::err_opt_not_valid_with_opt)
2980b57cec5SDimitry Andric << Feature << "-target-feature";
2990b57cec5SDimitry Andric return false;
3000b57cec5SDimitry Andric }
3010b57cec5SDimitry Andric return true;
3020b57cec5SDimitry Andric }
3030b57cec5SDimitry Andric
getTargetBuiltins() const3040b57cec5SDimitry Andric ArrayRef<Builtin::Info> WebAssemblyTargetInfo::getTargetBuiltins() const {
305bdd1243dSDimitry Andric return llvm::ArrayRef(BuiltinInfo, clang::WebAssembly::LastTSBuiltin -
3060b57cec5SDimitry Andric Builtin::FirstTSBuiltin);
3070b57cec5SDimitry Andric }
3080b57cec5SDimitry Andric
adjust(DiagnosticsEngine & Diags,LangOptions & Opts)309fe6060f1SDimitry Andric void WebAssemblyTargetInfo::adjust(DiagnosticsEngine &Diags,
310fe6060f1SDimitry Andric LangOptions &Opts) {
31181ad6265SDimitry Andric TargetInfo::adjust(Diags, Opts);
31281ad6265SDimitry Andric // Turn off POSIXThreads and ThreadModel so that we don't predefine _REENTRANT
31381ad6265SDimitry Andric // or __STDCPP_THREADS__ if we will eventually end up stripping atomics
31481ad6265SDimitry Andric // because they are unsupported.
31581ad6265SDimitry Andric if (!HasAtomics || !HasBulkMemory) {
316fe6060f1SDimitry Andric Opts.POSIXThreads = false;
317fe6060f1SDimitry Andric Opts.setThreadModel(LangOptions::ThreadModelKind::Single);
3181fd87a68SDimitry Andric Opts.ThreadsafeStatics = false;
319fe6060f1SDimitry Andric }
320fe6060f1SDimitry Andric }
321fe6060f1SDimitry Andric
getTargetDefines(const LangOptions & Opts,MacroBuilder & Builder) const3220b57cec5SDimitry Andric void WebAssembly32TargetInfo::getTargetDefines(const LangOptions &Opts,
3230b57cec5SDimitry Andric MacroBuilder &Builder) const {
3240b57cec5SDimitry Andric WebAssemblyTargetInfo::getTargetDefines(Opts, Builder);
3250b57cec5SDimitry Andric defineCPUMacros(Builder, "wasm32", /*Tuning=*/false);
3260b57cec5SDimitry Andric }
3270b57cec5SDimitry Andric
getTargetDefines(const LangOptions & Opts,MacroBuilder & Builder) const3280b57cec5SDimitry Andric void WebAssembly64TargetInfo::getTargetDefines(const LangOptions &Opts,
3290b57cec5SDimitry Andric MacroBuilder &Builder) const {
3300b57cec5SDimitry Andric WebAssemblyTargetInfo::getTargetDefines(Opts, Builder);
3310b57cec5SDimitry Andric defineCPUMacros(Builder, "wasm64", /*Tuning=*/false);
3320b57cec5SDimitry Andric }
333