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