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 230b57cec5SDimitry Andric const Builtin::Info WebAssemblyTargetInfo::BuiltinInfo[] = { 240b57cec5SDimitry Andric #define BUILTIN(ID, TYPE, ATTRS) \ 250b57cec5SDimitry Andric {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, 260b57cec5SDimitry Andric #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ 270b57cec5SDimitry Andric {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, 280b57cec5SDimitry Andric #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ 290b57cec5SDimitry Andric {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, 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("simd128", SIMDLevel >= SIMD128) 490b57cec5SDimitry Andric .Case("unimplemented-simd128", SIMDLevel >= UnimplementedSIMD128) 500b57cec5SDimitry Andric .Case("nontrapping-fptoint", HasNontrappingFPToInt) 510b57cec5SDimitry Andric .Case("sign-ext", HasSignExt) 520b57cec5SDimitry Andric .Case("exception-handling", HasExceptionHandling) 530b57cec5SDimitry Andric .Case("bulk-memory", HasBulkMemory) 540b57cec5SDimitry Andric .Case("atomics", HasAtomics) 550b57cec5SDimitry Andric .Case("mutable-globals", HasMutableGlobals) 560b57cec5SDimitry Andric .Case("multivalue", HasMultivalue) 570b57cec5SDimitry Andric .Case("tail-call", HasTailCall) 585ffd83dbSDimitry Andric .Case("reference-types", HasReferenceTypes) 590b57cec5SDimitry Andric .Default(false); 600b57cec5SDimitry Andric } 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric bool WebAssemblyTargetInfo::isValidCPUName(StringRef Name) const { 630b57cec5SDimitry Andric return llvm::find(ValidCPUNames, Name) != std::end(ValidCPUNames); 640b57cec5SDimitry Andric } 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric void WebAssemblyTargetInfo::fillValidCPUList( 670b57cec5SDimitry Andric SmallVectorImpl<StringRef> &Values) const { 680b57cec5SDimitry Andric Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames)); 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts, 720b57cec5SDimitry Andric MacroBuilder &Builder) const { 730b57cec5SDimitry Andric defineCPUMacros(Builder, "wasm", /*Tuning=*/false); 740b57cec5SDimitry Andric if (SIMDLevel >= SIMD128) 750b57cec5SDimitry Andric Builder.defineMacro("__wasm_simd128__"); 760b57cec5SDimitry Andric if (SIMDLevel >= UnimplementedSIMD128) 770b57cec5SDimitry Andric Builder.defineMacro("__wasm_unimplemented_simd128__"); 780b57cec5SDimitry Andric if (HasNontrappingFPToInt) 790b57cec5SDimitry Andric Builder.defineMacro("__wasm_nontrapping_fptoint__"); 800b57cec5SDimitry Andric if (HasSignExt) 810b57cec5SDimitry Andric Builder.defineMacro("__wasm_sign_ext__"); 820b57cec5SDimitry Andric if (HasExceptionHandling) 830b57cec5SDimitry Andric Builder.defineMacro("__wasm_exception_handling__"); 840b57cec5SDimitry Andric if (HasBulkMemory) 850b57cec5SDimitry Andric Builder.defineMacro("__wasm_bulk_memory__"); 860b57cec5SDimitry Andric if (HasAtomics) 870b57cec5SDimitry Andric Builder.defineMacro("__wasm_atomics__"); 880b57cec5SDimitry Andric if (HasMutableGlobals) 890b57cec5SDimitry Andric Builder.defineMacro("__wasm_mutable_globals__"); 900b57cec5SDimitry Andric if (HasMultivalue) 910b57cec5SDimitry Andric Builder.defineMacro("__wasm_multivalue__"); 920b57cec5SDimitry Andric if (HasTailCall) 930b57cec5SDimitry Andric Builder.defineMacro("__wasm_tail_call__"); 945ffd83dbSDimitry Andric if (HasReferenceTypes) 955ffd83dbSDimitry Andric Builder.defineMacro("__wasm_reference_types__"); 960b57cec5SDimitry Andric } 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric void WebAssemblyTargetInfo::setSIMDLevel(llvm::StringMap<bool> &Features, 99*75b4d546SDimitry Andric SIMDEnum Level, bool Enabled) { 100*75b4d546SDimitry Andric if (Enabled) { 1010b57cec5SDimitry Andric switch (Level) { 1020b57cec5SDimitry Andric case UnimplementedSIMD128: 1030b57cec5SDimitry Andric Features["unimplemented-simd128"] = true; 1040b57cec5SDimitry Andric LLVM_FALLTHROUGH; 1050b57cec5SDimitry Andric case SIMD128: 1060b57cec5SDimitry Andric Features["simd128"] = true; 1070b57cec5SDimitry Andric LLVM_FALLTHROUGH; 1080b57cec5SDimitry Andric case NoSIMD: 1090b57cec5SDimitry Andric break; 1100b57cec5SDimitry Andric } 111*75b4d546SDimitry Andric return; 112*75b4d546SDimitry Andric } 113*75b4d546SDimitry Andric 114*75b4d546SDimitry Andric switch (Level) { 115*75b4d546SDimitry Andric case NoSIMD: 116*75b4d546SDimitry Andric case SIMD128: 117*75b4d546SDimitry Andric Features["simd128"] = false; 118*75b4d546SDimitry Andric LLVM_FALLTHROUGH; 119*75b4d546SDimitry Andric case UnimplementedSIMD128: 120*75b4d546SDimitry Andric Features["unimplemented-simd128"] = false; 121*75b4d546SDimitry Andric break; 122*75b4d546SDimitry Andric } 123*75b4d546SDimitry Andric } 124*75b4d546SDimitry Andric 125*75b4d546SDimitry Andric void WebAssemblyTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, 126*75b4d546SDimitry Andric StringRef Name, 127*75b4d546SDimitry Andric bool Enabled) const { 128*75b4d546SDimitry Andric if (Name == "simd128") 129*75b4d546SDimitry Andric setSIMDLevel(Features, SIMD128, Enabled); 130*75b4d546SDimitry Andric else if (Name == "unimplemented-simd128") 131*75b4d546SDimitry Andric setSIMDLevel(Features, UnimplementedSIMD128, Enabled); 132*75b4d546SDimitry Andric else 133*75b4d546SDimitry Andric Features[Name] = Enabled; 1340b57cec5SDimitry Andric } 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric bool WebAssemblyTargetInfo::initFeatureMap( 1370b57cec5SDimitry Andric llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, 1380b57cec5SDimitry Andric const std::vector<std::string> &FeaturesVec) const { 1390b57cec5SDimitry Andric if (CPU == "bleeding-edge") { 1400b57cec5SDimitry Andric Features["nontrapping-fptoint"] = true; 1410b57cec5SDimitry Andric Features["sign-ext"] = true; 1425ffd83dbSDimitry Andric Features["bulk-memory"] = true; 1430b57cec5SDimitry Andric Features["atomics"] = true; 1440b57cec5SDimitry Andric Features["mutable-globals"] = true; 1455ffd83dbSDimitry Andric Features["tail-call"] = true; 146*75b4d546SDimitry Andric setSIMDLevel(Features, SIMD128, true); 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric bool WebAssemblyTargetInfo::handleTargetFeatures( 1530b57cec5SDimitry Andric std::vector<std::string> &Features, DiagnosticsEngine &Diags) { 1540b57cec5SDimitry Andric for (const auto &Feature : Features) { 1550b57cec5SDimitry Andric if (Feature == "+simd128") { 1560b57cec5SDimitry Andric SIMDLevel = std::max(SIMDLevel, SIMD128); 1570b57cec5SDimitry Andric continue; 1580b57cec5SDimitry Andric } 1590b57cec5SDimitry Andric if (Feature == "-simd128") { 1600b57cec5SDimitry Andric SIMDLevel = std::min(SIMDLevel, SIMDEnum(SIMD128 - 1)); 1610b57cec5SDimitry Andric continue; 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric if (Feature == "+unimplemented-simd128") { 1640b57cec5SDimitry Andric SIMDLevel = std::max(SIMDLevel, SIMDEnum(UnimplementedSIMD128)); 1650b57cec5SDimitry Andric continue; 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric if (Feature == "-unimplemented-simd128") { 1680b57cec5SDimitry Andric SIMDLevel = std::min(SIMDLevel, SIMDEnum(UnimplementedSIMD128 - 1)); 1690b57cec5SDimitry Andric continue; 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric if (Feature == "+nontrapping-fptoint") { 1720b57cec5SDimitry Andric HasNontrappingFPToInt = true; 1730b57cec5SDimitry Andric continue; 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric if (Feature == "-nontrapping-fptoint") { 1760b57cec5SDimitry Andric HasNontrappingFPToInt = false; 1770b57cec5SDimitry Andric continue; 1780b57cec5SDimitry Andric } 1790b57cec5SDimitry Andric if (Feature == "+sign-ext") { 1800b57cec5SDimitry Andric HasSignExt = true; 1810b57cec5SDimitry Andric continue; 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric if (Feature == "-sign-ext") { 1840b57cec5SDimitry Andric HasSignExt = false; 1850b57cec5SDimitry Andric continue; 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric if (Feature == "+exception-handling") { 1880b57cec5SDimitry Andric HasExceptionHandling = true; 1890b57cec5SDimitry Andric continue; 1900b57cec5SDimitry Andric } 1910b57cec5SDimitry Andric if (Feature == "-exception-handling") { 1920b57cec5SDimitry Andric HasExceptionHandling = false; 1930b57cec5SDimitry Andric continue; 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric if (Feature == "+bulk-memory") { 1960b57cec5SDimitry Andric HasBulkMemory = true; 1970b57cec5SDimitry Andric continue; 1980b57cec5SDimitry Andric } 1990b57cec5SDimitry Andric if (Feature == "-bulk-memory") { 2000b57cec5SDimitry Andric HasBulkMemory = false; 2010b57cec5SDimitry Andric continue; 2020b57cec5SDimitry Andric } 2030b57cec5SDimitry Andric if (Feature == "+atomics") { 2040b57cec5SDimitry Andric HasAtomics = true; 2050b57cec5SDimitry Andric continue; 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric if (Feature == "-atomics") { 2080b57cec5SDimitry Andric HasAtomics = false; 2090b57cec5SDimitry Andric continue; 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric if (Feature == "+mutable-globals") { 2120b57cec5SDimitry Andric HasMutableGlobals = true; 2130b57cec5SDimitry Andric continue; 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric if (Feature == "-mutable-globals") { 2160b57cec5SDimitry Andric HasMutableGlobals = false; 2170b57cec5SDimitry Andric continue; 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric if (Feature == "+multivalue") { 2200b57cec5SDimitry Andric HasMultivalue = true; 2210b57cec5SDimitry Andric continue; 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric if (Feature == "-multivalue") { 2240b57cec5SDimitry Andric HasMultivalue = false; 2250b57cec5SDimitry Andric continue; 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric if (Feature == "+tail-call") { 2280b57cec5SDimitry Andric HasTailCall = true; 2290b57cec5SDimitry Andric continue; 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric if (Feature == "-tail-call") { 2320b57cec5SDimitry Andric HasTailCall = false; 2330b57cec5SDimitry Andric continue; 2340b57cec5SDimitry Andric } 2355ffd83dbSDimitry Andric if (Feature == "+reference-types") { 2365ffd83dbSDimitry Andric HasReferenceTypes = true; 2375ffd83dbSDimitry Andric continue; 2385ffd83dbSDimitry Andric } 2395ffd83dbSDimitry Andric if (Feature == "-reference-types") { 2405ffd83dbSDimitry Andric HasReferenceTypes = false; 2415ffd83dbSDimitry Andric continue; 2425ffd83dbSDimitry Andric } 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric Diags.Report(diag::err_opt_not_valid_with_opt) 2450b57cec5SDimitry Andric << Feature << "-target-feature"; 2460b57cec5SDimitry Andric return false; 2470b57cec5SDimitry Andric } 2480b57cec5SDimitry Andric return true; 2490b57cec5SDimitry Andric } 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric ArrayRef<Builtin::Info> WebAssemblyTargetInfo::getTargetBuiltins() const { 2520b57cec5SDimitry Andric return llvm::makeArrayRef(BuiltinInfo, clang::WebAssembly::LastTSBuiltin - 2530b57cec5SDimitry Andric Builtin::FirstTSBuiltin); 2540b57cec5SDimitry Andric } 2550b57cec5SDimitry Andric 2560b57cec5SDimitry Andric void WebAssembly32TargetInfo::getTargetDefines(const LangOptions &Opts, 2570b57cec5SDimitry Andric MacroBuilder &Builder) const { 2580b57cec5SDimitry Andric WebAssemblyTargetInfo::getTargetDefines(Opts, Builder); 2590b57cec5SDimitry Andric defineCPUMacros(Builder, "wasm32", /*Tuning=*/false); 2600b57cec5SDimitry Andric } 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric void WebAssembly64TargetInfo::getTargetDefines(const LangOptions &Opts, 2630b57cec5SDimitry Andric MacroBuilder &Builder) const { 2640b57cec5SDimitry Andric WebAssemblyTargetInfo::getTargetDefines(Opts, Builder); 2650b57cec5SDimitry Andric defineCPUMacros(Builder, "wasm64", /*Tuning=*/false); 2660b57cec5SDimitry Andric } 267