https://github.com/TartanLlama created https://github.com/llvm/llvm-project/pull/175800
(Currently in draft, as this will evolve alongside other toolchain component updates) The [WebAssembly Component Model](https://component-model.bytecodealliance.org/) has added support for [cooperative multithreading](https://github.com/WebAssembly/component-model/pull/557). This has been implemented in the [Wasmtime engine](https://github.com/bytecodealliance/wasmtime/pull/11751) and is part of the wider project of [WASI preview 3](https://wasi.dev/roadmap#upcoming-wasi-03-releases), which is currently tracked [here](https://github.com/orgs/bytecodealliance/projects/16). These changes will require updating the way that `__stack_pointer` and `__tls_base` work purely for a new `wasm32-wasip3` target; other targets will not be touched. Specifically, rather than using a Wasm global for tracking the stack pointer and TLS base, the new [`context.get/set`](https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#-canon-contextget) component model builtin functions will be used (the intention being that runtimes will need to aggressively optimize these calls into single load/stores). For justification on this choice rather than switching out the global at context-switch boundaries, see [this comment](https://github.com/WebAssembly/wasi-libc/issues/691#issuecomment-3716405618) and [this comment](https://github.com/WebAssembly/wasi-libc/issues/691#issuecomment-3716916730). >From 48a90dd7e288ad6c3ce8038c5b2d143dcc1dac34 Mon Sep 17 00:00:00 2001 From: Sy Brand <[email protected]> Date: Mon, 5 Jan 2026 14:43:56 +0000 Subject: [PATCH 1/2] Initial work --- clang/lib/Driver/ToolChains/WebAssembly.cpp | 33 ++- lld/wasm/Config.h | 10 + lld/wasm/Driver.cpp | 66 +++-- lld/wasm/Symbols.cpp | 8 +- lld/wasm/SyntheticSections.cpp | 11 +- lld/wasm/Writer.cpp | 27 +- lld/wasm/WriterUtils.cpp | 24 +- lld/wasm/WriterUtils.h | 4 + llvm/include/llvm/MC/MCSymbolWasm.h | 8 +- .../AsmParser/WebAssemblyAsmParser.cpp | 22 +- .../MCTargetDesc/WebAssemblyMCTargetDesc.h | 242 +++++++++--------- .../WebAssembly/WebAssemblyAsmPrinter.cpp | 31 ++- .../WebAssembly/WebAssemblyFrameLowering.cpp | 53 ++-- .../WebAssembly/WebAssemblyFrameLowering.h | 6 +- .../WebAssembly/WebAssemblyISelDAGToDAG.cpp | 6 +- .../WebAssembly/WebAssemblyISelLowering.cpp | 21 +- .../WebAssembly/WebAssemblyLateEHPrepare.cpp | 2 +- .../WebAssembly/WebAssemblyUtilities.cpp | 18 ++ .../Target/WebAssembly/WebAssemblyUtilities.h | 9 + 19 files changed, 372 insertions(+), 229 deletions(-) diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 15c6f19e87fee..d6ff6584258d2 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -30,13 +30,14 @@ using namespace llvm::opt; std::string WebAssembly::getMultiarchTriple(const Driver &D, const llvm::Triple &TargetTriple, StringRef SysRoot) const { - return (TargetTriple.getArchName() + "-" + - TargetTriple.getOSAndEnvironmentName()).str(); + return (TargetTriple.getArchName() + "-" + + TargetTriple.getOSAndEnvironmentName()) + .str(); } std::string wasm::Linker::getLinkerPath(const ArgList &Args) const { const ToolChain &ToolChain = getToolChain(); - if (const Arg* A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { + if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { StringRef UseLinker = A->getValue(); if (!UseLinker.empty()) { if (llvm::sys::path::is_absolute(UseLinker) && @@ -79,6 +80,10 @@ static bool WantsPthread(const llvm::Triple &Triple, const ArgList &Args) { return WantsPthread; } +static bool WantsSharedMemory(const llvm::Triple &Triple, const ArgList &Args) { + return WantsPthread(Triple, Args) && !TargetBuildsComponents(Triple); +} + void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -90,10 +95,14 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, ArgStringList CmdArgs; CmdArgs.push_back("-m"); + std::string arch; if (ToolChain.getTriple().isArch64Bit()) - CmdArgs.push_back("wasm64"); + arch = "wasm64"; else - CmdArgs.push_back("wasm32"); + arch = "wasm32"; + if (ToolChain.getTriple().getOSName() == "wasip3") + arch += "-wasip3"; + CmdArgs.push_back(Args.MakeArgString(arch)); if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("--strip-all"); @@ -160,7 +169,7 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - if (WantsPthread(ToolChain.getTriple(), Args)) + if (WantsSharedMemory(ToolChain.getTriple(), Args)) CmdArgs.push_back("--shared-memory"); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { @@ -233,9 +242,9 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, /// Given a base library directory, append path components to form the /// LTO directory. static std::string AppendLTOLibDir(const std::string &Dir) { - // The version allows the path to be keyed to the specific version of - // LLVM in used, as the bitcode format is not stable. - return Dir + "/llvm-lto/" LLVM_VERSION_STRING; + // The version allows the path to be keyed to the specific version of + // LLVM in used, as the bitcode format is not stable. + return Dir + "/llvm-lto/" LLVM_VERSION_STRING; } WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, @@ -502,7 +511,8 @@ void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs, if (getTriple().getOS() != llvm::Triple::UnknownOS) { const std::string MultiarchTriple = getMultiarchTriple(D, getTriple(), D.SysRoot); - addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include/" + MultiarchTriple); + addSystemInclude(DriverArgs, CC1Args, + D.SysRoot + "/include/" + MultiarchTriple); } addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include"); } @@ -631,5 +641,6 @@ void WebAssembly::addLibStdCXXIncludePaths( // Second add the generic one. addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/" + Version); // Third the backward one. - addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/" + Version + "/backward"); + addSystemInclude(DriverArgs, CC1Args, + LibPath + "/c++/" + Version + "/backward"); } diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h index 9d903e0c799db..55dea0a78eadb 100644 --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -35,6 +35,7 @@ class Symbol; class DefinedData; class GlobalSymbol; class DefinedFunction; +class UndefinedFunction; class UndefinedGlobal; class TableSymbol; @@ -70,6 +71,7 @@ struct Config { bool importTable; bool importUndefined; std::optional<bool> is64; + bool isWasip3; bool mergeDataSegments; bool noinhibitExec; bool pie; @@ -248,6 +250,14 @@ struct Ctx { // Used as an address space for function pointers, with each function that // is used as a function pointer being allocated a slot. TableSymbol *indirectFunctionTable; + + // __wasm_component_model_builtin_context_set_1 + // Function used to set TLS base in component model modules. + UndefinedFunction *contextSet1; + + // __wasm_component_model_builtin_context_get_1 + // Function used to get TLS base in component model modules. + UndefinedFunction *contextGet1; }; WasmSym sym; diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index fac166587cb9b..79ecc6c9f5858 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -656,15 +656,16 @@ static void readConfigs(opt::InputArgList &args) { ctx.arg.exportDynamic = args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, ctx.arg.shared); - // Parse wasm32/64. + // Parse wasm32/64 and maybe -wasip3. if (auto *arg = args.getLastArg(OPT_m)) { StringRef s = arg->getValue(); - if (s == "wasm32") + if (s.starts_with("wasm32")) ctx.arg.is64 = false; - else if (s == "wasm64") + else if (s.starts_with("wasm64")) ctx.arg.is64 = true; else error("invalid target architecture: " + s); + ctx.arg.isWasip3 = s.ends_with("-wasip3"); } // --threads= takes a positive integer and provides the default value for @@ -827,6 +828,10 @@ static void checkOptions(opt::InputArgList &args) { if (ctx.arg.tableBase) error("--table-base may not be used with -shared/-pie"); } + + if (ctx.arg.sharedMemory && ctx.arg.isWasip3) { + error("--shared-memory is incompatible with the wasip3 target"); + } } static const char *getReproduceOption(opt::InputArgList &args) { @@ -885,7 +890,7 @@ static void writeWhyExtract() { // Equivalent of demote demoteSharedAndLazySymbols() in the ELF linker static void demoteLazySymbols() { for (Symbol *sym : symtab->symbols()) { - if (auto* s = dyn_cast<LazySymbol>(sym)) { + if (auto *s = dyn_cast<LazySymbol>(sym)) { if (s->signature) { LLVM_DEBUG(llvm::dbgs() << "demoting lazy func: " << s->getName() << "\n"); @@ -906,6 +911,18 @@ createUndefinedGlobal(StringRef name, llvm::wasm::WasmGlobalType *type) { return sym; } +static UndefinedFunction * +createUndefinedFunction(StringRef name, std::optional<StringRef> importName, + std::optional<StringRef> importModule, + WasmSignature *signature) { + auto *sym = cast<UndefinedFunction>(symtab->addUndefinedFunction( + name, importName, importModule, WASM_SYMBOL_UNDEFINED, nullptr, signature, + true)); + ctx.arg.allowUndefinedSymbols.insert(sym->getName()); + sym->isUsedInRegularObj = true; + return sym; +} + static InputGlobal *createGlobal(StringRef name, bool isMutable) { llvm::wasm::WasmGlobal wasmGlobal; bool is64 = ctx.arg.is64.value_or(false); @@ -946,11 +963,13 @@ static void createSyntheticSymbols() { bool is64 = ctx.arg.is64.value_or(false); + auto stack_pointer_name = + ctx.arg.isWasip3 ? "__init_stack_pointer" : "__stack_pointer"; if (ctx.isPic) { ctx.sym.stackPointer = - createUndefinedGlobal("__stack_pointer", ctx.arg.is64.value_or(false) - ? &mutableGlobalTypeI64 - : &mutableGlobalTypeI32); + createUndefinedGlobal(stack_pointer_name, ctx.arg.is64.value_or(false) + ? &mutableGlobalTypeI64 + : &mutableGlobalTypeI32); // For PIC code, we import two global variables (__memory_base and // __table_base) from the environment and use these as the offset at // which to load our static data and function table. @@ -963,14 +982,15 @@ static void createSyntheticSymbols() { ctx.sym.tableBase->markLive(); } else { // For non-PIC code - ctx.sym.stackPointer = createGlobalVariable("__stack_pointer", true); + ctx.sym.stackPointer = createGlobalVariable(stack_pointer_name, true); ctx.sym.stackPointer->markLive(); } - if (ctx.arg.sharedMemory) { + if (ctx.arg.sharedMemory || ctx.arg.isWasip3) { // TLS symbols are all hidden/dso-local - ctx.sym.tlsBase = - createGlobalVariable("__tls_base", true, WASM_SYMBOL_VISIBILITY_HIDDEN); + auto tls_base_name = ctx.arg.isWasip3 ? "__init_tls_base" : "__tls_base"; + ctx.sym.tlsBase = createGlobalVariable(tls_base_name, true, + WASM_SYMBOL_VISIBILITY_HIDDEN); ctx.sym.tlsSize = createGlobalVariable("__tls_size", false, WASM_SYMBOL_VISIBILITY_HIDDEN); ctx.sym.tlsAlign = createGlobalVariable("__tls_align", false, @@ -979,6 +999,16 @@ static void createSyntheticSymbols() { "__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN, make<SyntheticFunction>(is64 ? i64ArgSignature : i32ArgSignature, "__wasm_init_tls")); + static WasmSignature contextSet1Signature{{}, {ValType::I32}}; + ctx.sym.contextSet1 = createUndefinedFunction( + "__wasm_component_model_builtin_context_set_1", "[context-set-1]", + "$root", &contextSet1Signature); + ctx.sym.contextSet1->markLive(); + static WasmSignature contextGet1Signature{{ValType::I32}, {}}; + ctx.sym.contextGet1 = createUndefinedFunction( + "__wasm_component_model_builtin_context_get_1", "[context-get-1]", + "$root", &contextGet1Signature); + ctx.sym.contextGet1->markLive(); } } @@ -1014,7 +1044,7 @@ static void createOptionalSymbols() { // // __tls_size and __tls_align are not needed in this case since they are only // needed for __wasm_init_tls (which we do not create in this case). - if (!ctx.arg.sharedMemory) + if (!ctx.arg.sharedMemory && !ctx.arg.isWasip3) ctx.sym.tlsBase = createOptionalGlobal("__tls_base", false); } @@ -1023,15 +1053,15 @@ static void processStubLibrariesPreLTO() { for (auto &stub_file : ctx.stubFiles) { LLVM_DEBUG(llvm::dbgs() << "processing stub file: " << stub_file->getName() << "\n"); - for (auto [name, deps]: stub_file->symbolDependencies) { - auto* sym = symtab->find(name); + for (auto [name, deps] : stub_file->symbolDependencies) { + auto *sym = symtab->find(name); // If the symbol is not present at all (yet), or if it is present but // undefined, then mark the dependent symbols as used by a regular // object so they will be preserved and exported by the LTO process. if (!sym || sym->isUndefined()) { for (const auto dep : deps) { - auto* needed = symtab->find(dep); - if (needed ) { + auto *needed = symtab->find(dep); + if (needed) { needed->isUsedInRegularObj = true; // Like with handleLibcall we have to extract any LTO archive // members that might need to be exported due to stub library @@ -1103,8 +1133,8 @@ static void processStubLibraries() { // First look for any imported symbols that directly match // the names of the stub imports - for (auto [name, deps]: stub_file->symbolDependencies) { - auto* sym = symtab->find(name); + for (auto [name, deps] : stub_file->symbolDependencies) { + auto *sym = symtab->find(name); if (sym && sym->isUndefined()) { depsAdded |= addStubSymbolDeps(stub_file, sym, deps); } else { diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp index f2040441e6257..97a9871a06308 100644 --- a/lld/wasm/Symbols.cpp +++ b/lld/wasm/Symbols.cpp @@ -95,7 +95,7 @@ WasmSymbolType Symbol::getWasmType() const { } const WasmSignature *Symbol::getSignature() const { - if (auto* f = dyn_cast<FunctionSymbol>(this)) + if (auto *f = dyn_cast<FunctionSymbol>(this)) return f->signature; if (auto *t = dyn_cast<TagSymbol>(this)) return t->signature; @@ -223,9 +223,7 @@ bool Symbol::isExportedExplicit() const { return forceExport || flags & WASM_SYMBOL_EXPORTED; } -bool Symbol::isNoStrip() const { - return flags & WASM_SYMBOL_NO_STRIP; -} +bool Symbol::isNoStrip() const { return flags & WASM_SYMBOL_NO_STRIP; } uint32_t FunctionSymbol::getFunctionIndex() const { if (const auto *u = dyn_cast<UndefinedFunction>(this)) @@ -413,7 +411,7 @@ void LazySymbol::setWeak() { flags |= (flags & ~WASM_SYMBOL_BINDING_MASK) | WASM_SYMBOL_BINDING_WEAK; } -void printTraceSymbolUndefined(StringRef name, const InputFile* file) { +void printTraceSymbolUndefined(StringRef name, const InputFile *file) { message(toString(file) + ": reference to " + name); } diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index 399a5084e6595..0d3e060ac381e 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -434,8 +434,7 @@ void GlobalSection::addInternalGOTEntry(Symbol *sym) { void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const { assert(!ctx.arg.extendedConst); bool is64 = ctx.arg.is64.value_or(false); - unsigned opcode_ptr_add = is64 ? WASM_OPCODE_I64_ADD - : WASM_OPCODE_I32_ADD; + unsigned opcode_ptr_add = is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD; for (const Symbol *sym : internalGotSymbols) { if (TLS != sym->isTLS()) @@ -445,7 +444,7 @@ void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const { // Get __memory_base writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); if (sym->isTLS()) - writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "__tls_base"); + writeGetTLSBase(ctx, os); else writeUleb128(os, ctx.sym.memoryBase->getGlobalIndex(), "__memory_base"); @@ -614,7 +613,7 @@ void ElemSection::writeBody() { uint32_t tableIndex = ctx.arg.tableBase; for (const FunctionSymbol *sym : indirectFunctions) { assert(sym->getTableIndex() == tableIndex); - (void) tableIndex; + (void)tableIndex; writeUleb128(os, sym->getFunctionIndex(), "function index"); ++tableIndex; } @@ -631,7 +630,7 @@ void DataCountSection::writeBody() { } bool DataCountSection::isNeeded() const { - return numSegments && ctx.arg.sharedMemory; + return numSegments && (ctx.arg.sharedMemory || ctx.arg.isWasip3); } void LinkingSection::writeBody() { @@ -960,4 +959,4 @@ void BuildIdSection::writeBuildId(llvm::ArrayRef<uint8_t> buf) { memcpy(hashPlaceholderPtr, buf.data(), hashSize); } -} // namespace wasm::lld +} // namespace lld::wasm diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 9a5b56fc52e2f..12f72dc239a09 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -311,7 +311,8 @@ void Writer::writeBuildId() { } static void setGlobalPtr(DefinedGlobal *g, uint64_t memoryPtr) { - LLVM_DEBUG(dbgs() << "setGlobalPtr " << g->getName() << " -> " << memoryPtr << "\n"); + LLVM_DEBUG(dbgs() << "setGlobalPtr " << g->getName() << " -> " << memoryPtr + << "\n"); g->global->setPointerValue(memoryPtr); } @@ -358,7 +359,8 @@ void Writer::layoutMemory() { placeStack(); if (ctx.arg.globalBase) { if (ctx.arg.globalBase < memoryPtr) { - error("--global-base cannot be less than stack size when --stack-first is used"); + error("--global-base cannot be less than stack size when --stack-first " + "is used"); return; } memoryPtr = ctx.arg.globalBase; @@ -382,6 +384,7 @@ void Writer::layoutMemory() { for (OutputSegment *seg : segments) { out.dylinkSec->memAlign = std::max(out.dylinkSec->memAlign, seg->alignment); memoryPtr = alignTo(memoryPtr, 1ULL << seg->alignment); + seg->startVA = memoryPtr; log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", seg->name, memoryPtr, seg->size, seg->alignment)); @@ -1175,7 +1178,7 @@ void Writer::createSyntheticInitFunctions() { auto hasTLSRelocs = [](const OutputSegment *segment) { if (segment->isTLS()) - for (const auto* is: segment->inputSegments) + for (const auto *is : segment->inputSegments) if (is->getRelocations().size()) return true; return false; @@ -1350,8 +1353,7 @@ void Writer::createInitMemoryFunction() { } else { writePtrConst(os, s->startVA, is64, "destination address"); } - writeU8(os, WASM_OPCODE_GLOBAL_SET, "GLOBAL_SET"); - writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "__tls_base"); + writeSetTLSBase(ctx, os); if (ctx.isPic) { writeU8(os, WASM_OPCODE_LOCAL_GET, "local.tee"); writeUleb128(os, 1, "local 1"); @@ -1624,10 +1626,17 @@ void Writer::createInitTLSFunction() { writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); writeUleb128(os, 0, "local index"); - writeU8(os, WASM_OPCODE_GLOBAL_SET, "global.set"); - writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "global index"); + if (ctx.arg.isWasip3) { + writeU8(os, WASM_OPCODE_CALL, "call"); + writeUleb128(os, ctx.sym.contextSet1->getFunctionIndex(), + "function index"); + } else { + writeU8(os, WASM_OPCODE_GLOBAL_SET, "global.set"); + writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "global index"); + } - // FIXME(wvo): this local needs to be I64 in wasm64, or we need an extend op. + // FIXME(wvo): this local needs to be I64 in wasm64, or we need an + // extend op. writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); writeUleb128(os, 0, "local index"); @@ -1893,4 +1902,4 @@ void Writer::createHeader() { void writeResult() { Writer().run(); } -} // namespace wasm::lld +} // namespace lld::wasm diff --git a/lld/wasm/WriterUtils.cpp b/lld/wasm/WriterUtils.cpp index b78c354ffb97b..8e945f57ef39c 100644 --- a/lld/wasm/WriterUtils.cpp +++ b/lld/wasm/WriterUtils.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "WriterUtils.h" +#include "Config.h" +#include "Symbols.h" #include "lld/Common/ErrorHandler.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Debug.h" @@ -97,7 +99,7 @@ void writeSleb128(raw_ostream &os, int64_t number, const Twine &msg) { } void writeBytes(raw_ostream &os, const char *bytes, size_t count, - const Twine &msg) { + const Twine &msg) { debugWrite(os.tell(), msg + " [data[" + Twine(count) + "]]"); os.write(bytes, count); } @@ -266,5 +268,25 @@ void writeExport(raw_ostream &os, const WasmExport &export_) { } } +void writeGetTLSBase(const Ctx &ctx, raw_ostream &os) { + if (ctx.arg.isWasip3) { + writeU8(os, WASM_OPCODE_CALL, "call"); + writeUleb128(os, ctx.sym.contextGet1->getFunctionIndex(), "function index"); + } else { + writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_SET"); + writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "__tls_base"); + } +} + +void writeSetTLSBase(const Ctx &ctx, raw_ostream &os) { + if (ctx.arg.isWasip3) { + writeU8(os, WASM_OPCODE_CALL, "call"); + writeUleb128(os, ctx.sym.contextSet1->getFunctionIndex(), "function index"); + } else { + writeU8(os, WASM_OPCODE_GLOBAL_SET, "GLOBAL_SET"); + writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "__tls_base"); + } +} + } // namespace wasm } // namespace lld diff --git a/lld/wasm/WriterUtils.h b/lld/wasm/WriterUtils.h index 2be79d1d86e97..404c5c33ed7b6 100644 --- a/lld/wasm/WriterUtils.h +++ b/lld/wasm/WriterUtils.h @@ -64,6 +64,10 @@ void writeImport(raw_ostream &os, const llvm::wasm::WasmImport &import); void writeExport(raw_ostream &os, const llvm::wasm::WasmExport &export_); +struct Ctx; +void writeGetTLSBase(const Ctx &ctx, raw_ostream &os); +void writeSetTLSBase(const Ctx &ctx, raw_ostream &os); + } // namespace wasm std::string toString(llvm::wasm::ValType type); diff --git a/llvm/include/llvm/MC/MCSymbolWasm.h b/llvm/include/llvm/MC/MCSymbolWasm.h index 5c9f14e5e6d64..11cbce5b0ccd0 100644 --- a/llvm/include/llvm/MC/MCSymbolWasm.h +++ b/llvm/include/llvm/MC/MCSymbolWasm.h @@ -54,16 +54,12 @@ class MCSymbolWasm : public MCSymbol { void setType(wasm::WasmSymbolType type) { Type = type; } - bool isExported() const { - return getFlags() & wasm::WASM_SYMBOL_EXPORTED; - } + bool isExported() const { return getFlags() & wasm::WASM_SYMBOL_EXPORTED; } void setExported() const { modifyFlags(wasm::WASM_SYMBOL_EXPORTED, wasm::WASM_SYMBOL_EXPORTED); } - bool isNoStrip() const { - return getFlags() & wasm::WASM_SYMBOL_NO_STRIP; - } + bool isNoStrip() const { return getFlags() & wasm::WASM_SYMBOL_NO_STRIP; } void setNoStrip() const { modifyFlags(wasm::WASM_SYMBOL_NO_STRIP, wasm::WASM_SYMBOL_NO_STRIP); } diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp index 9175b2731dac0..25704c9ef0ac4 100644 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -415,6 +415,23 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser { return Name; } + StringRef expectStringOrIdent() { + if (Lexer.is(AsmToken::String)) { + auto Str = Lexer.getTok().getString(); + Parser.Lex(); + Str.consume_front("\""); + Str.consume_back("\""); + return Str; + } + if (Lexer.is(AsmToken::Identifier)) { + auto Name = Lexer.getTok().getString(); + Parser.Lex(); + llvm::outs() << "Parsed ident: " << Name << "\n"; + return Name; + } + error("Expected string or identifier, got: ", Lexer.getTok()); + } + bool parseRegTypeList(SmallVectorImpl<wasm::ValType> &Types) { while (Lexer.is(AsmToken::Identifier)) { auto Type = WebAssembly::parseType(Lexer.getTok().getString()); @@ -1057,7 +1074,8 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser { return ParseStatus::Failure; if (expect(AsmToken::Comma, ",")) return ParseStatus::Failure; - auto ImportModule = expectIdent(); + + StringRef ImportModule = expectStringOrIdent(); if (ImportModule.empty()) return ParseStatus::Failure; auto *WasmSym = @@ -1073,7 +1091,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser { return ParseStatus::Failure; if (expect(AsmToken::Comma, ",")) return ParseStatus::Failure; - auto ImportName = expectIdent(); + StringRef ImportName = expectStringOrIdent(); if (ImportName.empty()) return ParseStatus::Failure; auto *WasmSym = diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h index 5dc0e3aa91622..5c6d07ba88c61 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -146,128 +146,128 @@ static const unsigned End = 0x0b; /// Return the default p2align value for a load or store with the given opcode. inline unsigned GetDefaultP2AlignAny(unsigned Opc) { switch (Opc) { -#define WASM_LOAD_STORE(NAME) \ - case WebAssembly::NAME##_A32: \ - case WebAssembly::NAME##_A64: \ - case WebAssembly::NAME##_A32_S: \ +#define WASM_LOAD_STORE(NAME) \ + case WebAssembly::NAME##_A32: \ + case WebAssembly::NAME##_A64: \ + case WebAssembly::NAME##_A32_S: \ case WebAssembly::NAME##_A64_S: - WASM_LOAD_STORE(LOAD8_S_I32) - WASM_LOAD_STORE(LOAD8_U_I32) - WASM_LOAD_STORE(LOAD8_S_I64) - WASM_LOAD_STORE(LOAD8_U_I64) - WASM_LOAD_STORE(ATOMIC_LOAD8_U_I32) - WASM_LOAD_STORE(ATOMIC_LOAD8_U_I64) - WASM_LOAD_STORE(STORE8_I32) - WASM_LOAD_STORE(STORE8_I64) - WASM_LOAD_STORE(ATOMIC_STORE8_I32) - WASM_LOAD_STORE(ATOMIC_STORE8_I64) - WASM_LOAD_STORE(ATOMIC_RMW8_U_ADD_I32) - WASM_LOAD_STORE(ATOMIC_RMW8_U_ADD_I64) - WASM_LOAD_STORE(ATOMIC_RMW8_U_SUB_I32) - WASM_LOAD_STORE(ATOMIC_RMW8_U_SUB_I64) - WASM_LOAD_STORE(ATOMIC_RMW8_U_AND_I32) - WASM_LOAD_STORE(ATOMIC_RMW8_U_AND_I64) - WASM_LOAD_STORE(ATOMIC_RMW8_U_OR_I32) - WASM_LOAD_STORE(ATOMIC_RMW8_U_OR_I64) - WASM_LOAD_STORE(ATOMIC_RMW8_U_XOR_I32) - WASM_LOAD_STORE(ATOMIC_RMW8_U_XOR_I64) - WASM_LOAD_STORE(ATOMIC_RMW8_U_XCHG_I32) - WASM_LOAD_STORE(ATOMIC_RMW8_U_XCHG_I64) - WASM_LOAD_STORE(ATOMIC_RMW8_U_CMPXCHG_I32) - WASM_LOAD_STORE(ATOMIC_RMW8_U_CMPXCHG_I64) - WASM_LOAD_STORE(LOAD8_SPLAT) - WASM_LOAD_STORE(LOAD_LANE_8) - WASM_LOAD_STORE(STORE_LANE_I8x16) - return 0; - WASM_LOAD_STORE(LOAD16_S_I32) - WASM_LOAD_STORE(LOAD16_U_I32) - WASM_LOAD_STORE(LOAD16_S_I64) - WASM_LOAD_STORE(LOAD16_U_I64) - WASM_LOAD_STORE(ATOMIC_LOAD16_U_I32) - WASM_LOAD_STORE(ATOMIC_LOAD16_U_I64) - WASM_LOAD_STORE(STORE16_I32) - WASM_LOAD_STORE(STORE16_I64) - WASM_LOAD_STORE(ATOMIC_STORE16_I32) - WASM_LOAD_STORE(ATOMIC_STORE16_I64) - WASM_LOAD_STORE(ATOMIC_RMW16_U_ADD_I32) - WASM_LOAD_STORE(ATOMIC_RMW16_U_ADD_I64) - WASM_LOAD_STORE(ATOMIC_RMW16_U_SUB_I32) - WASM_LOAD_STORE(ATOMIC_RMW16_U_SUB_I64) - WASM_LOAD_STORE(ATOMIC_RMW16_U_AND_I32) - WASM_LOAD_STORE(ATOMIC_RMW16_U_AND_I64) - WASM_LOAD_STORE(ATOMIC_RMW16_U_OR_I32) - WASM_LOAD_STORE(ATOMIC_RMW16_U_OR_I64) - WASM_LOAD_STORE(ATOMIC_RMW16_U_XOR_I32) - WASM_LOAD_STORE(ATOMIC_RMW16_U_XOR_I64) - WASM_LOAD_STORE(ATOMIC_RMW16_U_XCHG_I32) - WASM_LOAD_STORE(ATOMIC_RMW16_U_XCHG_I64) - WASM_LOAD_STORE(ATOMIC_RMW16_U_CMPXCHG_I32) - WASM_LOAD_STORE(ATOMIC_RMW16_U_CMPXCHG_I64) - WASM_LOAD_STORE(LOAD16_SPLAT) - WASM_LOAD_STORE(LOAD_LANE_16) - WASM_LOAD_STORE(STORE_LANE_I16x8) - WASM_LOAD_STORE(LOAD_F16_F32) - WASM_LOAD_STORE(STORE_F16_F32) - return 1; - WASM_LOAD_STORE(LOAD_I32) - WASM_LOAD_STORE(LOAD_F32) - WASM_LOAD_STORE(STORE_I32) - WASM_LOAD_STORE(STORE_F32) - WASM_LOAD_STORE(LOAD32_S_I64) - WASM_LOAD_STORE(LOAD32_U_I64) - WASM_LOAD_STORE(STORE32_I64) - WASM_LOAD_STORE(ATOMIC_LOAD_I32) - WASM_LOAD_STORE(ATOMIC_LOAD32_U_I64) - WASM_LOAD_STORE(ATOMIC_STORE_I32) - WASM_LOAD_STORE(ATOMIC_STORE32_I64) - WASM_LOAD_STORE(ATOMIC_RMW_ADD_I32) - WASM_LOAD_STORE(ATOMIC_RMW32_U_ADD_I64) - WASM_LOAD_STORE(ATOMIC_RMW_SUB_I32) - WASM_LOAD_STORE(ATOMIC_RMW32_U_SUB_I64) - WASM_LOAD_STORE(ATOMIC_RMW_AND_I32) - WASM_LOAD_STORE(ATOMIC_RMW32_U_AND_I64) - WASM_LOAD_STORE(ATOMIC_RMW_OR_I32) - WASM_LOAD_STORE(ATOMIC_RMW32_U_OR_I64) - WASM_LOAD_STORE(ATOMIC_RMW_XOR_I32) - WASM_LOAD_STORE(ATOMIC_RMW32_U_XOR_I64) - WASM_LOAD_STORE(ATOMIC_RMW_XCHG_I32) - WASM_LOAD_STORE(ATOMIC_RMW32_U_XCHG_I64) - WASM_LOAD_STORE(ATOMIC_RMW_CMPXCHG_I32) - WASM_LOAD_STORE(ATOMIC_RMW32_U_CMPXCHG_I64) - WASM_LOAD_STORE(MEMORY_ATOMIC_NOTIFY) - WASM_LOAD_STORE(MEMORY_ATOMIC_WAIT32) - WASM_LOAD_STORE(LOAD32_SPLAT) - WASM_LOAD_STORE(LOAD_ZERO_32) - WASM_LOAD_STORE(LOAD_LANE_32) - WASM_LOAD_STORE(STORE_LANE_I32x4) - return 2; - WASM_LOAD_STORE(LOAD_I64) - WASM_LOAD_STORE(LOAD_F64) - WASM_LOAD_STORE(STORE_I64) - WASM_LOAD_STORE(STORE_F64) - WASM_LOAD_STORE(ATOMIC_LOAD_I64) - WASM_LOAD_STORE(ATOMIC_STORE_I64) - WASM_LOAD_STORE(ATOMIC_RMW_ADD_I64) - WASM_LOAD_STORE(ATOMIC_RMW_SUB_I64) - WASM_LOAD_STORE(ATOMIC_RMW_AND_I64) - WASM_LOAD_STORE(ATOMIC_RMW_OR_I64) - WASM_LOAD_STORE(ATOMIC_RMW_XOR_I64) - WASM_LOAD_STORE(ATOMIC_RMW_XCHG_I64) - WASM_LOAD_STORE(ATOMIC_RMW_CMPXCHG_I64) - WASM_LOAD_STORE(MEMORY_ATOMIC_WAIT64) - WASM_LOAD_STORE(LOAD64_SPLAT) - WASM_LOAD_STORE(LOAD_EXTEND_S_I16x8) - WASM_LOAD_STORE(LOAD_EXTEND_U_I16x8) - WASM_LOAD_STORE(LOAD_EXTEND_S_I32x4) - WASM_LOAD_STORE(LOAD_EXTEND_U_I32x4) - WASM_LOAD_STORE(LOAD_EXTEND_S_I64x2) - WASM_LOAD_STORE(LOAD_EXTEND_U_I64x2) - WASM_LOAD_STORE(LOAD_ZERO_64) - WASM_LOAD_STORE(LOAD_LANE_64) - WASM_LOAD_STORE(STORE_LANE_I64x2) - return 3; - WASM_LOAD_STORE(LOAD_V128) - WASM_LOAD_STORE(STORE_V128) + WASM_LOAD_STORE(LOAD8_S_I32) + WASM_LOAD_STORE(LOAD8_U_I32) + WASM_LOAD_STORE(LOAD8_S_I64) + WASM_LOAD_STORE(LOAD8_U_I64) + WASM_LOAD_STORE(ATOMIC_LOAD8_U_I32) + WASM_LOAD_STORE(ATOMIC_LOAD8_U_I64) + WASM_LOAD_STORE(STORE8_I32) + WASM_LOAD_STORE(STORE8_I64) + WASM_LOAD_STORE(ATOMIC_STORE8_I32) + WASM_LOAD_STORE(ATOMIC_STORE8_I64) + WASM_LOAD_STORE(ATOMIC_RMW8_U_ADD_I32) + WASM_LOAD_STORE(ATOMIC_RMW8_U_ADD_I64) + WASM_LOAD_STORE(ATOMIC_RMW8_U_SUB_I32) + WASM_LOAD_STORE(ATOMIC_RMW8_U_SUB_I64) + WASM_LOAD_STORE(ATOMIC_RMW8_U_AND_I32) + WASM_LOAD_STORE(ATOMIC_RMW8_U_AND_I64) + WASM_LOAD_STORE(ATOMIC_RMW8_U_OR_I32) + WASM_LOAD_STORE(ATOMIC_RMW8_U_OR_I64) + WASM_LOAD_STORE(ATOMIC_RMW8_U_XOR_I32) + WASM_LOAD_STORE(ATOMIC_RMW8_U_XOR_I64) + WASM_LOAD_STORE(ATOMIC_RMW8_U_XCHG_I32) + WASM_LOAD_STORE(ATOMIC_RMW8_U_XCHG_I64) + WASM_LOAD_STORE(ATOMIC_RMW8_U_CMPXCHG_I32) + WASM_LOAD_STORE(ATOMIC_RMW8_U_CMPXCHG_I64) + WASM_LOAD_STORE(LOAD8_SPLAT) + WASM_LOAD_STORE(LOAD_LANE_8) + WASM_LOAD_STORE(STORE_LANE_I8x16) + return 0; + WASM_LOAD_STORE(LOAD16_S_I32) + WASM_LOAD_STORE(LOAD16_U_I32) + WASM_LOAD_STORE(LOAD16_S_I64) + WASM_LOAD_STORE(LOAD16_U_I64) + WASM_LOAD_STORE(ATOMIC_LOAD16_U_I32) + WASM_LOAD_STORE(ATOMIC_LOAD16_U_I64) + WASM_LOAD_STORE(STORE16_I32) + WASM_LOAD_STORE(STORE16_I64) + WASM_LOAD_STORE(ATOMIC_STORE16_I32) + WASM_LOAD_STORE(ATOMIC_STORE16_I64) + WASM_LOAD_STORE(ATOMIC_RMW16_U_ADD_I32) + WASM_LOAD_STORE(ATOMIC_RMW16_U_ADD_I64) + WASM_LOAD_STORE(ATOMIC_RMW16_U_SUB_I32) + WASM_LOAD_STORE(ATOMIC_RMW16_U_SUB_I64) + WASM_LOAD_STORE(ATOMIC_RMW16_U_AND_I32) + WASM_LOAD_STORE(ATOMIC_RMW16_U_AND_I64) + WASM_LOAD_STORE(ATOMIC_RMW16_U_OR_I32) + WASM_LOAD_STORE(ATOMIC_RMW16_U_OR_I64) + WASM_LOAD_STORE(ATOMIC_RMW16_U_XOR_I32) + WASM_LOAD_STORE(ATOMIC_RMW16_U_XOR_I64) + WASM_LOAD_STORE(ATOMIC_RMW16_U_XCHG_I32) + WASM_LOAD_STORE(ATOMIC_RMW16_U_XCHG_I64) + WASM_LOAD_STORE(ATOMIC_RMW16_U_CMPXCHG_I32) + WASM_LOAD_STORE(ATOMIC_RMW16_U_CMPXCHG_I64) + WASM_LOAD_STORE(LOAD16_SPLAT) + WASM_LOAD_STORE(LOAD_LANE_16) + WASM_LOAD_STORE(STORE_LANE_I16x8) + WASM_LOAD_STORE(LOAD_F16_F32) + WASM_LOAD_STORE(STORE_F16_F32) + return 1; + WASM_LOAD_STORE(LOAD_I32) + WASM_LOAD_STORE(LOAD_F32) + WASM_LOAD_STORE(STORE_I32) + WASM_LOAD_STORE(STORE_F32) + WASM_LOAD_STORE(LOAD32_S_I64) + WASM_LOAD_STORE(LOAD32_U_I64) + WASM_LOAD_STORE(STORE32_I64) + WASM_LOAD_STORE(ATOMIC_LOAD_I32) + WASM_LOAD_STORE(ATOMIC_LOAD32_U_I64) + WASM_LOAD_STORE(ATOMIC_STORE_I32) + WASM_LOAD_STORE(ATOMIC_STORE32_I64) + WASM_LOAD_STORE(ATOMIC_RMW_ADD_I32) + WASM_LOAD_STORE(ATOMIC_RMW32_U_ADD_I64) + WASM_LOAD_STORE(ATOMIC_RMW_SUB_I32) + WASM_LOAD_STORE(ATOMIC_RMW32_U_SUB_I64) + WASM_LOAD_STORE(ATOMIC_RMW_AND_I32) + WASM_LOAD_STORE(ATOMIC_RMW32_U_AND_I64) + WASM_LOAD_STORE(ATOMIC_RMW_OR_I32) + WASM_LOAD_STORE(ATOMIC_RMW32_U_OR_I64) + WASM_LOAD_STORE(ATOMIC_RMW_XOR_I32) + WASM_LOAD_STORE(ATOMIC_RMW32_U_XOR_I64) + WASM_LOAD_STORE(ATOMIC_RMW_XCHG_I32) + WASM_LOAD_STORE(ATOMIC_RMW32_U_XCHG_I64) + WASM_LOAD_STORE(ATOMIC_RMW_CMPXCHG_I32) + WASM_LOAD_STORE(ATOMIC_RMW32_U_CMPXCHG_I64) + WASM_LOAD_STORE(MEMORY_ATOMIC_NOTIFY) + WASM_LOAD_STORE(MEMORY_ATOMIC_WAIT32) + WASM_LOAD_STORE(LOAD32_SPLAT) + WASM_LOAD_STORE(LOAD_ZERO_32) + WASM_LOAD_STORE(LOAD_LANE_32) + WASM_LOAD_STORE(STORE_LANE_I32x4) + return 2; + WASM_LOAD_STORE(LOAD_I64) + WASM_LOAD_STORE(LOAD_F64) + WASM_LOAD_STORE(STORE_I64) + WASM_LOAD_STORE(STORE_F64) + WASM_LOAD_STORE(ATOMIC_LOAD_I64) + WASM_LOAD_STORE(ATOMIC_STORE_I64) + WASM_LOAD_STORE(ATOMIC_RMW_ADD_I64) + WASM_LOAD_STORE(ATOMIC_RMW_SUB_I64) + WASM_LOAD_STORE(ATOMIC_RMW_AND_I64) + WASM_LOAD_STORE(ATOMIC_RMW_OR_I64) + WASM_LOAD_STORE(ATOMIC_RMW_XOR_I64) + WASM_LOAD_STORE(ATOMIC_RMW_XCHG_I64) + WASM_LOAD_STORE(ATOMIC_RMW_CMPXCHG_I64) + WASM_LOAD_STORE(MEMORY_ATOMIC_WAIT64) + WASM_LOAD_STORE(LOAD64_SPLAT) + WASM_LOAD_STORE(LOAD_EXTEND_S_I16x8) + WASM_LOAD_STORE(LOAD_EXTEND_U_I16x8) + WASM_LOAD_STORE(LOAD_EXTEND_S_I32x4) + WASM_LOAD_STORE(LOAD_EXTEND_U_I32x4) + WASM_LOAD_STORE(LOAD_EXTEND_S_I64x2) + WASM_LOAD_STORE(LOAD_EXTEND_U_I64x2) + WASM_LOAD_STORE(LOAD_ZERO_64) + WASM_LOAD_STORE(LOAD_LANE_64) + WASM_LOAD_STORE(STORE_LANE_I64x2) + return 3; + WASM_LOAD_STORE(LOAD_V128) + WASM_LOAD_STORE(STORE_V128) return 4; default: return -1; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 526420bb2b294..ce17ee65c45eb 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -227,11 +227,11 @@ MCSymbol *WebAssemblyAsmPrinter::getOrCreateWasmSymbol(StringRef Name) { // functions. It's OK to hardcode knowledge of specific symbols here; this // method is precisely there for fetching the signatures of known // Clang-provided symbols. - if (Name == "__stack_pointer" || Name == "__tls_base" || + if (Name == "__stack_pointer" || Name == "__init_stack_pointer" || + Name == "__tls_base" || Name == "__init_tls_base" || Name == "__memory_base" || Name == "__table_base" || Name == "__tls_size" || Name == "__tls_align") { - bool Mutable = - Name == "__stack_pointer" || Name == "__tls_base"; + bool Mutable = Name == "__stack_pointer" || Name == "__tls_base"; WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); WasmSym->setGlobalType(wasm::WasmGlobalType{ uint8_t(Subtarget.hasAddr64() ? wasm::WASM_TYPE_I64 @@ -259,6 +259,26 @@ MCSymbol *WebAssemblyAsmPrinter::getOrCreateWasmSymbol(StringRef Name) { wasm::ValType AddrType = Subtarget.hasAddr64() ? wasm::ValType::I64 : wasm::ValType::I32; Params.push_back(AddrType); + } else if (Name == "__wasm_component_model_builtin_context_get_0") { + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); + WasmSym->setImportModule("$root"); + WasmSym->setImportName("[context-get-0]"); + Returns.push_back(wasm::ValType::I32); + } else if (Name == "__wasm_component_model_builtin_context_set_0") { + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); + WasmSym->setImportModule("$root"); + WasmSym->setImportName("[context-set-0]"); + Params.push_back(wasm::ValType::I32); + } else if (Name == "__wasm_component_model_builtin_context_get_1") { + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); + WasmSym->setImportModule("$root"); + WasmSym->setImportName("[context-get-1]"); + Returns.push_back(wasm::ValType::I32); + } else if (Name == "__wasm_component_model_builtin_context_set_1") { + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); + WasmSym->setImportModule("$root"); + WasmSym->setImportName("[context-set-1]"); + Params.push_back(wasm::ValType::I32); } else { // Function symbols WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); WebAssembly::getLibcallSignature(Subtarget, Name, Returns, Params); @@ -471,7 +491,7 @@ void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) { OutStreamer->switchSection(Producers); OutStreamer->emitULEB128IntValue(FieldCount); for (auto &Producers : {std::make_pair("language", &Languages), - std::make_pair("processed-by", &Tools)}) { + std::make_pair("processed-by", &Tools)}) { if (Producers.second->empty()) continue; OutStreamer->emitULEB128IntValue(strlen(Producers.first)); @@ -580,7 +600,8 @@ void WebAssemblyAsmPrinter::EmitFunctionAttributes(Module &M) { // Emit a custom section for each unique attribute. for (const auto &[Name, Symbols] : CustomSections) { MCSectionWasm *CustomSection = OutContext.getWasmSection( - ".custom_section.llvm.func_attr.annotate." + Name, SectionKind::getMetadata()); + ".custom_section.llvm.func_attr.annotate." + Name, + SectionKind::getMetadata()); OutStreamer->pushSection(); OutStreamer->switchSection(CustomSection); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index 5a1779c2c80fb..67b9e75be482f 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -188,8 +188,7 @@ unsigned WebAssemblyFrameLowering::getFPReg(const MachineFunction &MF) { : WebAssembly::FP32; } -unsigned -WebAssemblyFrameLowering::getOpcConst(const MachineFunction &MF) { +unsigned WebAssemblyFrameLowering::getOpcConst(const MachineFunction &MF) { return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32; @@ -213,31 +212,38 @@ unsigned WebAssemblyFrameLowering::getOpcAnd(const MachineFunction &MF) { : WebAssembly::AND_I32; } -unsigned -WebAssemblyFrameLowering::getOpcGlobGet(const MachineFunction &MF) { +unsigned WebAssemblyFrameLowering::getOpcGlobGet(const MachineFunction &MF) { return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() ? WebAssembly::GLOBAL_GET_I64 : WebAssembly::GLOBAL_GET_I32; } -unsigned -WebAssemblyFrameLowering::getOpcGlobSet(const MachineFunction &MF) { +unsigned WebAssemblyFrameLowering::getOpcGlobSet(const MachineFunction &MF) { return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() ? WebAssembly::GLOBAL_SET_I64 : WebAssembly::GLOBAL_SET_I32; } -void WebAssemblyFrameLowering::writeSPToGlobal( +void WebAssemblyFrameLowering::writeBackSP( unsigned SrcReg, MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator &InsertStore, const DebugLoc &DL) const { const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); - const char *ES = "__stack_pointer"; - auto *SPSymbol = MF.createExternalSymbolName(ES); + if (MF.getSubtarget<WebAssemblySubtarget>().getTargetTriple().getOSName() == + "wasip3") { + const char *ES = "__wasm_component_model_builtin_context_set_0"; + auto *SPSymbol = MF.createExternalSymbolName(ES); + BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::CALL)) + .addExternalSymbol(SPSymbol) + .addReg(SrcReg); + } else { + const char *ES = "__stack_pointer"; + auto *SPSymbol = MF.createExternalSymbolName(ES); - BuildMI(MBB, InsertStore, DL, TII->get(getOpcGlobSet(MF))) - .addExternalSymbol(SPSymbol) - .addReg(SrcReg); + BuildMI(MBB, InsertStore, DL, TII->get(getOpcGlobSet(MF))) + .addExternalSymbol(SPSymbol) + .addReg(SrcReg); + } } MachineBasicBlock::iterator @@ -251,7 +257,7 @@ WebAssemblyFrameLowering::eliminateCallFramePseudoInstr( if (I->getOpcode() == TII->getCallFrameDestroyOpcode() && needsSPWriteback(MF)) { DebugLoc DL = I->getDebugLoc(); - writeSPToGlobal(getSPReg(MF), MF, MBB, I, DL); + writeBackSP(getSPReg(MF), MF, MBB, I, DL); } return MBB.erase(I); } @@ -283,10 +289,17 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, if (StackSize) SPReg = MRI.createVirtualRegister(PtrRC); - const char *ES = "__stack_pointer"; - auto *SPSymbol = MF.createExternalSymbolName(ES); - BuildMI(MBB, InsertPt, DL, TII->get(getOpcGlobGet(MF)), SPReg) - .addExternalSymbol(SPSymbol); + if (ST.getTargetTriple().getOSName() == "wasip3") { + const char *ES = "__wasm_component_model_builtin_context_get_0"; + auto *SPSymbol = MF.createExternalSymbolName(ES); + BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CALL), SPReg) + .addExternalSymbol(SPSymbol); + } else { + const char *ES = "__stack_pointer"; + auto *SPSymbol = MF.createExternalSymbolName(ES); + BuildMI(MBB, InsertPt, DL, TII->get(getOpcGlobGet(MF)), SPReg) + .addExternalSymbol(SPSymbol); + } bool HasBP = hasBP(MF); if (HasBP) { @@ -309,7 +322,7 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, Register BitmaskReg = MRI.createVirtualRegister(PtrRC); Align Alignment = MFI.getMaxAlign(); BuildMI(MBB, InsertPt, DL, TII->get(getOpcConst(MF)), BitmaskReg) - .addImm((int64_t) ~(Alignment.value() - 1)); + .addImm((int64_t)~(Alignment.value() - 1)); BuildMI(MBB, InsertPt, DL, TII->get(getOpcAnd(MF)), getSPReg(MF)) .addReg(getSPReg(MF)) .addReg(BitmaskReg); @@ -322,7 +335,7 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, .addReg(getSPReg(MF)); } if (StackSize && needsSPWriteback(MF)) { - writeSPToGlobal(getSPReg(MF), MF, MBB, InsertPt, DL); + writeBackSP(getSPReg(MF), MF, MBB, InsertPt, DL); } } @@ -364,7 +377,7 @@ void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF, SPReg = SPFPReg; } - writeSPToGlobal(SPReg, MF, MBB, InsertPt, DL); + writeBackSP(SPReg, MF, MBB, InsertPt, DL); } bool WebAssemblyFrameLowering::isSupportedStackID( diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h index 710d5173d64db..e567345e93773 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h @@ -23,7 +23,7 @@ class WebAssemblyFrameLowering final : public TargetFrameLowering { public: /// Size of the red zone for the user stack (leaf functions can use this much /// space below the stack pointer without writing it back to __stack_pointer - /// global). + /// global/context.set). // TODO: (ABI) Revisit and decide how large it should be. static const size_t RedZoneSize = 128; @@ -47,8 +47,8 @@ class WebAssemblyFrameLowering final : public TargetFrameLowering { bool needsPrologForEH(const MachineFunction &MF) const; - /// Write SP back to __stack_pointer global. - void writeSPToGlobal(unsigned SrcReg, MachineFunction &MF, + /// Write SP back to __stack_pointer global or context.set. + void writeBackSP(unsigned SrcReg, MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator &InsertStore, const DebugLoc &DL) const; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp index 2541b0433ab59..d083eefe9b29d 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp @@ -307,10 +307,8 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) { MVT PtrVT = TLI.getPointerTy(CurDAG->getDataLayout()); switch (IntNo) { case Intrinsic::wasm_tls_base: { - MachineSDNode *TLSBase = CurDAG->getMachineNode( - GlobalGetIns, DL, PtrVT, MVT::Other, - CurDAG->getTargetExternalSymbol("__tls_base", PtrVT), - Node->getOperand(0)); + MachineSDNode *TLSBase = + llvm::WebAssembly::getTLSBase(*CurDAG, DL, Subtarget); ReplaceNode(Node, TLSBase); return; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index ad70d1b7e0a1e..295ee45abe8b5 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -2001,17 +2001,11 @@ WebAssemblyTargetLowering::LowerGlobalTLSAddress(SDValue Op, model == GlobalValue::LocalDynamicTLSModel || (model == GlobalValue::GeneralDynamicTLSModel && getTargetMachine().shouldAssumeDSOLocal(GV))) { - // For DSO-local TLS variables we use offset from __tls_base + // For DSO-local TLS variables we use offset from __tls_base, or + // context.get(1) on wasip3. MVT PtrVT = getPointerTy(DAG.getDataLayout()); - auto GlobalGet = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 - : WebAssembly::GLOBAL_GET_I32; - const char *BaseName = MF.createExternalSymbolName("__tls_base"); - - SDValue BaseAddr( - DAG.getMachineNode(GlobalGet, DL, PtrVT, - DAG.getTargetExternalSymbol(BaseName, PtrVT)), - 0); + SDValue BaseAddr(WebAssembly::getTLSBase(DAG, DL, Subtarget), 0); SDValue TLSOffset = DAG.getTargetGlobalAddress( GV, DL, PtrVT, GA->getOffset(), WebAssemblyII::MO_TLS_BASE_REL); @@ -2197,14 +2191,7 @@ SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op, } case Intrinsic::thread_pointer: { - MVT PtrVT = getPointerTy(DAG.getDataLayout()); - auto GlobalGet = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 - : WebAssembly::GLOBAL_GET_I32; - const char *TlsBase = MF.createExternalSymbolName("__tls_base"); - return SDValue( - DAG.getMachineNode(GlobalGet, DL, PtrVT, - DAG.getTargetExternalSymbol(TlsBase, PtrVT)), - 0); + return SDValue(WebAssembly::getTLSBase(DAG, DL, Subtarget), 0); } } } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp index 8ac32f939c5f2..24d5c19399bdb 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp @@ -405,7 +405,7 @@ bool WebAssemblyLateEHPrepare::restoreStackPointer(MachineFunction &MF) { WebAssembly::isCatch(InsertPos->getOpcode()) && "catch/catch_all should be present in every EH pad at this point"); ++InsertPos; // Skip the catch instruction - FrameLowering->writeSPToGlobal(FrameLowering->getSPReg(MF), MF, MBB, + FrameLowering->writeBackSP(FrameLowering->getSPReg(MF), MF, MBB, InsertPos, MBB.begin()->getDebugLoc()); } return Changed; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index 890486778e700..2996e8ca58829 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -194,3 +194,21 @@ bool WebAssembly::canLowerReturn(size_t ResultSize, const WebAssemblySubtarget *Subtarget) { return ResultSize <= 1 || canLowerMultivalueReturn(Subtarget); } + +MachineSDNode *WebAssembly::getTLSBase(SelectionDAG &DAG, const SDLoc &DL, + const WebAssemblySubtarget *Subtarget) { + MVT PtrVT = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32; + auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 + : WebAssembly::GLOBAL_GET_I32; + + if (Subtarget->getTargetTriple().getOSName() == "wasip3") { + return DAG.getMachineNode( + WebAssembly::CALL, DL, PtrVT, MVT::Other, + DAG.getTargetExternalSymbol( + "__wasm_component_model_builtin_context_get_1", PtrVT), + DAG.getEntryNode()); + } else { + return DAG.getMachineNode(GlobalGetIns, DL, PtrVT, + DAG.getTargetExternalSymbol("__tls_base", PtrVT)); + } +} \ No newline at end of file diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h index 046b1b5db2a79..9dc94d53b46e8 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h @@ -27,6 +27,9 @@ class MCSymbolWasm; class TargetRegisterClass; class WebAssemblyFunctionInfo; class WebAssemblySubtarget; +class MachineSDNode; +class SDLoc; +class SelectionDAG; namespace WebAssembly { @@ -73,6 +76,12 @@ bool canLowerMultivalueReturn(const WebAssemblySubtarget *Subtarget); /// memory. bool canLowerReturn(size_t ResultSize, const WebAssemblySubtarget *Subtarget); +// Get the TLS base value for the current target +// On wasip3: calls __wasm_component_model_builtin_context_get_1 +// Otherwise: global.get __tls_base +MachineSDNode *getTLSBase(SelectionDAG &DAG, const SDLoc &DL, + const WebAssemblySubtarget *Subtarget); + } // end namespace WebAssembly } // end namespace llvm >From 540d785b5489e8b48bde3de39e736b2ab2865ca3 Mon Sep 17 00:00:00 2001 From: Sy Brand <[email protected]> Date: Fri, 9 Jan 2026 12:24:41 +0000 Subject: [PATCH 2/2] Get wasip3 into working state --- lld/wasm/Config.h | 2 ++ lld/wasm/Driver.cpp | 27 ++++++++------- lld/wasm/Relocations.cpp | 4 +-- lld/wasm/SyntheticSections.cpp | 13 ++++---- lld/wasm/Writer.cpp | 10 +++--- .../WebAssembly/WebAssemblyTargetMachine.cpp | 33 ++++++++++++------- 6 files changed, 54 insertions(+), 35 deletions(-) diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h index 55dea0a78eadb..e26ec0e399893 100644 --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -50,6 +50,8 @@ enum class BuildIdKind { None, Fast, Sha1, Hexstring, Uuid }; // and such fields have the same name as the corresponding options. // Most fields are initialized by the driver. struct Config { + bool isMultithreaded() const { return sharedMemory || isWasip3; } + bool allowMultipleDefinition; bool bsymbolic; bool checkFeatures; diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 79ecc6c9f5858..4c12e8ac9f8e7 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -986,7 +986,7 @@ static void createSyntheticSymbols() { ctx.sym.stackPointer->markLive(); } - if (ctx.arg.sharedMemory || ctx.arg.isWasip3) { + if (ctx.arg.isMultithreaded()) { // TLS symbols are all hidden/dso-local auto tls_base_name = ctx.arg.isWasip3 ? "__init_tls_base" : "__tls_base"; ctx.sym.tlsBase = createGlobalVariable(tls_base_name, true, @@ -999,16 +999,21 @@ static void createSyntheticSymbols() { "__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN, make<SyntheticFunction>(is64 ? i64ArgSignature : i32ArgSignature, "__wasm_init_tls")); - static WasmSignature contextSet1Signature{{}, {ValType::I32}}; - ctx.sym.contextSet1 = createUndefinedFunction( - "__wasm_component_model_builtin_context_set_1", "[context-set-1]", - "$root", &contextSet1Signature); - ctx.sym.contextSet1->markLive(); - static WasmSignature contextGet1Signature{{ValType::I32}, {}}; - ctx.sym.contextGet1 = createUndefinedFunction( - "__wasm_component_model_builtin_context_get_1", "[context-get-1]", - "$root", &contextGet1Signature); - ctx.sym.contextGet1->markLive(); + if (ctx.arg.isWasip3) { + ctx.sym.tlsBase->markLive(); + ctx.sym.tlsSize->markLive(); + ctx.sym.tlsAlign->markLive(); + static WasmSignature contextSet1Signature{{}, {ValType::I32}}; + ctx.sym.contextSet1 = createUndefinedFunction( + "__wasm_component_model_builtin_context_set_1", "[context-set-1]", + "$root", &contextSet1Signature); + ctx.sym.contextSet1->markLive(); + static WasmSignature contextGet1Signature{{ValType::I32}, {}}; + ctx.sym.contextGet1 = createUndefinedFunction( + "__wasm_component_model_builtin_context_get_1", "[context-get-1]", + "$root", &contextGet1Signature); + ctx.sym.contextGet1->markLive(); + } } } diff --git a/lld/wasm/Relocations.cpp b/lld/wasm/Relocations.cpp index 52888ad25034e..46bbc4806961c 100644 --- a/lld/wasm/Relocations.cpp +++ b/lld/wasm/Relocations.cpp @@ -33,7 +33,7 @@ static bool requiresGOTAccess(const Symbol *sym) { return true; } -static bool allowUndefined(const Symbol* sym) { +static bool allowUndefined(const Symbol *sym) { // Symbols that are explicitly imported are always allowed to be undefined at // link time. if (sym->isImported()) @@ -125,7 +125,7 @@ void scanRelocations(InputChunk *chunk) { // In single-threaded builds TLS is lowered away and TLS data can be // merged with normal data and allowing TLS relocation in non-TLS // segments. - if (ctx.arg.sharedMemory) { + if (ctx.arg.isMultithreaded()) { if (!sym->isTLS()) { error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) + diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index 0d3e060ac381e..1a4fe26145e81 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -487,9 +487,9 @@ void GlobalSection::writeBody() { // the correct runtime value during `__wasm_apply_global_relocs`. if (!ctx.arg.extendedConst && ctx.isPic && !sym->isTLS()) mutable_ = true; - // With multi-theadeding any TLS globals must be mutable since they get + // With multi-threading any TLS globals must be mutable since they get // set during `__wasm_apply_global_tls_relocs` - if (ctx.arg.sharedMemory && sym->isTLS()) + if (ctx.arg.isMultithreaded() && sym->isTLS()) mutable_ = true; } WasmGlobalType type{itype, mutable_}; @@ -526,10 +526,11 @@ void GlobalSection::writeBody() { } else { WasmInitExpr initExpr; if (auto *d = dyn_cast<DefinedData>(sym)) - // In the sharedMemory case TLS globals are set during - // `__wasm_apply_global_tls_relocs`, but in the non-shared case + // In the multi-threaded case, TLS globals are set during + // `__wasm_apply_global_tls_relocs`, but in the non-multi-threaded case // we know the absolute value at link time. - initExpr = intConst(d->getVA(/*absolute=*/!ctx.arg.sharedMemory), is64); + initExpr = + intConst(d->getVA(/*absolute=*/!ctx.arg.isMultithreaded()), is64); else if (auto *f = dyn_cast<FunctionSymbol>(sym)) initExpr = intConst(f->isStub ? 0 : f->getTableIndex(), is64); else { @@ -630,7 +631,7 @@ void DataCountSection::writeBody() { } bool DataCountSection::isNeeded() const { - return numSegments && (ctx.arg.sharedMemory || ctx.arg.isWasip3); + return numSegments && ctx.arg.isMultithreaded(); } void LinkingSection::writeBody() { diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 12f72dc239a09..b75cda6384b70 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1024,7 +1024,7 @@ static StringRef getOutputDataSegmentName(const InputChunk &seg) { OutputSegment *Writer::createOutputSegment(StringRef name) { LLVM_DEBUG(dbgs() << "new segment: " << name << "\n"); OutputSegment *s = make<OutputSegment>(name); - if (ctx.arg.sharedMemory) + if (ctx.arg.isMultithreaded()) s->initFlags = WASM_DATA_SEGMENT_IS_PASSIVE; if (!ctx.arg.relocatable && name.starts_with(".bss")) s->isBss = true; @@ -1158,14 +1158,14 @@ void Writer::createSyntheticInitFunctions() { "__wasm_init_memory", WASM_SYMBOL_VISIBILITY_HIDDEN, make<SyntheticFunction>(nullSignature, "__wasm_init_memory")); ctx.sym.initMemory->markLive(); - if (ctx.arg.sharedMemory) { + if (ctx.arg.isMultithreaded()) { // This global is assigned during __wasm_init_memory in the shared memory // case. ctx.sym.tlsBase->markLive(); } } - if (ctx.arg.sharedMemory) { + if (ctx.arg.isMultithreaded()) { if (out.globalSec->needsTLSRelocations()) { ctx.sym.applyGlobalTLSRelocs = symtab->addSyntheticFunction( "__wasm_apply_global_tls_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN, @@ -1416,7 +1416,7 @@ void Writer::createInitMemoryFunction() { if (needsPassiveInitialization(s) && !s->isBss) { // The TLS region should not be dropped since its is needed // during the initialization of each thread (__wasm_init_tls). - if (ctx.arg.sharedMemory && s->isTLS()) + if (ctx.arg.isMultithreaded() && s->isTLS()) continue; // data.drop instruction writeU8(os, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix"); @@ -1626,6 +1626,8 @@ void Writer::createInitTLSFunction() { writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); writeUleb128(os, 0, "local index"); + // On WASIP3, we call `context.set 1` to set the TLS base, + // otherwise, we set the `__tls_base` global. if (ctx.arg.isWasip3) { writeU8(os, WASM_OPCODE_CALL, "call"); writeUleb128(os, ctx.sym.contextSet1->getFunctionIndex(), diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index 621640c12f695..6c11958e8cf3b 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -260,7 +260,8 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { // Take the union of all features used in the module and use it for each // function individually, since having multiple feature sets in one module // currently does not make sense for WebAssembly. If atomics are not enabled, - // also strip atomic operations and thread local storage. + // also strip atomic operations and thread local storage, unless the target + // is WASIP3, which can use TLS without atomics due to cooperative threading. static char ID; WebAssemblyTargetMachine *WasmTM; @@ -279,17 +280,25 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { bool StrippedAtomics = false; bool StrippedTLS = false; - if (!Features[WebAssembly::FeatureAtomics]) { - StrippedAtomics = stripAtomics(M); - StrippedTLS = stripThreadLocals(M); - } else if (!Features[WebAssembly::FeatureBulkMemory]) { - StrippedTLS |= stripThreadLocals(M); - } + if (WasmTM->getTargetTriple().getOSName() == "wasip3") { + // WASIP3 allows TLS without atomics, so don't strip TLS even if + // atomics are disabled. + if (!Features[WebAssembly::FeatureAtomics]) { + StrippedAtomics = stripAtomics(M); + } + } else { + if (!Features[WebAssembly::FeatureAtomics]) { + StrippedAtomics = stripAtomics(M); + StrippedTLS = stripThreadLocals(M); + } else if (!Features[WebAssembly::FeatureBulkMemory]) { + StrippedTLS |= stripThreadLocals(M); + } - if (StrippedAtomics && !StrippedTLS) - stripThreadLocals(M); - else if (StrippedTLS && !StrippedAtomics) - stripAtomics(M); + if (StrippedAtomics && !StrippedTLS) + stripThreadLocals(M); + else if (StrippedTLS && !StrippedAtomics) + stripAtomics(M); + } recordFeatures(M, Features, StrippedAtomics || StrippedTLS); @@ -404,7 +413,7 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { // Code compiled without atomics or bulk-memory may have had its atomics or // thread-local data lowered to nonatomic operations or non-thread-local // data. In that case, we mark the pseudo-feature "shared-mem" as disallowed - // to tell the linker that it would be unsafe to allow this code ot be used + // to tell the linker that it would be unsafe to allow this code to be used // in a module with shared memory. if (Stripped) { M.addModuleFlag(Module::ModFlagBehavior::Error, "wasm-feature-shared-mem", _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
