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