xref: /freebsd/contrib/llvm-project/clang/lib/Basic/Targets/WebAssembly.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
1 //===--- WebAssembly.cpp - Implement WebAssembly target feature support ---===//
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 // This file implements WebAssembly TargetInfo objects.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "WebAssembly.h"
14 #include "Targets.h"
15 #include "clang/Basic/Builtins.h"
16 #include "clang/Basic/Diagnostic.h"
17 #include "clang/Basic/TargetBuiltins.h"
18 #include "llvm/ADT/StringSwitch.h"
19 
20 using namespace clang;
21 using namespace clang::targets;
22 
23 static constexpr int NumBuiltins =
24     clang::WebAssembly::LastTSBuiltin - Builtin::FirstTSBuiltin;
25 
26 static constexpr llvm::StringTable BuiltinStrings =
27     CLANG_BUILTIN_STR_TABLE_START
28 #define BUILTIN CLANG_BUILTIN_STR_TABLE
29 #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE
30 #include "clang/Basic/BuiltinsWebAssembly.def"
31     ;
32 
33 static constexpr auto BuiltinInfos = Builtin::MakeInfos<NumBuiltins>({
34 #define BUILTIN CLANG_BUILTIN_ENTRY
35 #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY
36 #define LIBBUILTIN CLANG_LIBBUILTIN_ENTRY
37 #include "clang/Basic/BuiltinsWebAssembly.def"
38 });
39 
40 static constexpr llvm::StringLiteral ValidCPUNames[] = {
41     {"mvp"}, {"bleeding-edge"}, {"generic"}, {"lime1"}};
42 
43 StringRef WebAssemblyTargetInfo::getABI() const { return ABI; }
44 
45 bool WebAssemblyTargetInfo::setABI(const std::string &Name) {
46   if (Name != "mvp" && Name != "experimental-mv")
47     return false;
48 
49   ABI = Name;
50   return true;
51 }
52 
53 bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
54   return llvm::StringSwitch<bool>(Feature)
55       .Case("atomics", HasAtomics)
56       .Case("bulk-memory", HasBulkMemory)
57       .Case("bulk-memory-opt", HasBulkMemoryOpt)
58       .Case("call-indirect-overlong", HasCallIndirectOverlong)
59       .Case("exception-handling", HasExceptionHandling)
60       .Case("extended-const", HasExtendedConst)
61       .Case("fp16", HasFP16)
62       .Case("multimemory", HasMultiMemory)
63       .Case("multivalue", HasMultivalue)
64       .Case("mutable-globals", HasMutableGlobals)
65       .Case("nontrapping-fptoint", HasNontrappingFPToInt)
66       .Case("reference-types", HasReferenceTypes)
67       .Case("relaxed-simd", SIMDLevel >= RelaxedSIMD)
68       .Case("sign-ext", HasSignExt)
69       .Case("simd128", SIMDLevel >= SIMD128)
70       .Case("tail-call", HasTailCall)
71       .Case("wide-arithmetic", HasWideArithmetic)
72       .Default(false);
73 }
74 
75 bool WebAssemblyTargetInfo::isValidCPUName(StringRef Name) const {
76   return llvm::is_contained(ValidCPUNames, Name);
77 }
78 
79 void WebAssemblyTargetInfo::fillValidCPUList(
80     SmallVectorImpl<StringRef> &Values) const {
81   Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames));
82 }
83 
84 void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts,
85                                              MacroBuilder &Builder) const {
86   defineCPUMacros(Builder, "wasm", /*Tuning=*/false);
87   if (HasAtomics)
88     Builder.defineMacro("__wasm_atomics__");
89   if (HasBulkMemory)
90     Builder.defineMacro("__wasm_bulk_memory__");
91   if (HasBulkMemoryOpt)
92     Builder.defineMacro("__wasm_bulk_memory_opt__");
93   if (HasExceptionHandling)
94     Builder.defineMacro("__wasm_exception_handling__");
95   if (HasExtendedConst)
96     Builder.defineMacro("__wasm_extended_const__");
97   if (HasMultiMemory)
98     Builder.defineMacro("__wasm_multimemory__");
99   if (HasFP16)
100     Builder.defineMacro("__wasm_fp16__");
101   if (HasMultivalue)
102     Builder.defineMacro("__wasm_multivalue__");
103   if (HasMutableGlobals)
104     Builder.defineMacro("__wasm_mutable_globals__");
105   if (HasNontrappingFPToInt)
106     Builder.defineMacro("__wasm_nontrapping_fptoint__");
107   if (HasReferenceTypes)
108     Builder.defineMacro("__wasm_reference_types__");
109   if (SIMDLevel >= RelaxedSIMD)
110     Builder.defineMacro("__wasm_relaxed_simd__");
111   if (HasSignExt)
112     Builder.defineMacro("__wasm_sign_ext__");
113   if (SIMDLevel >= SIMD128)
114     Builder.defineMacro("__wasm_simd128__");
115   if (HasTailCall)
116     Builder.defineMacro("__wasm_tail_call__");
117   if (HasWideArithmetic)
118     Builder.defineMacro("__wasm_wide_arithmetic__");
119 
120   Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
121   Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
122   Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
123   Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
124 }
125 
126 void WebAssemblyTargetInfo::setSIMDLevel(llvm::StringMap<bool> &Features,
127                                          SIMDEnum Level, bool Enabled) {
128   if (Enabled) {
129     switch (Level) {
130     case RelaxedSIMD:
131       Features["relaxed-simd"] = true;
132       [[fallthrough]];
133     case SIMD128:
134       Features["simd128"] = true;
135       [[fallthrough]];
136     case NoSIMD:
137       break;
138     }
139     return;
140   }
141 
142   switch (Level) {
143   case NoSIMD:
144   case SIMD128:
145     Features["simd128"] = false;
146     [[fallthrough]];
147   case RelaxedSIMD:
148     Features["relaxed-simd"] = false;
149     break;
150   }
151 }
152 
153 void WebAssemblyTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
154                                               StringRef Name,
155                                               bool Enabled) const {
156   if (Name == "simd128")
157     setSIMDLevel(Features, SIMD128, Enabled);
158   else if (Name == "relaxed-simd")
159     setSIMDLevel(Features, RelaxedSIMD, Enabled);
160   else
161     Features[Name] = Enabled;
162 }
163 
164 bool WebAssemblyTargetInfo::initFeatureMap(
165     llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
166     const std::vector<std::string> &FeaturesVec) const {
167   auto addGenericFeatures = [&]() {
168     Features["bulk-memory"] = true;
169     Features["bulk-memory-opt"] = true;
170     Features["call-indirect-overlong"] = true;
171     Features["multivalue"] = true;
172     Features["mutable-globals"] = true;
173     Features["nontrapping-fptoint"] = true;
174     Features["reference-types"] = true;
175     Features["sign-ext"] = true;
176   };
177   auto addLime1Features = [&]() {
178     // Lime1:
179     // <https://github.com/WebAssembly/tool-conventions/blob/main/Lime.md#lime1>
180     Features["bulk-memory-opt"] = true;
181     Features["call-indirect-overlong"] = true;
182     Features["extended-const"] = true;
183     Features["multivalue"] = true;
184     Features["mutable-globals"] = true;
185     Features["nontrapping-fptoint"] = true;
186     Features["sign-ext"] = true;
187   };
188   auto addBleedingEdgeFeatures = [&]() {
189     addGenericFeatures();
190     Features["atomics"] = true;
191     Features["exception-handling"] = true;
192     Features["extended-const"] = true;
193     Features["fp16"] = true;
194     Features["multimemory"] = true;
195     Features["tail-call"] = true;
196     Features["wide-arithmetic"] = true;
197     setSIMDLevel(Features, RelaxedSIMD, true);
198   };
199   if (CPU == "generic") {
200     addGenericFeatures();
201   } else if (CPU == "lime1") {
202     addLime1Features();
203   } else if (CPU == "bleeding-edge") {
204     addBleedingEdgeFeatures();
205   }
206 
207   return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
208 }
209 
210 bool WebAssemblyTargetInfo::handleTargetFeatures(
211     std::vector<std::string> &Features, DiagnosticsEngine &Diags) {
212   for (const auto &Feature : Features) {
213     if (Feature == "+atomics") {
214       HasAtomics = true;
215       continue;
216     }
217     if (Feature == "-atomics") {
218       HasAtomics = false;
219       continue;
220     }
221     if (Feature == "+bulk-memory") {
222       HasBulkMemory = true;
223       continue;
224     }
225     if (Feature == "-bulk-memory") {
226       HasBulkMemory = false;
227       continue;
228     }
229     if (Feature == "+bulk-memory-opt") {
230       HasBulkMemoryOpt = true;
231       continue;
232     }
233     if (Feature == "-bulk-memory-opt") {
234       HasBulkMemoryOpt = false;
235       continue;
236     }
237     if (Feature == "+call-indirect-overlong") {
238       HasCallIndirectOverlong = true;
239       continue;
240     }
241     if (Feature == "-call-indirect-overlong") {
242       HasCallIndirectOverlong = false;
243       continue;
244     }
245     if (Feature == "+exception-handling") {
246       HasExceptionHandling = true;
247       continue;
248     }
249     if (Feature == "-exception-handling") {
250       HasExceptionHandling = false;
251       continue;
252     }
253     if (Feature == "+extended-const") {
254       HasExtendedConst = true;
255       continue;
256     }
257     if (Feature == "-extended-const") {
258       HasExtendedConst = false;
259       continue;
260     }
261     if (Feature == "+fp16") {
262       SIMDLevel = std::max(SIMDLevel, SIMD128);
263       HasFP16 = true;
264       continue;
265     }
266     if (Feature == "-fp16") {
267       HasFP16 = false;
268       continue;
269     }
270     if (Feature == "+multimemory") {
271       HasMultiMemory = true;
272       continue;
273     }
274     if (Feature == "-multimemory") {
275       HasMultiMemory = false;
276       continue;
277     }
278     if (Feature == "+multivalue") {
279       HasMultivalue = true;
280       continue;
281     }
282     if (Feature == "-multivalue") {
283       HasMultivalue = false;
284       continue;
285     }
286     if (Feature == "+mutable-globals") {
287       HasMutableGlobals = true;
288       continue;
289     }
290     if (Feature == "-mutable-globals") {
291       HasMutableGlobals = false;
292       continue;
293     }
294     if (Feature == "+nontrapping-fptoint") {
295       HasNontrappingFPToInt = true;
296       continue;
297     }
298     if (Feature == "-nontrapping-fptoint") {
299       HasNontrappingFPToInt = false;
300       continue;
301     }
302     if (Feature == "+reference-types") {
303       HasReferenceTypes = true;
304       continue;
305     }
306     if (Feature == "-reference-types") {
307       HasReferenceTypes = false;
308       continue;
309     }
310     if (Feature == "+relaxed-simd") {
311       SIMDLevel = std::max(SIMDLevel, RelaxedSIMD);
312       continue;
313     }
314     if (Feature == "-relaxed-simd") {
315       SIMDLevel = std::min(SIMDLevel, SIMDEnum(RelaxedSIMD - 1));
316       continue;
317     }
318     if (Feature == "+sign-ext") {
319       HasSignExt = true;
320       continue;
321     }
322     if (Feature == "-sign-ext") {
323       HasSignExt = false;
324       continue;
325     }
326     if (Feature == "+simd128") {
327       SIMDLevel = std::max(SIMDLevel, SIMD128);
328       continue;
329     }
330     if (Feature == "-simd128") {
331       SIMDLevel = std::min(SIMDLevel, SIMDEnum(SIMD128 - 1));
332       continue;
333     }
334     if (Feature == "+tail-call") {
335       HasTailCall = true;
336       continue;
337     }
338     if (Feature == "-tail-call") {
339       HasTailCall = false;
340       continue;
341     }
342     if (Feature == "+wide-arithmetic") {
343       HasWideArithmetic = true;
344       continue;
345     }
346     if (Feature == "-wide-arithmetic") {
347       HasWideArithmetic = false;
348       continue;
349     }
350 
351     Diags.Report(diag::err_opt_not_valid_with_opt)
352         << Feature << "-target-feature";
353     return false;
354   }
355 
356   // bulk-memory-opt is a subset of bulk-memory.
357   if (HasBulkMemory) {
358     HasBulkMemoryOpt = true;
359   }
360 
361   // The reference-types feature included the change to `call_indirect`
362   // encodings to support overlong immediates.
363   if (HasReferenceTypes) {
364     HasCallIndirectOverlong = true;
365   }
366 
367   return true;
368 }
369 
370 llvm::SmallVector<Builtin::InfosShard>
371 WebAssemblyTargetInfo::getTargetBuiltins() const {
372   return {{&BuiltinStrings, BuiltinInfos}};
373 }
374 
375 void WebAssemblyTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts,
376                                    const TargetInfo *Aux) {
377   TargetInfo::adjust(Diags, Opts, Aux);
378   // Turn off POSIXThreads and ThreadModel so that we don't predefine _REENTRANT
379   // or __STDCPP_THREADS__ if we will eventually end up stripping atomics
380   // because they are unsupported.
381   if (!HasAtomics || !HasBulkMemory) {
382     Opts.POSIXThreads = false;
383     Opts.setThreadModel(LangOptions::ThreadModelKind::Single);
384     Opts.ThreadsafeStatics = false;
385   }
386 }
387 
388 void WebAssembly32TargetInfo::getTargetDefines(const LangOptions &Opts,
389                                                MacroBuilder &Builder) const {
390   WebAssemblyTargetInfo::getTargetDefines(Opts, Builder);
391   defineCPUMacros(Builder, "wasm32", /*Tuning=*/false);
392 }
393 
394 void WebAssembly64TargetInfo::getTargetDefines(const LangOptions &Opts,
395                                                MacroBuilder &Builder) const {
396   WebAssemblyTargetInfo::getTargetDefines(Opts, Builder);
397   defineCPUMacros(Builder, "wasm64", /*Tuning=*/false);
398 }
399