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 365ffd83dbSDimitry Andric StringRef WebAssemblyTargetInfo::getABI() const { return ABI; } 375ffd83dbSDimitry Andric 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 460b57cec5SDimitry 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 650b57cec5SDimitry Andric bool WebAssemblyTargetInfo::isValidCPUName(StringRef Name) const { 66349cc55cSDimitry Andric return llvm::is_contained(ValidCPUNames, Name); 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric void WebAssemblyTargetInfo::fillValidCPUList( 700b57cec5SDimitry Andric SmallVectorImpl<StringRef> &Values) const { 710b57cec5SDimitry Andric Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames)); 720b57cec5SDimitry Andric } 730b57cec5SDimitry Andric 740b57cec5SDimitry 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 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 13975b4d546SDimitry 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 1500b57cec5SDimitry 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 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 3040b57cec5SDimitry Andric ArrayRef<Builtin::Info> WebAssemblyTargetInfo::getTargetBuiltins() const { 305bdd1243dSDimitry Andric return llvm::ArrayRef(BuiltinInfo, clang::WebAssembly::LastTSBuiltin - 3060b57cec5SDimitry Andric Builtin::FirstTSBuiltin); 3070b57cec5SDimitry Andric } 3080b57cec5SDimitry Andric 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 3220b57cec5SDimitry 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 3280b57cec5SDimitry 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