1*0b57cec5SDimitry Andric //===--- WebAssembly.cpp - Implement WebAssembly target feature support ---===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file implements WebAssembly TargetInfo objects. 10*0b57cec5SDimitry Andric // 11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 12*0b57cec5SDimitry Andric 13*0b57cec5SDimitry Andric #include "WebAssembly.h" 14*0b57cec5SDimitry Andric #include "Targets.h" 15*0b57cec5SDimitry Andric #include "clang/Basic/Builtins.h" 16*0b57cec5SDimitry Andric #include "clang/Basic/Diagnostic.h" 17*0b57cec5SDimitry Andric #include "clang/Basic/TargetBuiltins.h" 18*0b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h" 19*0b57cec5SDimitry Andric 20*0b57cec5SDimitry Andric using namespace clang; 21*0b57cec5SDimitry Andric using namespace clang::targets; 22*0b57cec5SDimitry Andric 23*0b57cec5SDimitry Andric const Builtin::Info WebAssemblyTargetInfo::BuiltinInfo[] = { 24*0b57cec5SDimitry Andric #define BUILTIN(ID, TYPE, ATTRS) \ 25*0b57cec5SDimitry Andric {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, 26*0b57cec5SDimitry Andric #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ 27*0b57cec5SDimitry Andric {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, 28*0b57cec5SDimitry Andric #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ 29*0b57cec5SDimitry Andric {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, 30*0b57cec5SDimitry Andric #include "clang/Basic/BuiltinsWebAssembly.def" 31*0b57cec5SDimitry Andric }; 32*0b57cec5SDimitry Andric 33*0b57cec5SDimitry Andric static constexpr llvm::StringLiteral ValidCPUNames[] = { 34*0b57cec5SDimitry Andric {"mvp"}, {"bleeding-edge"}, {"generic"}}; 35*0b57cec5SDimitry Andric 36*0b57cec5SDimitry Andric bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const { 37*0b57cec5SDimitry Andric return llvm::StringSwitch<bool>(Feature) 38*0b57cec5SDimitry Andric .Case("simd128", SIMDLevel >= SIMD128) 39*0b57cec5SDimitry Andric .Case("unimplemented-simd128", SIMDLevel >= UnimplementedSIMD128) 40*0b57cec5SDimitry Andric .Case("nontrapping-fptoint", HasNontrappingFPToInt) 41*0b57cec5SDimitry Andric .Case("sign-ext", HasSignExt) 42*0b57cec5SDimitry Andric .Case("exception-handling", HasExceptionHandling) 43*0b57cec5SDimitry Andric .Case("bulk-memory", HasBulkMemory) 44*0b57cec5SDimitry Andric .Case("atomics", HasAtomics) 45*0b57cec5SDimitry Andric .Case("mutable-globals", HasMutableGlobals) 46*0b57cec5SDimitry Andric .Case("multivalue", HasMultivalue) 47*0b57cec5SDimitry Andric .Case("tail-call", HasTailCall) 48*0b57cec5SDimitry Andric .Default(false); 49*0b57cec5SDimitry Andric } 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric bool WebAssemblyTargetInfo::isValidCPUName(StringRef Name) const { 52*0b57cec5SDimitry Andric return llvm::find(ValidCPUNames, Name) != std::end(ValidCPUNames); 53*0b57cec5SDimitry Andric } 54*0b57cec5SDimitry Andric 55*0b57cec5SDimitry Andric void WebAssemblyTargetInfo::fillValidCPUList( 56*0b57cec5SDimitry Andric SmallVectorImpl<StringRef> &Values) const { 57*0b57cec5SDimitry Andric Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames)); 58*0b57cec5SDimitry Andric } 59*0b57cec5SDimitry Andric 60*0b57cec5SDimitry Andric void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts, 61*0b57cec5SDimitry Andric MacroBuilder &Builder) const { 62*0b57cec5SDimitry Andric defineCPUMacros(Builder, "wasm", /*Tuning=*/false); 63*0b57cec5SDimitry Andric if (SIMDLevel >= SIMD128) 64*0b57cec5SDimitry Andric Builder.defineMacro("__wasm_simd128__"); 65*0b57cec5SDimitry Andric if (SIMDLevel >= UnimplementedSIMD128) 66*0b57cec5SDimitry Andric Builder.defineMacro("__wasm_unimplemented_simd128__"); 67*0b57cec5SDimitry Andric if (HasNontrappingFPToInt) 68*0b57cec5SDimitry Andric Builder.defineMacro("__wasm_nontrapping_fptoint__"); 69*0b57cec5SDimitry Andric if (HasSignExt) 70*0b57cec5SDimitry Andric Builder.defineMacro("__wasm_sign_ext__"); 71*0b57cec5SDimitry Andric if (HasExceptionHandling) 72*0b57cec5SDimitry Andric Builder.defineMacro("__wasm_exception_handling__"); 73*0b57cec5SDimitry Andric if (HasBulkMemory) 74*0b57cec5SDimitry Andric Builder.defineMacro("__wasm_bulk_memory__"); 75*0b57cec5SDimitry Andric if (HasAtomics) 76*0b57cec5SDimitry Andric Builder.defineMacro("__wasm_atomics__"); 77*0b57cec5SDimitry Andric if (HasMutableGlobals) 78*0b57cec5SDimitry Andric Builder.defineMacro("__wasm_mutable_globals__"); 79*0b57cec5SDimitry Andric if (HasMultivalue) 80*0b57cec5SDimitry Andric Builder.defineMacro("__wasm_multivalue__"); 81*0b57cec5SDimitry Andric if (HasTailCall) 82*0b57cec5SDimitry Andric Builder.defineMacro("__wasm_tail_call__"); 83*0b57cec5SDimitry Andric } 84*0b57cec5SDimitry Andric 85*0b57cec5SDimitry Andric void WebAssemblyTargetInfo::setSIMDLevel(llvm::StringMap<bool> &Features, 86*0b57cec5SDimitry Andric SIMDEnum Level) { 87*0b57cec5SDimitry Andric switch (Level) { 88*0b57cec5SDimitry Andric case UnimplementedSIMD128: 89*0b57cec5SDimitry Andric Features["unimplemented-simd128"] = true; 90*0b57cec5SDimitry Andric LLVM_FALLTHROUGH; 91*0b57cec5SDimitry Andric case SIMD128: 92*0b57cec5SDimitry Andric Features["simd128"] = true; 93*0b57cec5SDimitry Andric LLVM_FALLTHROUGH; 94*0b57cec5SDimitry Andric case NoSIMD: 95*0b57cec5SDimitry Andric break; 96*0b57cec5SDimitry Andric } 97*0b57cec5SDimitry Andric } 98*0b57cec5SDimitry Andric 99*0b57cec5SDimitry Andric bool WebAssemblyTargetInfo::initFeatureMap( 100*0b57cec5SDimitry Andric llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, 101*0b57cec5SDimitry Andric const std::vector<std::string> &FeaturesVec) const { 102*0b57cec5SDimitry Andric if (CPU == "bleeding-edge") { 103*0b57cec5SDimitry Andric Features["nontrapping-fptoint"] = true; 104*0b57cec5SDimitry Andric Features["sign-ext"] = true; 105*0b57cec5SDimitry Andric Features["atomics"] = true; 106*0b57cec5SDimitry Andric Features["mutable-globals"] = true; 107*0b57cec5SDimitry Andric setSIMDLevel(Features, SIMD128); 108*0b57cec5SDimitry Andric } 109*0b57cec5SDimitry Andric // Other targets do not consider user-configured features here, but while we 110*0b57cec5SDimitry Andric // are actively developing new features it is useful to let user-configured 111*0b57cec5SDimitry Andric // features control availability of builtins 112*0b57cec5SDimitry Andric setSIMDLevel(Features, SIMDLevel); 113*0b57cec5SDimitry Andric if (HasNontrappingFPToInt) 114*0b57cec5SDimitry Andric Features["nontrapping-fptoint"] = true; 115*0b57cec5SDimitry Andric if (HasSignExt) 116*0b57cec5SDimitry Andric Features["sign-ext"] = true; 117*0b57cec5SDimitry Andric if (HasExceptionHandling) 118*0b57cec5SDimitry Andric Features["exception-handling"] = true; 119*0b57cec5SDimitry Andric if (HasBulkMemory) 120*0b57cec5SDimitry Andric Features["bulk-memory"] = true; 121*0b57cec5SDimitry Andric if (HasAtomics) 122*0b57cec5SDimitry Andric Features["atomics"] = true; 123*0b57cec5SDimitry Andric if (HasMutableGlobals) 124*0b57cec5SDimitry Andric Features["mutable-globals"] = true; 125*0b57cec5SDimitry Andric if (HasMultivalue) 126*0b57cec5SDimitry Andric Features["multivalue"] = true; 127*0b57cec5SDimitry Andric if (HasTailCall) 128*0b57cec5SDimitry Andric Features["tail-call"] = true; 129*0b57cec5SDimitry Andric 130*0b57cec5SDimitry Andric return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); 131*0b57cec5SDimitry Andric } 132*0b57cec5SDimitry Andric 133*0b57cec5SDimitry Andric bool WebAssemblyTargetInfo::handleTargetFeatures( 134*0b57cec5SDimitry Andric std::vector<std::string> &Features, DiagnosticsEngine &Diags) { 135*0b57cec5SDimitry Andric for (const auto &Feature : Features) { 136*0b57cec5SDimitry Andric if (Feature == "+simd128") { 137*0b57cec5SDimitry Andric SIMDLevel = std::max(SIMDLevel, SIMD128); 138*0b57cec5SDimitry Andric continue; 139*0b57cec5SDimitry Andric } 140*0b57cec5SDimitry Andric if (Feature == "-simd128") { 141*0b57cec5SDimitry Andric SIMDLevel = std::min(SIMDLevel, SIMDEnum(SIMD128 - 1)); 142*0b57cec5SDimitry Andric continue; 143*0b57cec5SDimitry Andric } 144*0b57cec5SDimitry Andric if (Feature == "+unimplemented-simd128") { 145*0b57cec5SDimitry Andric SIMDLevel = std::max(SIMDLevel, SIMDEnum(UnimplementedSIMD128)); 146*0b57cec5SDimitry Andric continue; 147*0b57cec5SDimitry Andric } 148*0b57cec5SDimitry Andric if (Feature == "-unimplemented-simd128") { 149*0b57cec5SDimitry Andric SIMDLevel = std::min(SIMDLevel, SIMDEnum(UnimplementedSIMD128 - 1)); 150*0b57cec5SDimitry Andric continue; 151*0b57cec5SDimitry Andric } 152*0b57cec5SDimitry Andric if (Feature == "+nontrapping-fptoint") { 153*0b57cec5SDimitry Andric HasNontrappingFPToInt = true; 154*0b57cec5SDimitry Andric continue; 155*0b57cec5SDimitry Andric } 156*0b57cec5SDimitry Andric if (Feature == "-nontrapping-fptoint") { 157*0b57cec5SDimitry Andric HasNontrappingFPToInt = false; 158*0b57cec5SDimitry Andric continue; 159*0b57cec5SDimitry Andric } 160*0b57cec5SDimitry Andric if (Feature == "+sign-ext") { 161*0b57cec5SDimitry Andric HasSignExt = true; 162*0b57cec5SDimitry Andric continue; 163*0b57cec5SDimitry Andric } 164*0b57cec5SDimitry Andric if (Feature == "-sign-ext") { 165*0b57cec5SDimitry Andric HasSignExt = false; 166*0b57cec5SDimitry Andric continue; 167*0b57cec5SDimitry Andric } 168*0b57cec5SDimitry Andric if (Feature == "+exception-handling") { 169*0b57cec5SDimitry Andric HasExceptionHandling = true; 170*0b57cec5SDimitry Andric continue; 171*0b57cec5SDimitry Andric } 172*0b57cec5SDimitry Andric if (Feature == "-exception-handling") { 173*0b57cec5SDimitry Andric HasExceptionHandling = false; 174*0b57cec5SDimitry Andric continue; 175*0b57cec5SDimitry Andric } 176*0b57cec5SDimitry Andric if (Feature == "+bulk-memory") { 177*0b57cec5SDimitry Andric HasBulkMemory = true; 178*0b57cec5SDimitry Andric continue; 179*0b57cec5SDimitry Andric } 180*0b57cec5SDimitry Andric if (Feature == "-bulk-memory") { 181*0b57cec5SDimitry Andric HasBulkMemory = false; 182*0b57cec5SDimitry Andric continue; 183*0b57cec5SDimitry Andric } 184*0b57cec5SDimitry Andric if (Feature == "+atomics") { 185*0b57cec5SDimitry Andric HasAtomics = true; 186*0b57cec5SDimitry Andric continue; 187*0b57cec5SDimitry Andric } 188*0b57cec5SDimitry Andric if (Feature == "-atomics") { 189*0b57cec5SDimitry Andric HasAtomics = false; 190*0b57cec5SDimitry Andric continue; 191*0b57cec5SDimitry Andric } 192*0b57cec5SDimitry Andric if (Feature == "+mutable-globals") { 193*0b57cec5SDimitry Andric HasMutableGlobals = true; 194*0b57cec5SDimitry Andric continue; 195*0b57cec5SDimitry Andric } 196*0b57cec5SDimitry Andric if (Feature == "-mutable-globals") { 197*0b57cec5SDimitry Andric HasMutableGlobals = false; 198*0b57cec5SDimitry Andric continue; 199*0b57cec5SDimitry Andric } 200*0b57cec5SDimitry Andric if (Feature == "+multivalue") { 201*0b57cec5SDimitry Andric HasMultivalue = true; 202*0b57cec5SDimitry Andric continue; 203*0b57cec5SDimitry Andric } 204*0b57cec5SDimitry Andric if (Feature == "-multivalue") { 205*0b57cec5SDimitry Andric HasMultivalue = false; 206*0b57cec5SDimitry Andric continue; 207*0b57cec5SDimitry Andric } 208*0b57cec5SDimitry Andric if (Feature == "+tail-call") { 209*0b57cec5SDimitry Andric HasTailCall = true; 210*0b57cec5SDimitry Andric continue; 211*0b57cec5SDimitry Andric } 212*0b57cec5SDimitry Andric if (Feature == "-tail-call") { 213*0b57cec5SDimitry Andric HasTailCall = false; 214*0b57cec5SDimitry Andric continue; 215*0b57cec5SDimitry Andric } 216*0b57cec5SDimitry Andric 217*0b57cec5SDimitry Andric Diags.Report(diag::err_opt_not_valid_with_opt) 218*0b57cec5SDimitry Andric << Feature << "-target-feature"; 219*0b57cec5SDimitry Andric return false; 220*0b57cec5SDimitry Andric } 221*0b57cec5SDimitry Andric return true; 222*0b57cec5SDimitry Andric } 223*0b57cec5SDimitry Andric 224*0b57cec5SDimitry Andric ArrayRef<Builtin::Info> WebAssemblyTargetInfo::getTargetBuiltins() const { 225*0b57cec5SDimitry Andric return llvm::makeArrayRef(BuiltinInfo, clang::WebAssembly::LastTSBuiltin - 226*0b57cec5SDimitry Andric Builtin::FirstTSBuiltin); 227*0b57cec5SDimitry Andric } 228*0b57cec5SDimitry Andric 229*0b57cec5SDimitry Andric void WebAssembly32TargetInfo::getTargetDefines(const LangOptions &Opts, 230*0b57cec5SDimitry Andric MacroBuilder &Builder) const { 231*0b57cec5SDimitry Andric WebAssemblyTargetInfo::getTargetDefines(Opts, Builder); 232*0b57cec5SDimitry Andric defineCPUMacros(Builder, "wasm32", /*Tuning=*/false); 233*0b57cec5SDimitry Andric } 234*0b57cec5SDimitry Andric 235*0b57cec5SDimitry Andric void WebAssembly64TargetInfo::getTargetDefines(const LangOptions &Opts, 236*0b57cec5SDimitry Andric MacroBuilder &Builder) const { 237*0b57cec5SDimitry Andric WebAssemblyTargetInfo::getTargetDefines(Opts, Builder); 238*0b57cec5SDimitry Andric defineCPUMacros(Builder, "wasm64", /*Tuning=*/false); 239*0b57cec5SDimitry Andric } 240