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