From 48a90dd7e288ad6c3ce8038c5b2d143dcc1dac34 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 5 Jan 2026 14:43:56 +0000 Subject: [PATCH 001/134] 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 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(sym)) { + if (auto *s = dyn_cast(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 importName, + std::optional importModule, + WasmSignature *signature) { + auto *sym = cast(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(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(this)) + if (auto *f = dyn_cast(this)) return f->signature; if (auto *t = dyn_cast(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(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 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 &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().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().hasAddr64() ? WebAssembly::GLOBAL_GET_I64 : WebAssembly::GLOBAL_GET_I32; } -unsigned -WebAssemblyFrameLowering::getOpcGlobSet(const MachineFunction &MF) { +unsigned WebAssemblyFrameLowering::getOpcGlobSet(const MachineFunction &MF) { return MF.getSubtarget().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().getInstrInfo(); - const char *ES = "__stack_pointer"; - auto *SPSymbol = MF.createExternalSymbolName(ES); + if (MF.getSubtarget().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 Date: Fri, 9 Jan 2026 12:24:41 +0000 Subject: [PATCH 002/134] 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(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(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(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(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(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", From 8f222c968466b30c21fa7de858c2f4da8048b584 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 08:03:38 +0000 Subject: [PATCH 003/134] Don't disable threads on WASIP3 if no atomics, and don't set the TLS from __tls_init --- clang/lib/Basic/Targets/WebAssembly.cpp | 3 ++- lld/wasm/Writer.cpp | 14 +++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp index 5bbb7af4c2ca1..160d39996d902 100644 --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -398,7 +398,8 @@ void WebAssemblyTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts, // Turn off POSIXThreads and ThreadModel so that we don't predefine _REENTRANT // or __STDCPP_THREADS__ if we will eventually end up stripping atomics // because they are unsupported. - if (!HasAtomics || !HasBulkMemory) { + if (getTriple().getOSName() != "wasip3" && + (!HasAtomics || !HasBulkMemory)) { Opts.POSIXThreads = false; Opts.setThreadModel(LangOptions::ThreadModelKind::Single); Opts.ThreadsafeStatics = false; diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index b75cda6384b70..67dc7c8acd343 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1623,16 +1623,12 @@ void Writer::createInitTLSFunction() { writeUleb128(os, 0, "num locals"); if (tlsSeg) { - writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); - writeUleb128(os, 0, "local index"); + // On WASIP3, we don't set the TLS base inside the thread context; + // this should be done as part of the thread startup stub. + if (!ctx.arg.isWasip3) { + 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(), - "function index"); - } else { writeU8(os, WASM_OPCODE_GLOBAL_SET, "global.set"); writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "global index"); } From 6d2b4645c91b5dcf9cddd984b48d721860d86b98 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 12:26:43 +0000 Subject: [PATCH 004/134] Factor out WASIP3 into options and features --- clang/include/clang/Options/Options.td | 2 ++ clang/lib/Basic/Targets/WebAssembly.cpp | 16 ++++++++++---- clang/lib/Basic/Targets/WebAssembly.h | 4 ++++ clang/lib/Driver/ToolChains/WebAssembly.cpp | 11 ++++++++-- lld/wasm/Config.h | 4 ++-- lld/wasm/Driver.cpp | 22 ++++++++++--------- lld/wasm/Options.td | 3 +++ lld/wasm/Writer.cpp | 6 ++--- lld/wasm/WriterUtils.cpp | 4 ++-- llvm/lib/Target/WebAssembly/WebAssembly.td | 4 ++++ .../WebAssembly/WebAssemblyFrameLowering.cpp | 5 ++--- .../WebAssembly/WebAssemblyISelLowering.cpp | 2 +- .../WebAssembly/WebAssemblyInstrInfo.td | 5 +++++ .../WebAssembly/WebAssemblySubtarget.cpp | 5 +++++ .../Target/WebAssembly/WebAssemblySubtarget.h | 2 ++ .../WebAssembly/WebAssemblyTargetMachine.cpp | 9 ++++---- .../WebAssembly/WebAssemblyUtilities.cpp | 2 +- .../Target/WebAssembly/WebAssemblyUtilities.h | 2 +- 18 files changed, 75 insertions(+), 33 deletions(-) diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index cda11fdc94230..04972a2cd4b9c 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -5438,6 +5438,8 @@ def mbulk_memory_opt : Flag<["-"], "mbulk-memory-opt">, Group, Group; def mcall_indirect_overlong : Flag<["-"], "mcall-indirect-overlong">, Group; def mno_call_indirect_overlong : Flag<["-"], "mno-call-indirect-overlong">, Group; +def mcomponent_model_thread_context : Flag<["-"], "mcomponent-model-thread-context">, Group; +def mno_component_model_thread_context : Flag<["-"], "mno-component-model-thread-context">, Group; def mexception_handing : Flag<["-"], "mexception-handling">, Group; def mno_exception_handing : Flag<["-"], "mno-exception-handling">, Group; def mextended_const : Flag<["-"], "mextended-const">, Group; diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp index 160d39996d902..1d557bec6157e 100644 --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -362,6 +362,14 @@ bool WebAssemblyTargetInfo::handleTargetFeatures( HasWideArithmetic = false; continue; } + if (Feature == "+component-model-thread-context") { + HasComponentModelThreadContext = true; + continue; + } + if (Feature == "-component-model-thread-context") { + HasComponentModelThreadContext = false; + continue; + } Diags.Report(diag::err_opt_not_valid_with_opt) << Feature << "-target-feature"; @@ -395,10 +403,10 @@ WebAssemblyTargetInfo::getTargetBuiltins() const { void WebAssemblyTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts, const TargetInfo *Aux) { TargetInfo::adjust(Diags, Opts, Aux); - // Turn off POSIXThreads and ThreadModel so that we don't predefine _REENTRANT - // or __STDCPP_THREADS__ if we will eventually end up stripping atomics - // because they are unsupported. - if (getTriple().getOSName() != "wasip3" && + // If not using component model threading intrinsics, turn off POSIXThreads + // and ThreadModel so that we don't predefine _REENTRANT or __STDCPP_THREADS__ + // if we will eventually end up stripping atomics because they are unsupported. + if (!HasComponentModelThreadContext && (!HasAtomics || !HasBulkMemory)) { Opts.POSIXThreads = false; Opts.setThreadModel(LangOptions::ThreadModelKind::Single); diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h index 4de6ce6bb5a21..5bd8fae7c8311 100644 --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -61,6 +61,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo { bool HasBulkMemory = false; bool HasBulkMemoryOpt = false; bool HasCallIndirectOverlong = false; + bool HasComponentModelThreadContext = false; bool HasExceptionHandling = false; bool HasExtendedConst = false; bool HasFP16 = false; @@ -105,6 +106,9 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo { PtrDiffType = SignedLong; IntPtrType = SignedLong; } + if (T.getOSName() == "wasip3") { + HasComponentModelThreadContext = true; + } } StringRef getABI() const override; diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index d6ff6584258d2..436794445379d 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -100,8 +100,7 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, arch = "wasm64"; else arch = "wasm32"; - if (ToolChain.getTriple().getOSName() == "wasip3") - arch += "-wasip3"; + CmdArgs.push_back(Args.MakeArgString(arch)); if (Args.hasArg(options::OPT_s)) @@ -172,6 +171,14 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (WantsSharedMemory(ToolChain.getTriple(), Args)) CmdArgs.push_back("--shared-memory"); + // Enable component model thread context by default for wasip3 + bool DefaultComponentModelThreadContext = + ToolChain.getTriple().getOSName() == "wasip3"; + if (Args.hasFlag(options::OPT_mcomponent_model_thread_context, + options::OPT_mno_component_model_thread_context, + DefaultComponentModelThreadContext)) + CmdArgs.push_back("--component-model-thread-context"); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (ToolChain.ShouldLinkCXXStdlib(Args)) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h index e26ec0e399893..8f7566803231d 100644 --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -50,11 +50,12 @@ 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 isMultithreaded() const { return sharedMemory || componentModelThreadContext; } bool allowMultipleDefinition; bool bsymbolic; bool checkFeatures; + bool componentModelThreadContext; bool compressRelocations; bool demangle; bool disableVerify; @@ -73,7 +74,6 @@ struct Config { bool importTable; bool importUndefined; std::optional is64; - bool isWasip3; bool mergeDataSegments; bool noinhibitExec; bool pie; diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 4c12e8ac9f8e7..ed2287d649844 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -656,16 +656,15 @@ static void readConfigs(opt::InputArgList &args) { ctx.arg.exportDynamic = args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, ctx.arg.shared); - // Parse wasm32/64 and maybe -wasip3. + // Parse wasm32/64. if (auto *arg = args.getLastArg(OPT_m)) { StringRef s = arg->getValue(); - if (s.starts_with("wasm32")) + if (s == "wasm32") ctx.arg.is64 = false; - else if (s.starts_with("wasm64")) + else if (s == "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 @@ -706,6 +705,9 @@ static void readConfigs(opt::InputArgList &args) { if (args.hasArg(OPT_print_map)) ctx.arg.mapFile = "-"; + if (args.hasArg(OPT_component_model_thread_context)) + ctx.arg.componentModelThreadContext = true; + std::tie(ctx.arg.buildId, ctx.arg.buildIdVector) = getBuildId(args); } @@ -829,8 +831,8 @@ static void checkOptions(opt::InputArgList &args) { 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"); + if (ctx.arg.sharedMemory && ctx.arg.componentModelThreadContext) { + error("--shared-memory is incompatible with component model thread context intrinsics"); } } @@ -964,7 +966,7 @@ static void createSyntheticSymbols() { bool is64 = ctx.arg.is64.value_or(false); auto stack_pointer_name = - ctx.arg.isWasip3 ? "__init_stack_pointer" : "__stack_pointer"; + ctx.arg.componentModelThreadContext ? "__init_stack_pointer" : "__stack_pointer"; if (ctx.isPic) { ctx.sym.stackPointer = createUndefinedGlobal(stack_pointer_name, ctx.arg.is64.value_or(false) @@ -988,7 +990,7 @@ static void createSyntheticSymbols() { if (ctx.arg.isMultithreaded()) { // TLS symbols are all hidden/dso-local - auto tls_base_name = ctx.arg.isWasip3 ? "__init_tls_base" : "__tls_base"; + auto tls_base_name = ctx.arg.componentModelThreadContext ? "__init_tls_base" : "__tls_base"; ctx.sym.tlsBase = createGlobalVariable(tls_base_name, true, WASM_SYMBOL_VISIBILITY_HIDDEN); ctx.sym.tlsSize = createGlobalVariable("__tls_size", false, @@ -999,7 +1001,7 @@ static void createSyntheticSymbols() { "__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN, make(is64 ? i64ArgSignature : i32ArgSignature, "__wasm_init_tls")); - if (ctx.arg.isWasip3) { + if (ctx.arg.componentModelThreadContext) { ctx.sym.tlsBase->markLive(); ctx.sym.tlsSize->markLive(); ctx.sym.tlsAlign->markLive(); @@ -1049,7 +1051,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 && !ctx.arg.isWasip3) + if (!ctx.arg.sharedMemory && !ctx.arg.componentModelThreadContext) ctx.sym.tlsBase = createOptionalGlobal("__tls_base", false); } diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td index 33ecf03176d36..a9def1bc47c9a 100644 --- a/lld/wasm/Options.td +++ b/lld/wasm/Options.td @@ -190,6 +190,9 @@ def allow_undefined_file: J<"allow-undefined-file=">, def allow_undefined_file_s: Separate<["-"], "allow-undefined-file">, Alias; +def component_model_thread_context: FF<"component-model-thread-context">, + HelpText<"Use component model thread context intrinsics instead of global variables for the stack pointer and thread local storage">; + defm export: Eq<"export", "Force a symbol to be exported">; defm export_if_defined: Eq<"export-if-defined", diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 67dc7c8acd343..ab6998a6e3bc2 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1623,9 +1623,9 @@ void Writer::createInitTLSFunction() { writeUleb128(os, 0, "num locals"); if (tlsSeg) { - // On WASIP3, we don't set the TLS base inside the thread context; - // this should be done as part of the thread startup stub. - if (!ctx.arg.isWasip3) { + // When using component model thread context intrinsics, we don't set the TLS base + //inside __init_tls; this should be done as part of the thread startup stub. + if (!ctx.arg.componentModelThreadContext) { writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); writeUleb128(os, 0, "local index"); diff --git a/lld/wasm/WriterUtils.cpp b/lld/wasm/WriterUtils.cpp index 8e945f57ef39c..4cb2a9018cca8 100644 --- a/lld/wasm/WriterUtils.cpp +++ b/lld/wasm/WriterUtils.cpp @@ -269,7 +269,7 @@ void writeExport(raw_ostream &os, const WasmExport &export_) { } void writeGetTLSBase(const Ctx &ctx, raw_ostream &os) { - if (ctx.arg.isWasip3) { + if (ctx.arg.componentModelThreadContext) { writeU8(os, WASM_OPCODE_CALL, "call"); writeUleb128(os, ctx.sym.contextGet1->getFunctionIndex(), "function index"); } else { @@ -279,7 +279,7 @@ void writeGetTLSBase(const Ctx &ctx, raw_ostream &os) { } void writeSetTLSBase(const Ctx &ctx, raw_ostream &os) { - if (ctx.arg.isWasip3) { + if (ctx.arg.componentModelThreadContext) { writeU8(os, WASM_OPCODE_CALL, "call"); writeUleb128(os, ctx.sym.contextSet1->getFunctionIndex(), "function index"); } else { diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.td b/llvm/lib/Target/WebAssembly/WebAssembly.td index 089be5f1dc70e..ff6a78027037d 100644 --- a/llvm/lib/Target/WebAssembly/WebAssembly.td +++ b/llvm/lib/Target/WebAssembly/WebAssembly.td @@ -37,6 +37,10 @@ def FeatureCallIndirectOverlong : SubtargetFeature<"call-indirect-overlong", "HasCallIndirectOverlong", "true", "Enable overlong encoding for call_indirect immediates">; +def FeatureComponentModelThreadContext : + SubtargetFeature<"component-model-thread-context", "HasComponentModelThreadContext", "false", + "Enable component model thread context intrinsics">; + def FeatureExceptionHandling : SubtargetFeature<"exception-handling", "HasExceptionHandling", "true", "Enable Wasm exception handling">; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index 67b9e75be482f..5389318ad0e28 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -229,8 +229,7 @@ void WebAssemblyFrameLowering::writeBackSP( MachineBasicBlock::iterator &InsertStore, const DebugLoc &DL) const { const auto *TII = MF.getSubtarget().getInstrInfo(); - if (MF.getSubtarget().getTargetTriple().getOSName() == - "wasip3") { + if (MF.getSubtarget().hasComponentModelThreadContext()) { const char *ES = "__wasm_component_model_builtin_context_set_0"; auto *SPSymbol = MF.createExternalSymbolName(ES); BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::CALL)) @@ -289,7 +288,7 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, if (StackSize) SPReg = MRI.createVirtualRegister(PtrRC); - if (ST.getTargetTriple().getOSName() == "wasip3") { + if (ST.hasComponentModelThreadContext()) { const char *ES = "__wasm_component_model_builtin_context_get_0"; auto *SPSymbol = MF.createExternalSymbolName(ES); BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CALL), SPReg) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index 295ee45abe8b5..dcbd39dc71e66 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -2002,7 +2002,7 @@ WebAssemblyTargetLowering::LowerGlobalTLSAddress(SDValue Op, (model == GlobalValue::GeneralDynamicTLSModel && getTargetMachine().shouldAssumeDSOLocal(GV))) { // For DSO-local TLS variables we use offset from __tls_base, or - // context.get(1) on wasip3. + // context.get(1) if using component model threading intrinsics. MVT PtrVT = getPointerTy(DAG.getDataLayout()); SDValue BaseAddr(WebAssembly::getTLSBase(DAG, DL, Subtarget), 0); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td index 13d048a98d6ea..d4fd93cb71233 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -38,6 +38,11 @@ def HasCallIndirectOverlong : Predicate<"Subtarget->hasCallIndirectOverlong()">, AssemblerPredicate<(all_of FeatureCallIndirectOverlong), "call-indirect-overlong">; +def HasComponentModelThreadContext : + Predicate<"Subtarget->hasComponentModelThreadContext()">, + AssemblerPredicate<(all_of FeatureComponentModelThreadContext), + "component-model-thread-context">; + def HasExceptionHandling : Predicate<"Subtarget->hasExceptionHandling()">, AssemblerPredicate<(all_of FeatureExceptionHandling), "exception-handling">; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp index a3ce40f0297ec..68d474631f23f 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp @@ -33,6 +33,11 @@ WebAssemblySubtarget::initializeSubtargetDependencies(StringRef CPU, if (CPU.empty()) CPU = "generic"; + // WASIP3 implies using the component model thread context intrinsics by default. + if (TargetTriple.getOSName() == "wasip3") { + HasComponentModelThreadContext = true; + } + ParseSubtargetFeatures(CPU, /*TuneCPU*/ CPU, FS); FeatureBitset Bits = getFeatureBits(); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h index 2f88bbba05d00..5c086b8a4fe31 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h @@ -43,6 +43,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo { bool HasBulkMemory = false; bool HasBulkMemoryOpt = false; bool HasCallIndirectOverlong = false; + bool HasComponentModelThreadContext = false; bool HasExceptionHandling = false; bool HasExtendedConst = false; bool HasFP16 = false; @@ -100,6 +101,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo { bool hasBulkMemory() const { return HasBulkMemory; } bool hasBulkMemoryOpt() const { return HasBulkMemoryOpt; } bool hasCallIndirectOverlong() const { return HasCallIndirectOverlong; } + bool hasComponentModelThreadContext() const { return HasComponentModelThreadContext; } bool hasExceptionHandling() const { return HasExceptionHandling; } bool hasExtendedConst() const { return HasExtendedConst; } bool hasFP16() const { return HasFP16; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index 6c11958e8cf3b..bd34f4149fc5e 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -261,7 +261,8 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { // 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, unless the target - // is WASIP3, which can use TLS without atomics due to cooperative threading. + // is using component model threading intrinsics which allow thread local storage + // without atomics, in which case only strip atomics. static char ID; WebAssemblyTargetMachine *WasmTM; @@ -280,9 +281,9 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { bool StrippedAtomics = false; bool StrippedTLS = false; - if (WasmTM->getTargetTriple().getOSName() == "wasip3") { - // WASIP3 allows TLS without atomics, so don't strip TLS even if - // atomics are disabled. + if (Features[WebAssembly::FeatureComponentModelThreadContext]) { + // Using component model threading intrinsics allows TLS without + // atomics, so don't strip TLS even if atomics are disabled. if (!Features[WebAssembly::FeatureAtomics]) { StrippedAtomics = stripAtomics(M); } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index 2996e8ca58829..1c8aeae8bc1cb 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -201,7 +201,7 @@ MachineSDNode *WebAssembly::getTLSBase(SelectionDAG &DAG, const SDLoc &DL, auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 : WebAssembly::GLOBAL_GET_I32; - if (Subtarget->getTargetTriple().getOSName() == "wasip3") { + if (Subtarget->hasComponentModelThreadContext()) { return DAG.getMachineNode( WebAssembly::CALL, DL, PtrVT, MVT::Other, DAG.getTargetExternalSymbol( diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h index 9dc94d53b46e8..5b4e9cff19a55 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h @@ -77,7 +77,7 @@ bool canLowerMultivalueReturn(const WebAssemblySubtarget *Subtarget); 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 +// If using component model threading intrinsics: calls __wasm_component_model_builtin_context_get_1 // Otherwise: global.get __tls_base MachineSDNode *getTLSBase(SelectionDAG &DAG, const SDLoc &DL, const WebAssemblySubtarget *Subtarget); From 4a18333fe63c7a16d6b74633e334981cbbda5ade Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 14:16:17 +0000 Subject: [PATCH 005/134] Tighten up features --- clang/lib/Basic/Targets/WebAssembly.cpp | 3 +++ lld/wasm/Writer.cpp | 10 ++++++++++ llvm/lib/Target/WebAssembly/WebAssembly.td | 2 +- llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp | 9 ++++++--- .../Target/WebAssembly/WebAssemblyTargetMachine.cpp | 8 ++++++++ 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp index 0d7e99b11576e..785bec699f925 100644 --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -56,6 +56,7 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const { .Case("bulk-memory", HasBulkMemory) .Case("bulk-memory-opt", HasBulkMemoryOpt) .Case("call-indirect-overlong", HasCallIndirectOverlong) + .Case("component-model-thread-context", HasComponentModelThreadContext) .Case("compact-imports", HasCompactImports) .Case("exception-handling", HasExceptionHandling) .Case("extended-const", HasExtendedConst) @@ -120,6 +121,8 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__wasm_tail_call__"); if (HasWideArithmetic) Builder.defineMacro("__wasm_wide_arithmetic__"); + if (HasComponentModelThreadContext) + Builder.defineMacro("__wasm_component_model_thread_context__"); // Note that not all wasm features appear here. For example, // HasCompatctImports diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index eaf5481a5dcd6..d18999f907561 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -644,6 +644,16 @@ void Writer::populateTargetFeatures() { " because it was not compiled with 'atomics' or 'bulk-memory' " "features."); + if (ctx.arg.componentModelThreadContext && disallowed.contains("component-model-thread-context")) + error("--component-model-thread-context is disallowed by " + + disallowed["component-model-thread-context"] + + " because it was not compiled with the 'component-model-thread-context' feature."); + + if (!ctx.arg.componentModelThreadContext && used.contains("component-model-thread-context")) + error("component-model-thread-context feature used by " + + used["component-model-thread-context"] + + " but --component-model-thread-context not specified."); + for (auto feature : {"atomics", "bulk-memory"}) if (!allowed.contains(feature)) error(StringRef("'") + feature + diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.td b/llvm/lib/Target/WebAssembly/WebAssembly.td index 0575f471b5412..5c1076aff985b 100644 --- a/llvm/lib/Target/WebAssembly/WebAssembly.td +++ b/llvm/lib/Target/WebAssembly/WebAssembly.td @@ -38,7 +38,7 @@ def FeatureCallIndirectOverlong : "Enable overlong encoding for call_indirect immediates">; def FeatureComponentModelThreadContext : - SubtargetFeature<"component-model-thread-context", "HasComponentModelThreadContext", "false", + SubtargetFeature<"component-model-thread-context", "HasComponentModelThreadContext", "true", "Enable component model thread context intrinsics">; def FeatureExceptionHandling : diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp index e027221f454ce..fa99249840dd9 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp @@ -38,13 +38,16 @@ WebAssemblySubtarget::initializeSubtargetDependencies(StringRef CPU, if (CPU.empty()) CPU = "generic"; + ParseSubtargetFeatures(CPU, /*TuneCPU*/ CPU, FS); + // WASIP3 implies using the component model thread context intrinsics by default. - if (TargetTriple.getOSName() == "wasip3") { + if (!FS.contains("component-model-thread-context") && + !HasComponentModelThreadContext && + TargetTriple.getOSName() == "wasip3") { + ToggleFeature(WebAssembly::FeatureComponentModelThreadContext); HasComponentModelThreadContext = true; } - ParseSubtargetFeatures(CPU, /*TuneCPU*/ CPU, FS); - FeatureBitset Bits = getFeatureBits(); // bulk-memory implies bulk-memory-opt diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index 8ed00ec2cf064..b484468d95a1e 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -429,6 +429,14 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { M.addModuleFlag(Module::ModFlagBehavior::Error, "wasm-feature-shared-mem", wasm::WASM_FEATURE_PREFIX_DISALLOWED); } + + // Mark component-model-thread-context as disallowed when not in use to + // prevent linking object files with incompatible threading ABIs. + if (!Features[WebAssembly::FeatureComponentModelThreadContext]) { + M.addModuleFlag(Module::ModFlagBehavior::Error, + "wasm-feature-component-model-thread-context", + wasm::WASM_FEATURE_PREFIX_DISALLOWED); + } } }; char CoalesceFeaturesAndStripAtomics::ID = 0; From 927daeb7e990692208adea16de038b271e659f60 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 14:26:15 +0000 Subject: [PATCH 006/134] Make feature detection work properly --- lld/wasm/Writer.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index d18999f907561..431169d3fdd39 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -644,6 +644,12 @@ void Writer::populateTargetFeatures() { " because it was not compiled with 'atomics' or 'bulk-memory' " "features."); + for (auto feature : {"atomics", "bulk-memory"}) + if (!allowed.contains(feature)) + error(StringRef("'") + feature + + "' feature must be used in order to use shared memory"); + } + if (ctx.arg.componentModelThreadContext && disallowed.contains("component-model-thread-context")) error("--component-model-thread-context is disallowed by " + disallowed["component-model-thread-context"] + @@ -654,13 +660,7 @@ void Writer::populateTargetFeatures() { used["component-model-thread-context"] + " but --component-model-thread-context not specified."); - for (auto feature : {"atomics", "bulk-memory"}) - if (!allowed.contains(feature)) - error(StringRef("'") + feature + - "' feature must be used in order to use shared memory"); - } - - if (tlsUsed) { + if (tlsUsed && !ctx.arg.componentModelThreadContext) { for (auto feature : {"atomics", "bulk-memory"}) if (!allowed.contains(feature)) error(StringRef("'") + feature + From e632709c827ad5e5bb6a6e87a7f2d852b14ecc3f Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 15:16:34 +0000 Subject: [PATCH 007/134] Fix TLS relocations for non WASIP3 --- lld/wasm/SyntheticSections.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index 023c690c14354..27fe215b6143b 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -474,11 +474,12 @@ void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const { if (auto *d = dyn_cast(sym)) { // Get __memory_base - writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); if (sym->isTLS()) writeGetTLSBase(ctx, os); - else + else { + writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); writeUleb128(os, ctx.sym.memoryBase->getGlobalIndex(), "__memory_base"); + } // Add the virtual address of the data symbol writePtrConst(os, d->getVA(), is64, "offset"); From f44bf2984770351e7ff7100fb524aa1b1b9bf956 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 15:18:27 +0000 Subject: [PATCH 008/134] Add stack pointer ABI test --- lld/test/wasm/stack-pointer-abi.s | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 lld/test/wasm/stack-pointer-abi.s diff --git a/lld/test/wasm/stack-pointer-abi.s b/lld/test/wasm/stack-pointer-abi.s new file mode 100644 index 0000000000000..11355a9c4586e --- /dev/null +++ b/lld/test/wasm/stack-pointer-abi.s @@ -0,0 +1,13 @@ +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s +# RUN: wasm-ld --component-model-thread-context -o %t-component-model.wasm %t.o +# RUN: obj2yaml %t-component-model.wasm | FileCheck %s --check-prefix=WITH +# RUN: wasm-ld -o %t-original.wasm %t.o +# RUN: obj2yaml %t-original.wasm | FileCheck %s --check-prefix=WITHOUT + +.globl _start +_start: + .functype _start () -> () + end_function + +# WITH: Name: __init_stack_pointer +# WITHOUT: Name: __stack_pointer \ No newline at end of file From 18a1ee3ae2db83e411bd8f8f842def0351be7a6c Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 15:43:16 +0000 Subject: [PATCH 009/134] Add tests for component model threading feature --- ...nent-model-threading-features-disallowed.s | 20 +++++++++++++++++++ .../wasm/component-model-threading-features.s | 20 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 lld/test/wasm/component-model-threading-features-disallowed.s create mode 100644 lld/test/wasm/component-model-threading-features.s diff --git a/lld/test/wasm/component-model-threading-features-disallowed.s b/lld/test/wasm/component-model-threading-features-disallowed.s new file mode 100644 index 0000000000000..9644b7e7caedd --- /dev/null +++ b/lld/test/wasm/component-model-threading-features-disallowed.s @@ -0,0 +1,20 @@ +# Test that objects with component-model-thread-context feature marked as DISALLOWED +# cannot link with --component-model-thread-context flag + +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t-without.o %s +# RUN: wasm-ld %t-without.o -o %t.wasm +# RUN: not wasm-ld --component-model-thread-context %t-without.o -o %t2.wasm 2>&1 | FileCheck %s + +# CHECK: error: --component-model-thread-context is disallowed by {{.*}} because it was not compiled with the 'component-model-thread-context' feature. + +.globl _start +_start: + .functype _start () -> () + end_function + +# Mark the feature as DISALLOWED (0x2d = '-' = WASM_FEATURE_PREFIX_DISALLOWED) +.section .custom_section.target_features,"",@ + .int8 1 + .int8 45 + .int8 30 + .ascii "component-model-thread-context" diff --git a/lld/test/wasm/component-model-threading-features.s b/lld/test/wasm/component-model-threading-features.s new file mode 100644 index 0000000000000..dd617c6f8fec5 --- /dev/null +++ b/lld/test/wasm/component-model-threading-features.s @@ -0,0 +1,20 @@ +# Test that objects with component-model-thread-context feature marked as USED +# can only link with --component-model-thread-context flag + +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t-with.o %s +# RUN: wasm-ld --component-model-thread-context %t-with.o -o %t.wasm +# RUN: not wasm-ld %t-with.o -o %t2.wasm 2>&1 | FileCheck %s + +# CHECK: error: component-model-thread-context feature used by {{.*}} but --component-model-thread-context not specified. + +.globl _start +_start: + .functype _start () -> () + end_function + +# Mark the feature as USED (0x2b = '+' = WASM_FEATURE_PREFIX_USED) +.section .custom_section.target_features,"",@ + .int8 1 + .int8 43 + .int8 30 + .ascii "component-model-thread-context" From 8980e38482f3d2f90e538a0316990151527c58f1 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 16:47:01 +0000 Subject: [PATCH 010/134] Add wasm-features test --- clang/test/Driver/wasm-features.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/clang/test/Driver/wasm-features.c b/clang/test/Driver/wasm-features.c index 89ced36eeffab..3a52150d2de27 100644 --- a/clang/test/Driver/wasm-features.c +++ b/clang/test/Driver/wasm-features.c @@ -112,3 +112,10 @@ // COMPACT-IMPORTS: "-target-feature" "+compact-imports" // NO-COMPACT-IMPORTS: "-target-feature" "-compact-imports" + +// RUN: %clang --target=wasm32-unknown-unknown -### %s -mcomponent-model-thread-context 2>&1 | FileCheck %s -check-prefix=COMPONENT-MODEL-THREAD-CONTEXT +// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-component-model-thread-context 2>&1 | FileCheck %s -check-prefix=NO-COMPONENT-MODEL-THREAD-CONTEXT + +// COMPONENT-MODEL-THREAD-CONTEXT: "-target-feature" "+component-model-thread-context" +// NO-COMPONENT-MODEL-THREAD-CONTEXT: "-target-feature" "-component-model-thread-context" + From 08a3a164e68889291d218e67959c889fe7ca4084 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 16:58:11 +0000 Subject: [PATCH 011/134] wasm-toolchain tests --- clang/test/Driver/wasm-toolchain.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/clang/test/Driver/wasm-toolchain.c b/clang/test/Driver/wasm-toolchain.c index 29a94aeec77a9..8654021e9a959 100644 --- a/clang/test/Driver/wasm-toolchain.c +++ b/clang/test/Driver/wasm-toolchain.c @@ -303,3 +303,17 @@ // RUN: | FileCheck -check-prefix=LINK_WALI_BASIC %s // LINK_WALI_BASIC: "-cc1" {{.*}} "-o" "[[temp:[^"]*]]" // LINK_WALI_BASIC: wasm-ld{{.*}}" "-L/foo/lib/wasm32-linux-muslwali" "crt1.o" "[[temp]]" "-lc" "{{.*[/\\]}}libclang_rt.builtins.a" "-o" "a.out" + +// Test that `wasm32-wasip3` passes --component-model-thread-context to the linker by default. + +// RUN: %clang --target=wasm32-wasip3 %s -### 2>&1 | FileCheck -check-prefix=WASIP3_DEFAULT %s +// WASIP3_DEFAULT: wasm-component-ld{{.*}}" {{.*}} "--component-model-thread-context" + +// Test that `wasm32-wasip3` does not pass --component-model-thread-context to the linker when +// -mno-component-model-thread-context is used, and that it also passes -target-feature -component-model-thread-context +// to disable the feature in clang-cc1. + +// RUN: %clang --target=wasm32-wasip3 %s -### -mno-component-model-thread-context 2>&1 | FileCheck -check-prefix=WASIP3_DISABLED %s + +// WASIP3_DISABLED-NOT: "--component-model-thread-context" +// WASIP3_DISABLED: "-target-feature" "-component-model-thread-context" \ No newline at end of file From 9092b93263908b886ff513a76febb59306907034 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 17:12:56 +0000 Subject: [PATCH 012/134] Formatting --- clang/lib/Driver/ToolChains/WebAssembly.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index eaa049237ce19..0d4cac5eeb6ae 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -31,13 +31,12 @@ std::string WebAssembly::getMultiarchTriple(const Driver &D, const llvm::Triple &TargetTriple, StringRef SysRoot) const { return (TargetTriple.getArchName() + "-" + - TargetTriple.getOSAndEnvironmentName()) - .str(); + 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) && @@ -249,9 +248,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, @@ -524,8 +523,7 @@ 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"); } @@ -654,6 +652,5 @@ 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"); } From 81ffb2b323bb1c757e88523d46b0289e8935e2b3 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 17:13:44 +0000 Subject: [PATCH 013/134] Formatting --- clang/lib/Driver/ToolChains/WebAssembly.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 0d4cac5eeb6ae..bb70887c00ade 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -30,8 +30,8 @@ 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 { From a9e73101f8858721bd9781317f86607f2c6f8a54 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 17:14:41 +0000 Subject: [PATCH 014/134] Revert arch change --- clang/lib/Driver/ToolChains/WebAssembly.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index bb70887c00ade..e8214c80d5f6f 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -94,13 +94,10 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, ArgStringList CmdArgs; CmdArgs.push_back("-m"); - std::string arch; if (ToolChain.getTriple().isArch64Bit()) - arch = "wasm64"; + CmdArgs.push_back("wasm64"); else - arch = "wasm32"; - - CmdArgs.push_back(Args.MakeArgString(arch)); + CmdArgs.push_back("wasm32"); if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("--strip-all"); From c369bb2ec1340fca42c9d1b05677c8c60125f617 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 17:15:21 +0000 Subject: [PATCH 015/134] Formatting --- lld/wasm/Driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 24d1637f702a3..9c6e5ef555b5a 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -656,7 +656,7 @@ 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. if (auto *arg = args.getLastArg(OPT_m)) { StringRef s = arg->getValue(); if (s == "wasm32") From d3688381869e7616a7eb6918add87e259a479568 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 17:16:05 +0000 Subject: [PATCH 016/134] Revert formatting change --- lld/wasm/Driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 9c6e5ef555b5a..c59f79b5a4b6e 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -892,7 +892,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(sym)) { + if (auto* s = dyn_cast(sym)) { if (s->signature) { LLVM_DEBUG(llvm::dbgs() << "demoting lazy func: " << s->getName() << "\n"); From 61f03e50ad420fc99ffe7cd453a9c5e35ea92e9c Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 17:17:33 +0000 Subject: [PATCH 017/134] Revert formatting change --- .../MCTargetDesc/WebAssemblyMCTargetDesc.h | 242 +++++++++--------- 1 file changed, 121 insertions(+), 121 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h index 5c6d07ba88c61..5dc0e3aa91622 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; From c9665c1f4ee21d51206dfa9fbaf24fe0bd94ba3c Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 17:20:06 +0000 Subject: [PATCH 018/134] Revert formatting changes --- llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp | 5 ++--- .../Target/WebAssembly/WebAssemblyFrameLowering.cpp | 11 +++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 8019f1d37b3b1..d87fbfb64cfae 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -498,7 +498,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)); @@ -607,8 +607,7 @@ 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 5389318ad0e28..f54bdd0dedb35 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -188,7 +188,8 @@ unsigned WebAssemblyFrameLowering::getFPReg(const MachineFunction &MF) { : WebAssembly::FP32; } -unsigned WebAssemblyFrameLowering::getOpcConst(const MachineFunction &MF) { +unsigned +WebAssemblyFrameLowering::getOpcConst(const MachineFunction &MF) { return MF.getSubtarget().hasAddr64() ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32; @@ -212,13 +213,15 @@ unsigned WebAssemblyFrameLowering::getOpcAnd(const MachineFunction &MF) { : WebAssembly::AND_I32; } -unsigned WebAssemblyFrameLowering::getOpcGlobGet(const MachineFunction &MF) { +unsigned +WebAssemblyFrameLowering::getOpcGlobGet(const MachineFunction &MF) { return MF.getSubtarget().hasAddr64() ? WebAssembly::GLOBAL_GET_I64 : WebAssembly::GLOBAL_GET_I32; } -unsigned WebAssemblyFrameLowering::getOpcGlobSet(const MachineFunction &MF) { +unsigned +WebAssemblyFrameLowering::getOpcGlobSet(const MachineFunction &MF) { return MF.getSubtarget().hasAddr64() ? WebAssembly::GLOBAL_SET_I64 : WebAssembly::GLOBAL_SET_I32; @@ -321,7 +324,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); From 07e122d7e70c71349100efd7dbe1d9ec92c484a0 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 17:34:53 +0000 Subject: [PATCH 019/134] Revert formatting changes --- lld/wasm/Driver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index c59f79b5a4b6e..81cc99c4bb287 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -1063,15 +1063,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 From 651c362ae6bb6bc5aa6b325efa2a4eafac0adc33 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 17:35:25 +0000 Subject: [PATCH 020/134] Revert formatting changes --- lld/wasm/Relocations.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lld/wasm/Relocations.cpp b/lld/wasm/Relocations.cpp index cb597fdeffcf3..046a04fa726ce 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()) From 0175bd56857849abd25bf61d07c6128f2b21a446 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 17:35:46 +0000 Subject: [PATCH 021/134] Revert formatting changes --- lld/wasm/Symbols.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp index 97a9871a06308..f2040441e6257 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(this)) + if (auto* f = dyn_cast(this)) return f->signature; if (auto *t = dyn_cast(this)) return t->signature; @@ -223,7 +223,9 @@ 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(this)) @@ -411,7 +413,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); } From 9a93078408a3277e61a7faa1926787b2884ac285 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 17:36:44 +0000 Subject: [PATCH 022/134] Revert formatting changes --- lld/wasm/SyntheticSections.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index 27fe215b6143b..f71aeef7975f3 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -466,7 +466,8 @@ 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()) @@ -647,7 +648,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; } From 85fab66cd4a511ab6b20792485b170876e51a767 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 17:38:10 +0000 Subject: [PATCH 023/134] Revert formatting changes --- lld/wasm/Writer.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 431169d3fdd39..b5496f8c4a208 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -311,8 +311,7 @@ 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); } @@ -359,8 +358,7 @@ 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; @@ -384,7 +382,6 @@ 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)); @@ -1196,7 +1193,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; From e577185ea0e9179b347f2b68f23abf85a4d79b7e Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 17:38:38 +0000 Subject: [PATCH 024/134] Revert formatting changes --- lld/wasm/WriterUtils.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lld/wasm/WriterUtils.cpp b/lld/wasm/WriterUtils.cpp index f68964ac6f990..541863f800488 100644 --- a/lld/wasm/WriterUtils.cpp +++ b/lld/wasm/WriterUtils.cpp @@ -98,8 +98,7 @@ void writeSleb128(raw_ostream &os, int64_t number, const Twine &msg) { encodeSLEB128(number, os); } -void writeBytes(raw_ostream &os, const char *bytes, size_t count, - const Twine &msg) { +void writeBytes(raw_ostream &os, const char *bytes, size_t count, const Twine &msg) { debugWrite(os.tell(), msg + " [data[" + Twine(count) + "]]"); os.write(bytes, count); } From 446d56ded155ba9c3d46c1db4268f3183743fbac Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 17 Feb 2026 17:40:25 +0000 Subject: [PATCH 025/134] Revert formatting changes --- llvm/include/llvm/MC/MCSymbolWasm.h | 8 ++++++-- llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/llvm/include/llvm/MC/MCSymbolWasm.h b/llvm/include/llvm/MC/MCSymbolWasm.h index 11cbce5b0ccd0..5c9f14e5e6d64 100644 --- a/llvm/include/llvm/MC/MCSymbolWasm.h +++ b/llvm/include/llvm/MC/MCSymbolWasm.h @@ -54,12 +54,16 @@ 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/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index f54bdd0dedb35..eb176161d1fdf 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -188,7 +188,7 @@ unsigned WebAssemblyFrameLowering::getFPReg(const MachineFunction &MF) { : WebAssembly::FP32; } -unsigned +unsigned WebAssemblyFrameLowering::getOpcConst(const MachineFunction &MF) { return MF.getSubtarget().hasAddr64() ? WebAssembly::CONST_I64 @@ -213,14 +213,14 @@ unsigned WebAssemblyFrameLowering::getOpcAnd(const MachineFunction &MF) { : WebAssembly::AND_I32; } -unsigned +unsigned WebAssemblyFrameLowering::getOpcGlobGet(const MachineFunction &MF) { return MF.getSubtarget().hasAddr64() ? WebAssembly::GLOBAL_GET_I64 : WebAssembly::GLOBAL_GET_I32; } -unsigned +unsigned WebAssemblyFrameLowering::getOpcGlobSet(const MachineFunction &MF) { return MF.getSubtarget().hasAddr64() ? WebAssembly::GLOBAL_SET_I64 From 3f10fe8cf65143e22b930d53700135c027758d75 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 18 Feb 2026 10:30:52 +0000 Subject: [PATCH 026/134] Remove linker flag --- clang/lib/Basic/Targets/WebAssembly.cpp | 4 ++ clang/lib/Basic/Targets/WebAssembly.h | 3 -- clang/lib/Driver/ToolChains/WebAssembly.cpp | 55 ++++++++++----------- lld/wasm/Config.h | 16 ++++-- lld/wasm/Driver.cpp | 21 ++++---- lld/wasm/Relocations.cpp | 2 +- lld/wasm/SymbolTable.cpp | 52 +++++++++++++++++++ lld/wasm/SymbolTable.h | 2 + lld/wasm/SyntheticSections.cpp | 6 +-- lld/wasm/Writer.cpp | 22 +++------ lld/wasm/WriterUtils.cpp | 4 +- 11 files changed, 117 insertions(+), 70 deletions(-) diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp index 785bec699f925..bced84f317c76 100644 --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -215,6 +215,10 @@ bool WebAssemblyTargetInfo::initFeatureMap( addBleedingEdgeFeatures(); } + if (getTriple().getOSName() == "wasip3") { + Features["component-model-thread-context"] = true; + } + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h index 95d2f9ace8d56..524849f2eb767 100644 --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -109,9 +109,6 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo { PtrDiffType = SignedLong; IntPtrType = SignedLong; } - if (T.getOSName() == "wasip3") { - HasComponentModelThreadContext = true; - } } StringRef getABI() const override; diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index e8214c80d5f6f..dc66113de9af2 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -167,14 +167,6 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (WantsSharedMemory(ToolChain.getTriple(), Args)) CmdArgs.push_back("--shared-memory"); - // Enable component model thread context by default for wasip3 - bool DefaultComponentModelThreadContext = - ToolChain.getTriple().getOSName() == "wasip3"; - if (Args.hasFlag(options::OPT_mcomponent_model_thread_context, - options::OPT_mno_component_model_thread_context, - DefaultComponentModelThreadContext)) - CmdArgs.push_back("--component-model-thread-context"); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (ToolChain.ShouldLinkCXXStdlib(Args)) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); @@ -319,36 +311,39 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, options::OPT_fno_use_init_array, true)) CC1Args.push_back("-fno-use-init-array"); - // '-pthread' implies atomics, bulk-memory, mutable-globals, and sign-ext + // '-pthread' implies bulk-memory, and shared memory is also used, + // also implies atomics, mutable-globals, and sign-ext. if (WantsPthread(getTriple(), DriverArgs)) { - if (DriverArgs.hasFlag(options::OPT_mno_atomics, options::OPT_matomics, - false)) - getDriver().Diag(diag::err_drv_argument_not_allowed_with) - << "-pthread" - << "-mno-atomics"; if (DriverArgs.hasFlag(options::OPT_mno_bulk_memory, options::OPT_mbulk_memory, false)) getDriver().Diag(diag::err_drv_argument_not_allowed_with) << "-pthread" << "-mno-bulk-memory"; - if (DriverArgs.hasFlag(options::OPT_mno_mutable_globals, - options::OPT_mmutable_globals, false)) - getDriver().Diag(diag::err_drv_argument_not_allowed_with) - << "-pthread" - << "-mno-mutable-globals"; - if (DriverArgs.hasFlag(options::OPT_mno_sign_ext, options::OPT_msign_ext, - false)) - getDriver().Diag(diag::err_drv_argument_not_allowed_with) - << "-pthread" - << "-mno-sign-ext"; - CC1Args.push_back("-target-feature"); - CC1Args.push_back("+atomics"); CC1Args.push_back("-target-feature"); CC1Args.push_back("+bulk-memory"); - CC1Args.push_back("-target-feature"); - CC1Args.push_back("+mutable-globals"); - CC1Args.push_back("-target-feature"); - CC1Args.push_back("+sign-ext"); + if (WantsSharedMemory(getTriple(), DriverArgs)) { + if (DriverArgs.hasFlag(options::OPT_mno_atomics, options::OPT_matomics, + false)) + getDriver().Diag(diag::err_drv_argument_not_allowed_with) + << "-pthread" + << "-mno-atomics"; + if (DriverArgs.hasFlag(options::OPT_mno_mutable_globals, + options::OPT_mmutable_globals, false)) + getDriver().Diag(diag::err_drv_argument_not_allowed_with) + << "-pthread" + << "-mno-mutable-globals"; + if (DriverArgs.hasFlag(options::OPT_mno_sign_ext, options::OPT_msign_ext, + false)) + getDriver().Diag(diag::err_drv_argument_not_allowed_with) + << "-pthread" + << "-mno-sign-ext"; + CC1Args.push_back("-target-feature"); + CC1Args.push_back("+atomics"); + CC1Args.push_back("-target-feature"); + CC1Args.push_back("+mutable-globals"); + CC1Args.push_back("-target-feature"); + CC1Args.push_back("+sign-ext"); + } } if (!DriverArgs.hasFlag(options::OPT_mmutable_globals, diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h index 0cda43f84e7ce..5514b1d6d7de2 100644 --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -51,12 +51,9 @@ 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 || componentModelThreadContext; } - bool allowMultipleDefinition; bool bsymbolic; bool checkFeatures; - bool componentModelThreadContext; bool compressRelocations; bool demangle; bool disableVerify; @@ -138,6 +135,8 @@ struct Config { llvm::SmallVector buildIdVector; }; +enum class ThreadContextAbi { Undetermined, Globals, ComponentModelBuiltins }; + // The Ctx object hold all other (non-configuration) global state. struct Ctx { Config arg; @@ -283,8 +282,19 @@ struct Ctx { 0> whyExtractRecords; + ThreadContextAbi threadContextAbi = ThreadContextAbi::Undetermined; + Ctx(); void reset(); + bool componentModelThreadContext() const { + return threadContextAbi == ThreadContextAbi::ComponentModelBuiltins; + } + bool globalsThreadContext() const { + // Use the global thread context ABI by default, even if we can't determine + // the ABI from the object files passed. + return !componentModelThreadContext(); + } + bool isMultithreaded() const { return componentModelThreadContext() || arg.sharedMemory; } }; extern Ctx ctx; diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 81cc99c4bb287..b1aacfe680451 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -705,9 +705,6 @@ static void readConfigs(opt::InputArgList &args) { if (args.hasArg(OPT_print_map)) ctx.arg.mapFile = "-"; - if (args.hasArg(OPT_component_model_thread_context)) - ctx.arg.componentModelThreadContext = true; - std::tie(ctx.arg.buildId, ctx.arg.buildIdVector) = getBuildId(args); } @@ -831,8 +828,8 @@ static void checkOptions(opt::InputArgList &args) { error("--table-base may not be used with -shared/-pie"); } - if (ctx.arg.sharedMemory && ctx.arg.componentModelThreadContext) { - error("--shared-memory is incompatible with component model thread context intrinsics"); + if (ctx.arg.sharedMemory && ctx.componentModelThreadContext()) { + error("--shared-memory is currently incompatible with component model thread context intrinsics"); } } @@ -966,7 +963,7 @@ static void createSyntheticSymbols() { bool is64 = ctx.arg.is64.value_or(false); auto stack_pointer_name = - ctx.arg.componentModelThreadContext ? "__init_stack_pointer" : "__stack_pointer"; + ctx.componentModelThreadContext() ? "__init_stack_pointer" : "__stack_pointer"; if (ctx.isPic) { ctx.sym.stackPointer = createUndefinedGlobal(stack_pointer_name, ctx.arg.is64.value_or(false) @@ -988,9 +985,9 @@ static void createSyntheticSymbols() { ctx.sym.stackPointer->markLive(); } - if (ctx.arg.isMultithreaded()) { + if (ctx.isMultithreaded()) { // TLS symbols are all hidden/dso-local - auto tls_base_name = ctx.arg.componentModelThreadContext ? "__init_tls_base" : "__tls_base"; + auto tls_base_name = ctx.componentModelThreadContext() ? "__init_tls_base" : "__tls_base"; ctx.sym.tlsBase = createGlobalVariable(tls_base_name, true, WASM_SYMBOL_VISIBILITY_HIDDEN); ctx.sym.tlsSize = createGlobalVariable("__tls_size", false, @@ -1001,7 +998,7 @@ static void createSyntheticSymbols() { "__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN, make(is64 ? i64ArgSignature : i32ArgSignature, "__wasm_init_tls")); - if (ctx.arg.componentModelThreadContext) { + if (ctx.componentModelThreadContext()) { ctx.sym.tlsBase->markLive(); ctx.sym.tlsSize->markLive(); ctx.sym.tlsAlign->markLive(); @@ -1054,7 +1051,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 && !ctx.arg.componentModelThreadContext) + if (!ctx.arg.sharedMemory && !ctx.componentModelThreadContext()) ctx.sym.tlsBase = createOptionalGlobal("__tls_base", false); } @@ -1398,14 +1395,14 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { ctx.arg.requiredExports.push_back(arg->getValue()); } - createSyntheticSymbols(); - // Add all files to the symbol table. This will add almost all // symbols that we need to the symbol table. for (InputFile *f : files) symtab->addFile(f); if (errorCount()) return; + + createSyntheticSymbols(); // Handle the `--undefined ` options. for (auto *arg : args.filtered(OPT_undefined)) diff --git a/lld/wasm/Relocations.cpp b/lld/wasm/Relocations.cpp index 046a04fa726ce..4a1523a371d15 100644 --- a/lld/wasm/Relocations.cpp +++ b/lld/wasm/Relocations.cpp @@ -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.isMultithreaded()) { + if (ctx.isMultithreaded()) { if (!sym->isTLS()) { error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) + diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp index 011e4341519cd..74e8f6440778a 100644 --- a/lld/wasm/SymbolTable.cpp +++ b/lld/wasm/SymbolTable.cpp @@ -69,6 +69,7 @@ void SymbolTable::addFile(InputFile *file, StringRef symName) { auto *f = cast(file); f->parse(false); ctx.objectFiles.push_back(f); + validateThreadContextAbi(f); } // This function is where all the optimizations of link-time @@ -91,6 +92,57 @@ void SymbolTable::compileBitcodeFiles() { auto *obj = cast(file); obj->parse(true); ctx.objectFiles.push_back(obj); + validateThreadContextAbi(obj); + } +} + +void SymbolTable::validateThreadContextAbi(const ObjFile *obj) { + // Check for the component-model-thread-context feature and validate that all + // files are consistent in whether they use it or disallow it. + + // A complication is that a user may attempt to link together object files + // compiled with different versions of LLVM, where one does not specifiy + // -component-model-thread-context when using the global thread context ABI. + // They may also attempt to link object files with the global ABI compiled with + // older LLVM versions, but link them with a newer wasm-ld. To ensure the correct behavior + // in both of these cases, we treat the presence of an __stack_pointer global as an indication + // that the global thread context ABI is being used, even if the component-model-thread-context + // feature is not disallowed. + + auto targetFeatures = obj->getWasmObj()->getTargetFeatures(); + auto threadContextFeature = llvm::find_if(targetFeatures, + [](const auto &f) { + return f.Name == "component-model-thread-context"; + }); + + bool usesComponentModelThreadContext = threadContextFeature != targetFeatures.end() && + threadContextFeature->Prefix == WASM_FEATURE_PREFIX_USED; + + if (threadContextFeature == targetFeatures.end()) { + // If the feature is not explicitly used or disallowed, check for the presence of __stack_pointer + // to determine if the global thread context ABI is being used. + auto sym = find("__stack_pointer"); + if (!sym || !sym->isDefined()) { + // No __stack_pointer global, so this is probably an object file compiled from assembly or + // some other source that doesn't care about the thread context ABI. As such, we let it pass. + return; + } + } + + if (usesComponentModelThreadContext) { + if (ctx.threadContextAbi == ThreadContextAbi::Undetermined) { + ctx.threadContextAbi = ThreadContextAbi::ComponentModelBuiltins; + } else if (ctx.threadContextAbi != ThreadContextAbi::ComponentModelBuiltins) { + error("thread context ABI mismatch: " + obj->getName() + + " uses component-model-thread-context but other files disallow it"); + } + } else { + if (ctx.threadContextAbi == ThreadContextAbi::Undetermined) { + ctx.threadContextAbi = ThreadContextAbi::Globals; + } else if (ctx.threadContextAbi != ThreadContextAbi::Globals) { + error("thread context ABI mismatch: " + obj->getName() + + " disallows component-model-thread-context but other files use it"); + } } } diff --git a/lld/wasm/SymbolTable.h b/lld/wasm/SymbolTable.h index 5d09d8b685716..ef6119223c9c8 100644 --- a/lld/wasm/SymbolTable.h +++ b/lld/wasm/SymbolTable.h @@ -104,6 +104,8 @@ class SymbolTable { void handleWeakUndefines(); DefinedFunction *createUndefinedStub(const WasmSignature &sig); + void validateThreadContextAbi(const ObjFile *obj); + private: std::pair insert(StringRef name, const InputFile *file); std::pair insertName(StringRef name); diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index f71aeef7975f3..d315b544fe9dd 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -523,7 +523,7 @@ void GlobalSection::writeBody() { mutable_ = true; // With multi-threading any TLS globals must be mutable since they get // set during `__wasm_apply_global_tls_relocs` - if (ctx.arg.isMultithreaded() && sym->isTLS()) + if (ctx.isMultithreaded() && sym->isTLS()) mutable_ = true; } WasmGlobalType type{itype, mutable_}; @@ -564,7 +564,7 @@ void GlobalSection::writeBody() { // `__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.isMultithreaded()), is64); + intConst(d->getVA(/*absolute=*/!ctx.isMultithreaded()), is64); else if (auto *f = dyn_cast(sym)) initExpr = intConst(f->isStub ? 0 : f->getTableIndex(), is64); else { @@ -665,7 +665,7 @@ void DataCountSection::writeBody() { } bool DataCountSection::isNeeded() const { - return numSegments && ctx.arg.isMultithreaded(); + return numSegments && ctx.isMultithreaded(); } void LinkingSection::writeBody() { diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index b5496f8c4a208..5b470f9c77020 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -647,17 +647,7 @@ void Writer::populateTargetFeatures() { "' feature must be used in order to use shared memory"); } - if (ctx.arg.componentModelThreadContext && disallowed.contains("component-model-thread-context")) - error("--component-model-thread-context is disallowed by " + - disallowed["component-model-thread-context"] + - " because it was not compiled with the 'component-model-thread-context' feature."); - - if (!ctx.arg.componentModelThreadContext && used.contains("component-model-thread-context")) - error("component-model-thread-context feature used by " + - used["component-model-thread-context"] + - " but --component-model-thread-context not specified."); - - if (tlsUsed && !ctx.arg.componentModelThreadContext) { + if (tlsUsed && !ctx.componentModelThreadContext()) { for (auto feature : {"atomics", "bulk-memory"}) if (!allowed.contains(feature)) error(StringRef("'") + feature + @@ -1039,7 +1029,7 @@ static StringRef getOutputDataSegmentName(const InputChunk &seg) { OutputSegment *Writer::createOutputSegment(StringRef name) { LLVM_DEBUG(dbgs() << "new segment: " << name << "\n"); OutputSegment *s = make(name); - if (ctx.arg.isMultithreaded()) + if (ctx.isMultithreaded()) s->initFlags = WASM_DATA_SEGMENT_IS_PASSIVE; if (!ctx.arg.relocatable && name.starts_with(".bss")) s->isBss = true; @@ -1173,14 +1163,14 @@ void Writer::createSyntheticInitFunctions() { "__wasm_init_memory", WASM_SYMBOL_VISIBILITY_HIDDEN, make(nullSignature, "__wasm_init_memory")); ctx.sym.initMemory->markLive(); - if (ctx.arg.isMultithreaded()) { + if (ctx.isMultithreaded()) { // This global is assigned during __wasm_init_memory in the shared memory // case. ctx.sym.tlsBase->markLive(); } } - if (ctx.arg.isMultithreaded()) { + if (ctx.isMultithreaded()) { if (out.globalSec->needsTLSRelocations()) { ctx.sym.applyGlobalTLSRelocs = symtab->addSyntheticFunction( "__wasm_apply_global_tls_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN, @@ -1431,7 +1421,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.isMultithreaded() && s->isTLS()) + if (ctx.isMultithreaded() && s->isTLS()) continue; // data.drop instruction writeU8(os, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix"); @@ -1640,7 +1630,7 @@ void Writer::createInitTLSFunction() { if (tlsSeg) { // When using component model thread context intrinsics, we don't set the TLS base //inside __init_tls; this should be done as part of the thread startup stub. - if (!ctx.arg.componentModelThreadContext) { + if (!ctx.componentModelThreadContext()) { writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); writeUleb128(os, 0, "local index"); diff --git a/lld/wasm/WriterUtils.cpp b/lld/wasm/WriterUtils.cpp index 541863f800488..f877149a77a94 100644 --- a/lld/wasm/WriterUtils.cpp +++ b/lld/wasm/WriterUtils.cpp @@ -272,7 +272,7 @@ void writeExport(raw_ostream &os, const WasmExport &export_) { } void writeGetTLSBase(const Ctx &ctx, raw_ostream &os) { - if (ctx.arg.componentModelThreadContext) { + if (ctx.componentModelThreadContext()) { writeU8(os, WASM_OPCODE_CALL, "call"); writeUleb128(os, ctx.sym.contextGet1->getFunctionIndex(), "function index"); } else { @@ -282,7 +282,7 @@ void writeGetTLSBase(const Ctx &ctx, raw_ostream &os) { } void writeSetTLSBase(const Ctx &ctx, raw_ostream &os) { - if (ctx.arg.componentModelThreadContext) { + if (ctx.componentModelThreadContext()) { writeU8(os, WASM_OPCODE_CALL, "call"); writeUleb128(os, ctx.sym.contextSet1->getFunctionIndex(), "function index"); } else { From dbae3efdcb2c3124a236b287f164bbdce1459606 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 18 Feb 2026 12:34:33 +0000 Subject: [PATCH 027/134] Determine thread context ABI automatically --- .../disallow-component-model-thread-context.s | 6 ++ lld/test/wasm/Inputs/stack-pointer.s | 11 +++ .../use-component-model-thread-context.s | 6 ++ lld/test/wasm/archive-export.test | 6 +- lld/test/wasm/comdats.ll | 6 +- ...nent-model-threading-features-disallowed.s | 20 ---- .../wasm/component-model-threading-features.s | 20 ---- lld/test/wasm/mutable-global-exports.s | 12 +-- lld/test/wasm/pie.s | 4 + lld/test/wasm/shared-weak-symbols.s | 8 +- lld/test/wasm/stack-pointer-abi.s | 16 +-- lld/test/wasm/thread-context-abi-mismatch.s | 28 ++++++ lld/test/wasm/visibility-hidden.ll | 6 +- lld/test/wasm/weak-undefined-pic.s | 10 ++ lld/wasm/Config.h | 13 +-- lld/wasm/Driver.cpp | 99 ++++++++++++++++--- lld/wasm/SymbolTable.cpp | 52 ---------- lld/wasm/SymbolTable.h | 2 - lld/wasm/Writer.cpp | 4 +- lld/wasm/WriterUtils.cpp | 4 +- 20 files changed, 187 insertions(+), 146 deletions(-) create mode 100644 lld/test/wasm/Inputs/disallow-component-model-thread-context.s create mode 100644 lld/test/wasm/Inputs/stack-pointer.s create mode 100644 lld/test/wasm/Inputs/use-component-model-thread-context.s delete mode 100644 lld/test/wasm/component-model-threading-features-disallowed.s delete mode 100644 lld/test/wasm/component-model-threading-features.s create mode 100644 lld/test/wasm/thread-context-abi-mismatch.s diff --git a/lld/test/wasm/Inputs/disallow-component-model-thread-context.s b/lld/test/wasm/Inputs/disallow-component-model-thread-context.s new file mode 100644 index 0000000000000..1af0292d2ec4b --- /dev/null +++ b/lld/test/wasm/Inputs/disallow-component-model-thread-context.s @@ -0,0 +1,6 @@ +# Mark the feature as DISALLOWED +.section .custom_section.target_features,"",@ + .int8 1 + .int8 45 + .int8 30 + .ascii "component-model-thread-context" \ No newline at end of file diff --git a/lld/test/wasm/Inputs/stack-pointer.s b/lld/test/wasm/Inputs/stack-pointer.s new file mode 100644 index 0000000000000..cfd76578a5e07 --- /dev/null +++ b/lld/test/wasm/Inputs/stack-pointer.s @@ -0,0 +1,11 @@ +.globaltype __stack_pointer, i32 + +.globl _start +_start: + .functype _start () -> (i32) + global.get __stack_pointer + i32.const 16 + i32.sub + drop + i32.const 0 + end_function \ No newline at end of file diff --git a/lld/test/wasm/Inputs/use-component-model-thread-context.s b/lld/test/wasm/Inputs/use-component-model-thread-context.s new file mode 100644 index 0000000000000..1c9554edb7e55 --- /dev/null +++ b/lld/test/wasm/Inputs/use-component-model-thread-context.s @@ -0,0 +1,6 @@ +# Mark the feature as USED +.section .custom_section.target_features,"",@ + .int8 1 + .int8 43 + .int8 30 + .ascii "component-model-thread-context" \ No newline at end of file diff --git a/lld/test/wasm/archive-export.test b/lld/test/wasm/archive-export.test index c67e500e46dd2..1432214fb1dc2 100644 --- a/lld/test/wasm/archive-export.test +++ b/lld/test/wasm/archive-export.test @@ -14,9 +14,6 @@ CHECK: Exports: CHECK-NEXT: - Name: memory CHECK-NEXT: Kind: MEMORY CHECK-NEXT: Index: 0 -CHECK-NEXT: - Name: __stack_pointer -CHECK-NEXT: Kind: GLOBAL -CHECK-NEXT: Index: 0 CHECK-NEXT: - Name: foo CHECK-NEXT: Kind: FUNCTION CHECK-NEXT: Index: 1 @@ -29,6 +26,9 @@ CHECK-NEXT: Index: 3 CHECK-NEXT: - Name: _start CHECK-NEXT: Kind: FUNCTION CHECK-NEXT: Index: 0 +CHECK-NEXT: - Name: __stack_pointer +CHECK-NEXT: Kind: GLOBAL +CHECK-NEXT: Index: 0 CHECK-NEXT: - Type: CODE NOEXPORT: Exports: diff --git a/lld/test/wasm/comdats.ll b/lld/test/wasm/comdats.ll index 1662a983698ac..249ad279f8acc 100644 --- a/lld/test/wasm/comdats.ll +++ b/lld/test/wasm/comdats.ll @@ -35,9 +35,6 @@ entry: ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 -; CHECK-NEXT: - Name: __stack_pointer -; CHECK-NEXT: Kind: GLOBAL -; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: _start ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 @@ -53,6 +50,9 @@ entry: ; CHECK-NEXT: - Name: callComdatFn2 ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 5 +; CHECK-NEXT: - Name: __stack_pointer +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Type: ELEM ; CHECK-NEXT: Segments: ; CHECK-NEXT: - Offset: diff --git a/lld/test/wasm/component-model-threading-features-disallowed.s b/lld/test/wasm/component-model-threading-features-disallowed.s deleted file mode 100644 index 9644b7e7caedd..0000000000000 --- a/lld/test/wasm/component-model-threading-features-disallowed.s +++ /dev/null @@ -1,20 +0,0 @@ -# Test that objects with component-model-thread-context feature marked as DISALLOWED -# cannot link with --component-model-thread-context flag - -# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t-without.o %s -# RUN: wasm-ld %t-without.o -o %t.wasm -# RUN: not wasm-ld --component-model-thread-context %t-without.o -o %t2.wasm 2>&1 | FileCheck %s - -# CHECK: error: --component-model-thread-context is disallowed by {{.*}} because it was not compiled with the 'component-model-thread-context' feature. - -.globl _start -_start: - .functype _start () -> () - end_function - -# Mark the feature as DISALLOWED (0x2d = '-' = WASM_FEATURE_PREFIX_DISALLOWED) -.section .custom_section.target_features,"",@ - .int8 1 - .int8 45 - .int8 30 - .ascii "component-model-thread-context" diff --git a/lld/test/wasm/component-model-threading-features.s b/lld/test/wasm/component-model-threading-features.s deleted file mode 100644 index dd617c6f8fec5..0000000000000 --- a/lld/test/wasm/component-model-threading-features.s +++ /dev/null @@ -1,20 +0,0 @@ -# Test that objects with component-model-thread-context feature marked as USED -# can only link with --component-model-thread-context flag - -# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t-with.o %s -# RUN: wasm-ld --component-model-thread-context %t-with.o -o %t.wasm -# RUN: not wasm-ld %t-with.o -o %t2.wasm 2>&1 | FileCheck %s - -# CHECK: error: component-model-thread-context feature used by {{.*}} but --component-model-thread-context not specified. - -.globl _start -_start: - .functype _start () -> () - end_function - -# Mark the feature as USED (0x2b = '+' = WASM_FEATURE_PREFIX_USED) -.section .custom_section.target_features,"",@ - .int8 1 - .int8 43 - .int8 30 - .ascii "component-model-thread-context" diff --git a/lld/test/wasm/mutable-global-exports.s b/lld/test/wasm/mutable-global-exports.s index 3cf1ae746b30a..af2dd428d8d78 100644 --- a/lld/test/wasm/mutable-global-exports.s +++ b/lld/test/wasm/mutable-global-exports.s @@ -57,12 +57,12 @@ _start: # CHECK-SP-NEXT: - Name: memory # CHECK-SP-NEXT: Kind: MEMORY # CHECK-SP-NEXT: Index: 0 -# CHECK-SP-NEXT: - Name: __stack_pointer -# CHECK-SP-NEXT: Kind: GLOBAL -# CHECK-SP-NEXT: Index: 0 # CHECK-SP-NEXT: - Name: _start # CHECK-SP-NEXT: Kind: FUNCTION # CHECK-SP-NEXT: Index: 0 +# CHECK-SP-NEXT: - Name: __stack_pointer +# CHECK-SP-NEXT: Kind: GLOBAL +# CHECK-SP-NEXT: Index: 0 # CHECK-SP-NEXT: - Type: CODE # CHECK-ALL: - Type: EXPORT @@ -73,9 +73,6 @@ _start: # CHECK-ALL-NEXT: - Name: __wasm_call_ctors # CHECK-ALL-NEXT: Kind: FUNCTION # CHECK-ALL-NEXT: Index: 0 -# CHECK-ALL-NEXT: - Name: __stack_pointer -# CHECK-ALL-NEXT: Kind: GLOBAL -# CHECK-ALL-NEXT: Index: 0 # CHECK-ALL-NEXT: - Name: _start # CHECK-ALL-NEXT: Kind: FUNCTION # CHECK-ALL-NEXT: Index: 1 @@ -85,6 +82,9 @@ _start: # CHECK-ALL-NEXT: - Name: bar_global # CHECK-ALL-NEXT: Kind: GLOBAL # CHECK-ALL-NEXT: Index: 5 +# CHECK-ALL-NEXT: - Name: __stack_pointer +# CHECK-ALL-NEXT: Kind: GLOBAL +# CHECK-ALL-NEXT: Index: 0 # CHECK-ALL-NEXT: - Name: __dso_handle # CHECK-ALL-NEXT: Kind: GLOBAL # CHECK-ALL-NEXT: Index: 6 diff --git a/lld/test/wasm/pie.s b/lld/test/wasm/pie.s index 21eac79207318..41f405062fba9 100644 --- a/lld/test/wasm/pie.s +++ b/lld/test/wasm/pie.s @@ -98,6 +98,10 @@ _start: # CHECK-NEXT: GlobalType: I32 # CHECK-NEXT: GlobalMutable: true # CHECK-NEXT: - Module: env +# CHECK-NEXT: Field: external_func +# CHECK-NEXT: Kind: FUNCTION +# CHECK-NEXT: SigIndex: 1 +# CHECK-NEXT: - Module: env # CHECK-NEXT: Field: __memory_base # CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: GlobalType: I32 diff --git a/lld/test/wasm/shared-weak-symbols.s b/lld/test/wasm/shared-weak-symbols.s index df049ce4600fe..62c46d8b9285f 100644 --- a/lld/test/wasm/shared-weak-symbols.s +++ b/lld/test/wasm/shared-weak-symbols.s @@ -42,6 +42,10 @@ call_weak: # CHECK-NEXT: Memory: # CHECK-NEXT: Minimum: 0x0 # CHECK-NEXT: - Module: env +# CHECK-NEXT: Field: weak_func +# CHECK-NEXT: Kind: FUNCTION +# CHECK-NEXT: SigIndex: 0 +# CHECK-NEXT: - Module: env # CHECK-NEXT: Field: __memory_base # CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: GlobalType: I32 @@ -51,10 +55,6 @@ call_weak: # CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: GlobalType: I32 # CHECK-NEXT: GlobalMutable: false -# CHECK-NEXT: - Module: env -# CHECK-NEXT: Field: weak_func -# CHECK-NEXT: Kind: FUNCTION -# CHECK-NEXT: SigIndex: 0 # CHECK-NEXT: - Type: FUNCTION # CHECK: - Type: EXPORT diff --git a/lld/test/wasm/stack-pointer-abi.s b/lld/test/wasm/stack-pointer-abi.s index 11355a9c4586e..fdffe30ce295a 100644 --- a/lld/test/wasm/stack-pointer-abi.s +++ b/lld/test/wasm/stack-pointer-abi.s @@ -1,13 +1,15 @@ +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t-component-model.o %S/Inputs/use-component-model-thread-context.s +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t-global.o %S/Inputs/disallow-component-model-thread-context.s # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s -# RUN: wasm-ld --component-model-thread-context -o %t-component-model.wasm %t.o -# RUN: obj2yaml %t-component-model.wasm | FileCheck %s --check-prefix=WITH -# RUN: wasm-ld -o %t-original.wasm %t.o -# RUN: obj2yaml %t-original.wasm | FileCheck %s --check-prefix=WITHOUT +# RUN: wasm-ld --component-model-thread-context -o %t-component-model.wasm %t-component-model.o %t.o +# RUN: obj2yaml %t-component-model.wasm | FileCheck %s --check-prefix=COMPONENT-MODEL +# RUN: wasm-ld -o %t-original.wasm %t-global.o %t.o +# RUN: obj2yaml %t-original.wasm | FileCheck %s --check-prefix=GLOBAL -.globl _start + .globl _start _start: .functype _start () -> () end_function -# WITH: Name: __init_stack_pointer -# WITHOUT: Name: __stack_pointer \ No newline at end of file +# COMPONENT-MODEL: Name: __init_stack_pointer +# GLOBAL: Name: __stack_pointer \ No newline at end of file diff --git a/lld/test/wasm/thread-context-abi-mismatch.s b/lld/test/wasm/thread-context-abi-mismatch.s new file mode 100644 index 0000000000000..3fe89a353134b --- /dev/null +++ b/lld/test/wasm/thread-context-abi-mismatch.s @@ -0,0 +1,28 @@ +# Test that linking object files with mismatched thread context ABIs fails with an error. + +# Test that the presence of an import of __stack_pointer from the env module is treated +# as an indication that the global thread context ABI is being used, even if the +# component-model-thread-context feature is not disallowed. + +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t-with.o %s +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t-without.o %S/Inputs/stack-pointer.s +# RUN: not wasm-ld %t-with.o %t-without.o -o %t.wasm 2>&1 | FileCheck %s + +# Test that explicitly disallowing the component-model-thread-context feature causes linking to fail +# with an error when other files use the feature. + +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t-disallow.o %S/Inputs/disallow-component-model-thread-context.s +# RUN: not wasm-ld %t-with.o %t-disallow.o -o %t.wasm 2>&1 | FileCheck %s + +# CHECK: error: thread context ABI mismatch: {{.*}} disallows component-model-thread-context but other files use it +.globl _start +_start: + .functype _start () -> () + end_function + +# Mark the feature as USED +.section .custom_section.target_features,"",@ + .int8 1 + .int8 43 + .int8 30 + .ascii "component-model-thread-context" diff --git a/lld/test/wasm/visibility-hidden.ll b/lld/test/wasm/visibility-hidden.ll index 6ed7ba3afdc02..657748676849d 100644 --- a/lld/test/wasm/visibility-hidden.ll +++ b/lld/test/wasm/visibility-hidden.ll @@ -43,9 +43,6 @@ entry: ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 -; CHECK-NEXT: - Name: __stack_pointer -; CHECK-NEXT: Kind: GLOBAL -; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: objectDefault ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 @@ -55,6 +52,9 @@ entry: ; CHECK-NEXT: - Name: archiveDefault ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 4 +; CHECK-NEXT: - Name: __stack_pointer +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Type: diff --git a/lld/test/wasm/weak-undefined-pic.s b/lld/test/wasm/weak-undefined-pic.s index 1a3a1715b4bb9..4be482c72728d 100644 --- a/lld/test/wasm/weak-undefined-pic.s +++ b/lld/test/wasm/weak-undefined-pic.s @@ -81,6 +81,16 @@ _start: # IMPORT: Field: foo # IMPORT-NEXT: Kind: FUNCTION # IMPORT-NEXT: SigIndex: 0 +# IMPORT-NEXT: - Module: env +# IMPORT-NEXT: Field: __memory_base +# IMPORT-NEXT: Kind: GLOBAL +# IMPORT-NEXT: GlobalType: I32 +# IMPORT-NEXT: GlobalMutable: false +# IMPORT-NEXT: - Module: env +# IMPORT-NEXT: Field: __table_base +# IMPORT-NEXT: Kind: GLOBAL +# IMPORT-NEXT: GlobalType: I32 +# IMPORT-NEXT: GlobalMutable: false # IMPORT-NEXT: - Module: GOT.func # IMPORT-NEXT: Field: foo # IMPORT-NEXT: Kind: GLOBAL diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h index 5514b1d6d7de2..2c4954e68bab4 100644 --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -282,19 +282,12 @@ struct Ctx { 0> whyExtractRecords; - ThreadContextAbi threadContextAbi = ThreadContextAbi::Undetermined; + // Whether to use component model thread context intrinsics for the stack pointer and TLS base. + bool componentModelThreadContext = false; Ctx(); void reset(); - bool componentModelThreadContext() const { - return threadContextAbi == ThreadContextAbi::ComponentModelBuiltins; - } - bool globalsThreadContext() const { - // Use the global thread context ABI by default, even if we can't determine - // the ABI from the object files passed. - return !componentModelThreadContext(); - } - bool isMultithreaded() const { return componentModelThreadContext() || arg.sharedMemory; } + bool isMultithreaded() const { return componentModelThreadContext || arg.sharedMemory; } }; extern Ctx ctx; diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index b1aacfe680451..e1609b2cd6eb2 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -828,7 +828,7 @@ static void checkOptions(opt::InputArgList &args) { error("--table-base may not be used with -shared/-pie"); } - if (ctx.arg.sharedMemory && ctx.componentModelThreadContext()) { + if (ctx.arg.sharedMemory && ctx.componentModelThreadContext) { error("--shared-memory is currently incompatible with component model thread context intrinsics"); } } @@ -942,12 +942,23 @@ static DefinedGlobal *createOptionalGlobal(StringRef name, bool isMutable) { return symtab->addOptionalGlobalSymbol(name, g); } -// Create ABI-defined synthetic symbols -static void createSyntheticSymbols() { +// Create ABI-defined synthetic symbols that are needed early, before LTO. +static void createEarlySyntheticSymbols() { if (ctx.arg.relocatable) return; static WasmSignature nullSignature = {{}, {}}; + ctx.sym.callCtors = symtab->addSyntheticFunction( + "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN, + make(nullSignature, "__wasm_call_ctors")); +} + +// Create synthetic symbols that rely on information that is only available +// after LTO, e.g. __stack_pointer, __tls_base. +static void createPostLTOSymbols() { + if (ctx.arg.relocatable) + return; + static WasmSignature i32ArgSignature = {{}, {ValType::I32}}; static WasmSignature i64ArgSignature = {{}, {ValType::I64}}; static llvm::wasm::WasmGlobalType globalTypeI32 = {WASM_TYPE_I32, false}; @@ -956,14 +967,11 @@ static void createSyntheticSymbols() { true}; static llvm::wasm::WasmGlobalType mutableGlobalTypeI64 = {WASM_TYPE_I64, true}; - ctx.sym.callCtors = symtab->addSyntheticFunction( - "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN, - make(nullSignature, "__wasm_call_ctors")); bool is64 = ctx.arg.is64.value_or(false); auto stack_pointer_name = - ctx.componentModelThreadContext() ? "__init_stack_pointer" : "__stack_pointer"; + ctx.componentModelThreadContext ? "__init_stack_pointer" : "__stack_pointer"; if (ctx.isPic) { ctx.sym.stackPointer = createUndefinedGlobal(stack_pointer_name, ctx.arg.is64.value_or(false) @@ -987,7 +995,7 @@ static void createSyntheticSymbols() { if (ctx.isMultithreaded()) { // TLS symbols are all hidden/dso-local - auto tls_base_name = ctx.componentModelThreadContext() ? "__init_tls_base" : "__tls_base"; + auto tls_base_name = ctx.componentModelThreadContext ? "__init_tls_base" : "__tls_base"; ctx.sym.tlsBase = createGlobalVariable(tls_base_name, true, WASM_SYMBOL_VISIBILITY_HIDDEN); ctx.sym.tlsSize = createGlobalVariable("__tls_size", false, @@ -998,7 +1006,7 @@ static void createSyntheticSymbols() { "__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN, make(is64 ? i64ArgSignature : i32ArgSignature, "__wasm_init_tls")); - if (ctx.componentModelThreadContext()) { + if (ctx.componentModelThreadContext) { ctx.sym.tlsBase->markLive(); ctx.sym.tlsSize->markLive(); ctx.sym.tlsAlign->markLive(); @@ -1051,7 +1059,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 && !ctx.componentModelThreadContext()) + if (!ctx.arg.sharedMemory && !ctx.componentModelThreadContext) ctx.sym.tlsBase = createOptionalGlobal("__tls_base", false); } @@ -1306,6 +1314,67 @@ static void checkZOptions(opt::InputArgList &args) { warn("unknown -z value: " + StringRef(arg->getValue())); } +// Determine the thread context ABI based on object file features. +// This must be called after LTO, since LTO object files are needed. +static void determineThreadContextAbi(ArrayRef files) { + // A complication is that a user may attempt to link together object files + // compiled with different versions of LLVM, where one does not specifiy + // -component-model-thread-context when using the global thread context ABI. + // They may also attempt to link object files with the global ABI compiled with + // older LLVM versions, but link them with a newer wasm-ld. To ensure the correct behavior + // in both of these cases, we treat the import of a __stack_pointer global from the env module + // as an indication that the global thread context ABI is being used. + + enum class ThreadContextAbi { + Undetermined, + ComponentModelBuiltins, + Globals + }; + + ThreadContextAbi threadContextAbi = ThreadContextAbi::Undetermined; + + for (ObjFile *obj : files) { + auto targetFeatures = obj->getWasmObj()->getTargetFeatures(); + auto threadContextFeature = llvm::find_if(targetFeatures, + [](const auto &f) { + return f.Name == "component-model-thread-context"; + }); + + bool usesComponentModelThreadContext = threadContextFeature != targetFeatures.end() && + threadContextFeature->Prefix == WASM_FEATURE_PREFIX_USED; + + if (threadContextFeature == targetFeatures.end()) { + // If the feature is not explicitly used or disallowed, check for the presence of __stack_pointer + // to determine if the global thread context ABI is being used. + auto sym = symtab->find("__stack_pointer"); + if (!sym || sym->kind() != Symbol::UndefinedGlobalKind || sym->importModule != "env") { + // No __stack_pointer import, so this is probably an object file compiled from assembly or + // some other source that doesn't care about the thread context ABI. As such, we let it pass. + break; + } + } + + if (usesComponentModelThreadContext) { + if (threadContextAbi == ThreadContextAbi::Undetermined) { + threadContextAbi = ThreadContextAbi::ComponentModelBuiltins; + } else if (threadContextAbi != ThreadContextAbi::ComponentModelBuiltins) { + error("thread context ABI mismatch: " + obj->getName() + + " uses component-model-thread-context but other files disallow it"); + } + } else { + if (threadContextAbi == ThreadContextAbi::Undetermined) { + threadContextAbi = ThreadContextAbi::Globals; + } else if (threadContextAbi != ThreadContextAbi::Globals) { + error("thread context ABI mismatch: " + obj->getName() + + " disallows component-model-thread-context but other files use it"); + } + } + } + + // If the ABI is undetermined at this point, default to the globals ABI + ctx.componentModelThreadContext = (threadContextAbi == ThreadContextAbi::ComponentModelBuiltins); +} + LinkerDriver::LinkerDriver(Ctx &ctx) : ctx(ctx) {} void LinkerDriver::linkerMain(ArrayRef argsArr) { @@ -1395,14 +1464,14 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { ctx.arg.requiredExports.push_back(arg->getValue()); } + createEarlySyntheticSymbols(); + // Add all files to the symbol table. This will add almost all // symbols that we need to the symbol table. for (InputFile *f : files) symtab->addFile(f); if (errorCount()) return; - - createSyntheticSymbols(); // Handle the `--undefined ` options. for (auto *arg : args.filtered(OPT_undefined)) @@ -1480,6 +1549,12 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { if (errorCount()) return; + // Now that LTO is complete and all object files are available, determine the + // thread context ABI and create symbols (__stack_pointer, __tls_base, etc.) based + // on the determined ABI. + determineThreadContextAbi(ctx.objectFiles); + createPostLTOSymbols(); + // The LTO process can generate new undefined symbols, specifically libcall // functions. Because those symbols might be declared in a stub library we // need the process the stub libraries once again after LTO to handle all diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp index 74e8f6440778a..011e4341519cd 100644 --- a/lld/wasm/SymbolTable.cpp +++ b/lld/wasm/SymbolTable.cpp @@ -69,7 +69,6 @@ void SymbolTable::addFile(InputFile *file, StringRef symName) { auto *f = cast(file); f->parse(false); ctx.objectFiles.push_back(f); - validateThreadContextAbi(f); } // This function is where all the optimizations of link-time @@ -92,57 +91,6 @@ void SymbolTable::compileBitcodeFiles() { auto *obj = cast(file); obj->parse(true); ctx.objectFiles.push_back(obj); - validateThreadContextAbi(obj); - } -} - -void SymbolTable::validateThreadContextAbi(const ObjFile *obj) { - // Check for the component-model-thread-context feature and validate that all - // files are consistent in whether they use it or disallow it. - - // A complication is that a user may attempt to link together object files - // compiled with different versions of LLVM, where one does not specifiy - // -component-model-thread-context when using the global thread context ABI. - // They may also attempt to link object files with the global ABI compiled with - // older LLVM versions, but link them with a newer wasm-ld. To ensure the correct behavior - // in both of these cases, we treat the presence of an __stack_pointer global as an indication - // that the global thread context ABI is being used, even if the component-model-thread-context - // feature is not disallowed. - - auto targetFeatures = obj->getWasmObj()->getTargetFeatures(); - auto threadContextFeature = llvm::find_if(targetFeatures, - [](const auto &f) { - return f.Name == "component-model-thread-context"; - }); - - bool usesComponentModelThreadContext = threadContextFeature != targetFeatures.end() && - threadContextFeature->Prefix == WASM_FEATURE_PREFIX_USED; - - if (threadContextFeature == targetFeatures.end()) { - // If the feature is not explicitly used or disallowed, check for the presence of __stack_pointer - // to determine if the global thread context ABI is being used. - auto sym = find("__stack_pointer"); - if (!sym || !sym->isDefined()) { - // No __stack_pointer global, so this is probably an object file compiled from assembly or - // some other source that doesn't care about the thread context ABI. As such, we let it pass. - return; - } - } - - if (usesComponentModelThreadContext) { - if (ctx.threadContextAbi == ThreadContextAbi::Undetermined) { - ctx.threadContextAbi = ThreadContextAbi::ComponentModelBuiltins; - } else if (ctx.threadContextAbi != ThreadContextAbi::ComponentModelBuiltins) { - error("thread context ABI mismatch: " + obj->getName() + - " uses component-model-thread-context but other files disallow it"); - } - } else { - if (ctx.threadContextAbi == ThreadContextAbi::Undetermined) { - ctx.threadContextAbi = ThreadContextAbi::Globals; - } else if (ctx.threadContextAbi != ThreadContextAbi::Globals) { - error("thread context ABI mismatch: " + obj->getName() + - " disallows component-model-thread-context but other files use it"); - } } } diff --git a/lld/wasm/SymbolTable.h b/lld/wasm/SymbolTable.h index ef6119223c9c8..5d09d8b685716 100644 --- a/lld/wasm/SymbolTable.h +++ b/lld/wasm/SymbolTable.h @@ -104,8 +104,6 @@ class SymbolTable { void handleWeakUndefines(); DefinedFunction *createUndefinedStub(const WasmSignature &sig); - void validateThreadContextAbi(const ObjFile *obj); - private: std::pair insert(StringRef name, const InputFile *file); std::pair insertName(StringRef name); diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 5b470f9c77020..25330f45c82dc 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -647,7 +647,7 @@ void Writer::populateTargetFeatures() { "' feature must be used in order to use shared memory"); } - if (tlsUsed && !ctx.componentModelThreadContext()) { + if (tlsUsed && !ctx.componentModelThreadContext) { for (auto feature : {"atomics", "bulk-memory"}) if (!allowed.contains(feature)) error(StringRef("'") + feature + @@ -1630,7 +1630,7 @@ void Writer::createInitTLSFunction() { if (tlsSeg) { // When using component model thread context intrinsics, we don't set the TLS base //inside __init_tls; this should be done as part of the thread startup stub. - if (!ctx.componentModelThreadContext()) { + if (!ctx.componentModelThreadContext) { writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); writeUleb128(os, 0, "local index"); diff --git a/lld/wasm/WriterUtils.cpp b/lld/wasm/WriterUtils.cpp index f877149a77a94..40c0883dc650e 100644 --- a/lld/wasm/WriterUtils.cpp +++ b/lld/wasm/WriterUtils.cpp @@ -272,7 +272,7 @@ void writeExport(raw_ostream &os, const WasmExport &export_) { } void writeGetTLSBase(const Ctx &ctx, raw_ostream &os) { - if (ctx.componentModelThreadContext()) { + if (ctx.componentModelThreadContext) { writeU8(os, WASM_OPCODE_CALL, "call"); writeUleb128(os, ctx.sym.contextGet1->getFunctionIndex(), "function index"); } else { @@ -282,7 +282,7 @@ void writeGetTLSBase(const Ctx &ctx, raw_ostream &os) { } void writeSetTLSBase(const Ctx &ctx, raw_ostream &os) { - if (ctx.componentModelThreadContext()) { + if (ctx.componentModelThreadContext) { writeU8(os, WASM_OPCODE_CALL, "call"); writeUleb128(os, ctx.sym.contextSet1->getFunctionIndex(), "function index"); } else { From e8babc79196f0e32d4650b139d209b72912ff193 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 18 Feb 2026 13:14:23 +0000 Subject: [PATCH 028/134] Fix comment --- clang/lib/Driver/ToolChains/WebAssembly.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index dc66113de9af2..53a22f3a9f9c6 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -311,7 +311,7 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, options::OPT_fno_use_init_array, true)) CC1Args.push_back("-fno-use-init-array"); - // '-pthread' implies bulk-memory, and shared memory is also used, + // '-pthread' implies bulk-memory, and, if shared memory is also used, // also implies atomics, mutable-globals, and sign-ext. if (WantsPthread(getTriple(), DriverArgs)) { if (DriverArgs.hasFlag(options::OPT_mno_bulk_memory, @@ -321,6 +321,7 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, << "-mno-bulk-memory"; CC1Args.push_back("-target-feature"); CC1Args.push_back("+bulk-memory"); + if (WantsSharedMemory(getTriple(), DriverArgs)) { if (DriverArgs.hasFlag(options::OPT_mno_atomics, options::OPT_matomics, false)) From 822ea98e4a7c8bef60170e4d3d1ffc089c462f18 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 18 Feb 2026 13:14:34 +0000 Subject: [PATCH 029/134] Test updates --- clang/test/Driver/wasm-toolchain.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/clang/test/Driver/wasm-toolchain.c b/clang/test/Driver/wasm-toolchain.c index 8654021e9a959..4a22ea8a02417 100644 --- a/clang/test/Driver/wasm-toolchain.c +++ b/clang/test/Driver/wasm-toolchain.c @@ -304,16 +304,6 @@ // LINK_WALI_BASIC: "-cc1" {{.*}} "-o" "[[temp:[^"]*]]" // LINK_WALI_BASIC: wasm-ld{{.*}}" "-L/foo/lib/wasm32-linux-muslwali" "crt1.o" "[[temp]]" "-lc" "{{.*[/\\]}}libclang_rt.builtins.a" "-o" "a.out" -// Test that `wasm32-wasip3` passes --component-model-thread-context to the linker by default. - -// RUN: %clang --target=wasm32-wasip3 %s -### 2>&1 | FileCheck -check-prefix=WASIP3_DEFAULT %s -// WASIP3_DEFAULT: wasm-component-ld{{.*}}" {{.*}} "--component-model-thread-context" - -// Test that `wasm32-wasip3` does not pass --component-model-thread-context to the linker when -// -mno-component-model-thread-context is used, and that it also passes -target-feature -component-model-thread-context -// to disable the feature in clang-cc1. - -// RUN: %clang --target=wasm32-wasip3 %s -### -mno-component-model-thread-context 2>&1 | FileCheck -check-prefix=WASIP3_DISABLED %s - -// WASIP3_DISABLED-NOT: "--component-model-thread-context" +// `-target=wasm32-wasip2` sets -component-model-thread-context +// RUN: %clang --target=wasm32-wasip2 %s -### 2>&1 | FileCheck -check-prefix=WASIP3_DISABLED %s // WASIP3_DISABLED: "-target-feature" "-component-model-thread-context" \ No newline at end of file From cb2fb8d14c2976c864d95a0ddc079c36efcdfc36 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 18 Feb 2026 13:14:55 +0000 Subject: [PATCH 030/134] TLS fixes --- lld/wasm/Driver.cpp | 32 +++++++++---------- lld/wasm/SyntheticSections.cpp | 11 +------ lld/wasm/Writer.cpp | 21 ++++-------- .../AsmParser/WebAssemblyAsmParser.cpp | 1 + 4 files changed, 25 insertions(+), 40 deletions(-) diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 5973ca47dd80e..a9f9566b3efb4 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -827,10 +827,6 @@ 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.componentModelThreadContext) { - error("--shared-memory is currently incompatible with component model thread context intrinsics"); - } } static const char *getReproduceOption(opt::InputArgList &args) { @@ -996,7 +992,7 @@ static void createPostLTOSymbols() { if (ctx.isMultithreaded()) { // TLS symbols are all hidden/dso-local auto tls_base_name = ctx.componentModelThreadContext ? "__init_tls_base" : "__tls_base"; - ctx.sym.tlsBase = createGlobalVariable(tls_base_name, true, + ctx.sym.tlsBase = createGlobalVariable(tls_base_name, !ctx.componentModelThreadContext, WASM_SYMBOL_VISIBILITY_HIDDEN); ctx.sym.tlsSize = createGlobalVariable("__tls_size", false, WASM_SYMBOL_VISIBILITY_HIDDEN); @@ -1010,6 +1006,7 @@ static void createPostLTOSymbols() { ctx.sym.tlsBase->markLive(); ctx.sym.tlsSize->markLive(); ctx.sym.tlsAlign->markLive(); + ctx.sym.initTLS->markLive(); static WasmSignature contextSet1Signature{{}, {ValType::I32}}; ctx.sym.contextSet1 = createUndefinedFunction( "__wasm_component_model_builtin_context_set_1", "[context-set-1]", @@ -1316,7 +1313,7 @@ static void checkZOptions(opt::InputArgList &args) { // Determine the thread context ABI based on object file features. // This must be called after LTO, since LTO object files are needed. -static void determineThreadContextAbi(ArrayRef files) { +static void determineThreadContextABI(ArrayRef files) { // A complication is that a user may attempt to link together object files // compiled with different versions of LLVM, where one does not specifiy // -component-model-thread-context when using the global thread context ABI. @@ -1325,13 +1322,13 @@ static void determineThreadContextAbi(ArrayRef files) { // in both of these cases, we treat the import of a __stack_pointer global from the env module // as an indication that the global thread context ABI is being used. - enum class ThreadContextAbi { + enum class ThreadContextABI { Undetermined, ComponentModelBuiltins, Globals }; - ThreadContextAbi threadContextAbi = ThreadContextAbi::Undetermined; + ThreadContextABI threadContextABI = ThreadContextABI::Undetermined; for (ObjFile *obj : files) { auto targetFeatures = obj->getWasmObj()->getTargetFeatures(); @@ -1355,16 +1352,16 @@ static void determineThreadContextAbi(ArrayRef files) { } if (usesComponentModelThreadContext) { - if (threadContextAbi == ThreadContextAbi::Undetermined) { - threadContextAbi = ThreadContextAbi::ComponentModelBuiltins; - } else if (threadContextAbi != ThreadContextAbi::ComponentModelBuiltins) { + if (threadContextABI == ThreadContextABI::Undetermined) { + threadContextABI = ThreadContextABI::ComponentModelBuiltins; + } else if (threadContextABI != ThreadContextABI::ComponentModelBuiltins) { error("thread context ABI mismatch: " + obj->getName() + " uses component-model-thread-context but other files disallow it"); } } else { - if (threadContextAbi == ThreadContextAbi::Undetermined) { - threadContextAbi = ThreadContextAbi::Globals; - } else if (threadContextAbi != ThreadContextAbi::Globals) { + if (threadContextABI == ThreadContextABI::Undetermined) { + threadContextABI = ThreadContextABI::Globals; + } else if (threadContextABI != ThreadContextABI::Globals) { error("thread context ABI mismatch: " + obj->getName() + " disallows component-model-thread-context but other files use it"); } @@ -1372,7 +1369,10 @@ static void determineThreadContextAbi(ArrayRef files) { } // If the ABI is undetermined at this point, default to the globals ABI - ctx.componentModelThreadContext = (threadContextAbi == ThreadContextAbi::ComponentModelBuiltins); + ctx.componentModelThreadContext = (threadContextABI == ThreadContextABI::ComponentModelBuiltins); + if (ctx.arg.sharedMemory && ctx.componentModelThreadContext) { + error("--shared-memory is currently incompatible with component model thread context intrinsics"); + } } LinkerDriver::LinkerDriver(Ctx &ctx) : ctx(ctx) {} @@ -1552,7 +1552,7 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { // Now that LTO is complete and all object files are available, determine the // thread context ABI and create symbols (__stack_pointer, __tls_base, etc.) based // on the determined ABI. - determineThreadContextAbi(ctx.objectFiles); + determineThreadContextABI(ctx.objectFiles); createPostLTOSymbols(); // The LTO process can generate new undefined symbols, specifically libcall diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index bd20a5d06216d..e00f769a21ce7 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -466,12 +466,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); -<<<<<<< sy/wasip3 - 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; ->>>>>>> main for (const Symbol *sym : internalGotSymbols) { if (TLS != sym->isTLS()) @@ -669,9 +664,6 @@ void DataCountSection::writeBody() { } bool DataCountSection::isNeeded() const { -<<<<<<< sy/wasip3 - return numSegments && ctx.isMultithreaded(); -======= // The datacount section is only required under certain circumstance. // Specifically, when the module includes bulk memory instructions that deal // with passive data segments. i.e. memory.init/data.drop. @@ -679,8 +671,7 @@ bool DataCountSection::isNeeded() const { // instructions are not yet supported in input files. However, in the case // of shared memory, lld itself will generate these instructions as part of // `__wasm_init_memory`. See Writer::createInitMemoryFunction. - return numSegments && ctx.arg.sharedMemory; ->>>>>>> main + return numSegments && ctx.isMultithreaded(); } void LinkingSection::writeBody() { diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 811aec740d446..23a9f3ddf8623 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -649,11 +649,13 @@ void Writer::populateTargetFeatures() { "' feature must be used in order to use shared memory"); } - if (tlsUsed && !ctx.componentModelThreadContext) { - for (auto feature : {"atomics", "bulk-memory"}) - if (!allowed.contains(feature)) - error(StringRef("'") + feature + - "' feature must be used in order to use thread-local storage"); + if (tlsUsed) { + if (!allowed.contains("bulk-memory")) { + error("bulk-memory feature must be used in order to use thread-local storage"); + } + if (!ctx.componentModelThreadContext && !allowed.contains("atomics")) { + error("atomics feature must be used in order to use thread-local storage"); + } } // Validate that used features are allowed in output @@ -1185,11 +1187,7 @@ void Writer::createSyntheticInitFunctions() { auto hasTLSRelocs = [](const OutputSegment *segment) { if (segment->isTLS()) -<<<<<<< sy/wasip3 - for (const auto* is : segment->inputSegments) -======= for (const auto *is : segment->inputSegments) ->>>>>>> main if (is->getRelocations().size()) return true; return false; @@ -1644,13 +1642,8 @@ void Writer::createInitTLSFunction() { writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "global index"); } -<<<<<<< sy/wasip3 - // 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. ->>>>>>> main writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); writeUleb128(os, 0, "local index"); diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp index 25704c9ef0ac4..7a9f675548a5c 100644 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -430,6 +430,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser { return Name; } error("Expected string or identifier, got: ", Lexer.getTok()); + return StringRef(); } bool parseRegTypeList(SmallVectorImpl &Types) { From 6cf7c2a3e1830100f7c38973bc015c7c690b7feb Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 18 Feb 2026 13:17:02 +0000 Subject: [PATCH 031/134] TLS test --- lld/test/wasm/tls-component-model.s | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 lld/test/wasm/tls-component-model.s diff --git a/lld/test/wasm/tls-component-model.s b/lld/test/wasm/tls-component-model.s new file mode 100644 index 0000000000000..d347ec0c1f2dc --- /dev/null +++ b/lld/test/wasm/tls-component-model.s @@ -0,0 +1,29 @@ +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s +# RUN: wasm-ld -o %t.wasm %t.o +# RUN: obj2yaml %t.wasm | FileCheck %s +# RUN: llvm-objdump -d --no-show-raw-insn %t.wasm | FileCheck %s --check-prefix=DIS + +.globl _start +_start: + .functype _start () -> (i32) + global.get tls_sym@GOT@TLS + end_function + +.section .tdata.tls_sym,"",@ +.globl tls_sym +tls_sym: + .int32 1 + .size tls_sym, 4 + +.section .custom_section.target_features,"",@ + .int8 2 + .int8 43 + .int8 30 + .ascii "component-model-thread-context" + .int8 43 + .int8 11 + .ascii "bulk-memory" + + +# CHECK: Name: __init_tls_base +# DIS: __wasm_init_tls \ No newline at end of file From fa7eea8ec4af4a799efb592ce4ff8c211fb6e138 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 18 Feb 2026 13:27:27 +0000 Subject: [PATCH 032/134] Continue rather than break when determiting thread context ABI --- lld/wasm/Driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index a9f9566b3efb4..f4924329e99c2 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -1347,7 +1347,7 @@ static void determineThreadContextABI(ArrayRef files) { if (!sym || sym->kind() != Symbol::UndefinedGlobalKind || sym->importModule != "env") { // No __stack_pointer import, so this is probably an object file compiled from assembly or // some other source that doesn't care about the thread context ABI. As such, we let it pass. - break; + continue; } } From cc1ea2f624645452e5aa28fff131c8ce89c56bfd Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 18 Feb 2026 13:45:43 +0000 Subject: [PATCH 033/134] Only consider the current object file's symbols for determining thread context ABI --- lld/wasm/Driver.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index f4924329e99c2..53497685c2f6b 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -1342,14 +1342,20 @@ static void determineThreadContextABI(ArrayRef files) { if (threadContextFeature == targetFeatures.end()) { // If the feature is not explicitly used or disallowed, check for the presence of __stack_pointer - // to determine if the global thread context ABI is being used. - auto sym = symtab->find("__stack_pointer"); - if (!sym || sym->kind() != Symbol::UndefinedGlobalKind || sym->importModule != "env") { + // import in this specific file to determine if the global thread context ABI is being used. + bool hasStackPointerImport = llvm::any_of(obj->getSymbols(), [](const auto &sym) { + return sym && sym->getName() == "__stack_pointer" && + sym->kind() == Symbol::UndefinedGlobalKind && + sym->importModule && sym->importModule == "env"; + }); + if (!hasStackPointerImport) { // No __stack_pointer import, so this is probably an object file compiled from assembly or // some other source that doesn't care about the thread context ABI. As such, we let it pass. continue; } - } + // Treat this as using the globals ABI + usesComponentModelThreadContext = false; + } if (usesComponentModelThreadContext) { if (threadContextABI == ThreadContextABI::Undetermined) { From b9039ebfeb0966a6b9aa6f35d770f36572552fef Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 18 Feb 2026 13:46:01 +0000 Subject: [PATCH 034/134] Typo --- lld/wasm/Driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 53497685c2f6b..1b2cab417c426 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -1341,7 +1341,7 @@ static void determineThreadContextABI(ArrayRef files) { threadContextFeature->Prefix == WASM_FEATURE_PREFIX_USED; if (threadContextFeature == targetFeatures.end()) { - // If the feature is not explicitly used or disallowed, check for the presence of __stack_pointer + // If the feature is not explicitly used or disallowed, check for the presence of a __stack_pointer // import in this specific file to determine if the global thread context ABI is being used. bool hasStackPointerImport = llvm::any_of(obj->getSymbols(), [](const auto &sym) { return sym && sym->getName() == "__stack_pointer" && From 1b490cdd9578877336d653b45180ccf5fc71eb2f Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 18 Feb 2026 13:46:48 +0000 Subject: [PATCH 035/134] Formatting --- lld/wasm/Driver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 1b2cab417c426..19881d1ae50df 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -1376,6 +1376,7 @@ static void determineThreadContextABI(ArrayRef files) { // If the ABI is undetermined at this point, default to the globals ABI ctx.componentModelThreadContext = (threadContextABI == ThreadContextABI::ComponentModelBuiltins); + if (ctx.arg.sharedMemory && ctx.componentModelThreadContext) { error("--shared-memory is currently incompatible with component model thread context intrinsics"); } From b55ae63edc37da979002ffd72c5a528caad25575 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 18 Feb 2026 14:32:19 +0000 Subject: [PATCH 036/134] TLS fixes --- lld/test/wasm/tls-component-model.s | 2 +- lld/wasm/Driver.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lld/test/wasm/tls-component-model.s b/lld/test/wasm/tls-component-model.s index d347ec0c1f2dc..3f10d497b237f 100644 --- a/lld/test/wasm/tls-component-model.s +++ b/lld/test/wasm/tls-component-model.s @@ -1,5 +1,5 @@ # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s -# RUN: wasm-ld -o %t.wasm %t.o +# RUN: wasm-ld -no-gc-sections -o %t.wasm %t.o # RUN: obj2yaml %t.wasm | FileCheck %s # RUN: llvm-objdump -d --no-show-raw-insn %t.wasm | FileCheck %s --check-prefix=DIS diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 19881d1ae50df..22a2c5ba17e07 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -1006,7 +1006,6 @@ static void createPostLTOSymbols() { ctx.sym.tlsBase->markLive(); ctx.sym.tlsSize->markLive(); ctx.sym.tlsAlign->markLive(); - ctx.sym.initTLS->markLive(); static WasmSignature contextSet1Signature{{}, {ValType::I32}}; ctx.sym.contextSet1 = createUndefinedFunction( "__wasm_component_model_builtin_context_set_1", "[context-set-1]", @@ -1376,7 +1375,7 @@ static void determineThreadContextABI(ArrayRef files) { // If the ABI is undetermined at this point, default to the globals ABI ctx.componentModelThreadContext = (threadContextABI == ThreadContextABI::ComponentModelBuiltins); - + if (ctx.arg.sharedMemory && ctx.componentModelThreadContext) { error("--shared-memory is currently incompatible with component model thread context intrinsics"); } From a1c563b9d2e251a0977727da86f7b2ed7df91276 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 18 Feb 2026 15:01:09 +0000 Subject: [PATCH 037/134] Tighten up Toolchain driver --- clang/lib/Driver/ToolChains/WebAssembly.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 53a22f3a9f9c6..6d3619b00471b 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -79,8 +79,17 @@ static bool WantsPthread(const llvm::Triple &Triple, const ArgList &Args) { return WantsPthread; } +static bool WantsComponentModelThreadContext(const llvm::Triple &Triple, const ArgList &Args) { + // If the target is WASIP3, then enable the + // component-model-thread-context feature by default, unless explicitly + // disabled. + return Triple.getOSName() == "wasip3" && + Args.hasFlag(options::OPT_mcomponent_model_thread_context, + options::OPT_mno_component_model_thread_context, true); +} + static bool WantsSharedMemory(const llvm::Triple &Triple, const ArgList &Args) { - return WantsPthread(Triple, Args) && !TargetBuildsComponents(Triple); + return WantsPthread(Triple, Args) && !WantsComponentModelThreadContext(Triple, Args); } void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -321,7 +330,7 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, << "-mno-bulk-memory"; CC1Args.push_back("-target-feature"); CC1Args.push_back("+bulk-memory"); - + if (WantsSharedMemory(getTriple(), DriverArgs)) { if (DriverArgs.hasFlag(options::OPT_mno_atomics, options::OPT_matomics, false)) From 69654ef006db053c8e787a54b34ae35757dd7676 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 18 Feb 2026 15:29:29 +0000 Subject: [PATCH 038/134] Fix clang test --- clang/test/Driver/wasm-toolchain.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/clang/test/Driver/wasm-toolchain.c b/clang/test/Driver/wasm-toolchain.c index 4a22ea8a02417..a1c726a0aae09 100644 --- a/clang/test/Driver/wasm-toolchain.c +++ b/clang/test/Driver/wasm-toolchain.c @@ -77,13 +77,13 @@ // '-pthread' sets +atomics, +bulk-memory, +mutable-globals, +sign-ext, and --shared-memory // RUN: %clang -### --target=wasm32-unknown-unknown --sysroot=/foo %s -pthread 2>&1 \ // RUN: | FileCheck -check-prefix=PTHREAD %s -// PTHREAD: "-cc1" {{.*}} "-target-feature" "+atomics" "-target-feature" "+bulk-memory" "-target-feature" "+mutable-globals" "-target-feature" "+sign-ext" +// PTHREAD: "-cc1" {{.*}} "-target-feature" "+bulk-memory" "-target-feature" "+atomics" "-target-feature" "+mutable-globals" "-target-feature" "+sign-ext" // PTHREAD: wasm-ld{{.*}}" "--shared-memory" "-lpthread" // // '-pthread' with '-nostdlib' should still set '--shared-memory' but not include '-lpthread' // RUN: %clang -### --target=wasm32-unknown-unknown --sysroot=/foo %s -pthread -nostdlib 2>&1 \ // RUN: | FileCheck -check-prefix=PTHREAD-NOSTDLIB %s -// PTHREAD-NOSTDLIB: "-cc1" {{.*}} "-target-feature" "+atomics" "-target-feature" "+bulk-memory" "-target-feature" "+mutable-globals" "-target-feature" "+sign-ext" +// PTHREAD-NOSTDLIB: "-cc1" {{.*}} "-target-feature" "+bulk-memory" "-target-feature" "+atomics" "-target-feature" "+mutable-globals" "-target-feature" "+sign-ext" // PTHREAD-NOSTDLIB: wasm-ld{{.*}}" "--shared-memory" "-o" "a.out" // '-pthread' not allowed with '-mno-atomics' @@ -113,7 +113,7 @@ // 'wasm32-wasi-threads' does the same thing as '-pthread' // RUN: %clang -### --target=wasm32-wasi-threads --sysroot=/foo %s 2>&1 \ // RUN: | FileCheck -check-prefix=WASI_THREADS %s -// WASI_THREADS: "-cc1" {{.*}} "-target-feature" "+atomics" "-target-feature" "+bulk-memory" "-target-feature" "+mutable-globals" "-target-feature" "+sign-ext" +// WASI_THREADS: "-cc1" {{.*}} "-target-feature" "+bulk-memory" "-target-feature" "+atomics" "-target-feature" "+mutable-globals" "-target-feature" "+sign-ext" // WASI_THREADS: wasm-ld{{.*}}" "--shared-memory" "-lpthread" // '-mllvm -emscripten-cxx-exceptions-allowed=foo,bar' sets @@ -303,7 +303,3 @@ // RUN: | FileCheck -check-prefix=LINK_WALI_BASIC %s // LINK_WALI_BASIC: "-cc1" {{.*}} "-o" "[[temp:[^"]*]]" // LINK_WALI_BASIC: wasm-ld{{.*}}" "-L/foo/lib/wasm32-linux-muslwali" "crt1.o" "[[temp]]" "-lc" "{{.*[/\\]}}libclang_rt.builtins.a" "-o" "a.out" - -// `-target=wasm32-wasip2` sets -component-model-thread-context -// RUN: %clang --target=wasm32-wasip2 %s -### 2>&1 | FileCheck -check-prefix=WASIP3_DISABLED %s -// WASIP3_DISABLED: "-target-feature" "-component-model-thread-context" \ No newline at end of file From b98b9ab199b87cd597912d1871da807b28c4ab4b Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 18 Feb 2026 15:39:04 +0000 Subject: [PATCH 039/134] Add wasm-target-features test for preprocessor defines --- clang/test/Preprocessor/wasm-target-features.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/clang/test/Preprocessor/wasm-target-features.c b/clang/test/Preprocessor/wasm-target-features.c index 3edaf9e7cd594..86a2ebd59c115 100644 --- a/clang/test/Preprocessor/wasm-target-features.c +++ b/clang/test/Preprocessor/wasm-target-features.c @@ -239,3 +239,12 @@ // RUN: | FileCheck %s -check-prefix=WIDE-ARITHMETIC // // WIDE-ARITHMETIC: #define __wasm_wide_arithmetic__ 1{{$}} + +// RUN: %clang -E -dM %s -o - 2>&1 \ +// RUN: -target wasm32-unknown-unknown -mcomponent-model-thread-context \ +// RUN: | FileCheck %s -check-prefix=COMPONENT-MODEL-THREAD-CONTEXT +// RUN: %clang -E -dM %s -o - 2>&1 \ +// RUN: -target wasm64-unknown-unknown -mcomponent-model-thread-context \ +// RUN: | FileCheck %s -check-prefix=COMPONENT-MODEL-THREAD-CONTEXT + +// COMPONENT-MODEL-THREAD-CONTEXT: #define __wasm_component_model_thread_context__ 1{{$}} \ No newline at end of file From 7121ea5b659abd23af7e9d6a4ab3656bf729dc61 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 18 Feb 2026 17:02:41 +0000 Subject: [PATCH 040/134] Remove debug code --- llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp index 7a9f675548a5c..07defee925877 100644 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -426,7 +426,6 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser { 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()); From 70b3b93176162d563e5f494557ebd16b8b1dfae6 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 18 Feb 2026 17:47:28 +0000 Subject: [PATCH 041/134] Complete asm printing/parsing changes --- .../AsmParser/WebAssemblyAsmParser.cpp | 5 ++- .../WebAssemblyTargetStreamer.cpp | 31 +++++++++++++++---- llvm/test/MC/WebAssembly/export-name.s | 12 +++++++ llvm/test/MC/WebAssembly/import-module.s | 14 +++++++++ 4 files changed, 53 insertions(+), 9 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp index 07defee925877..b48abe85aca91 100644 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -1058,7 +1058,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser { return ParseStatus::Failure; if (expect(AsmToken::Comma, ",")) return ParseStatus::Failure; - auto ExportName = expectIdent(); + auto ExportName = expectStringOrIdent(); if (ExportName.empty()) return ParseStatus::Failure; auto *WasmSym = @@ -1074,8 +1074,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser { return ParseStatus::Failure; if (expect(AsmToken::Comma, ",")) return ParseStatus::Failure; - - StringRef ImportModule = expectStringOrIdent(); + auto ImportModule = expectStringOrIdent(); if (ImportModule.empty()) return ParseStatus::Failure; auto *WasmSym = diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp index c18de5fc1939e..916a42664279f 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -22,6 +22,15 @@ #include "llvm/Support/FormattedStream.h" using namespace llvm; +static bool shouldQuoteName(StringRef Name) { + // Wasm export/import names and import module names can contain characters + // that are not allowed in identifiers, so we need to quote them. + auto isValidStartChar = [](char C) { return isalpha(C) || C == '_' || C == '.'; }; + auto isValidChar = [&](char C) { return isValidStartChar(C) || isdigit(C); }; + return !(Name.size() > 0 && isValidStartChar(Name.front())) || + llvm::any_of(Name, [&](char C) { return !isValidChar(C); }); +} + WebAssemblyTargetStreamer::WebAssemblyTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {} @@ -94,22 +103,32 @@ void WebAssemblyTargetAsmStreamer::emitTagType(const MCSymbolWasm *Sym) { OS << "\n"; } +static void emitNameWithQuoting(formatted_raw_ostream &OS, StringRef Name) { + if (shouldQuoteName(Name)) + OS << '"' << Name << '"'; + else + OS << Name; +} + void WebAssemblyTargetAsmStreamer::emitImportModule(const MCSymbolWasm *Sym, StringRef ImportModule) { - OS << "\t.import_module\t" << Sym->getName() << ", " - << ImportModule << '\n'; + OS << "\t.import_module\t" << Sym->getName() << ", "; + emitNameWithQuoting(OS, ImportModule); + OS << '\n'; } void WebAssemblyTargetAsmStreamer::emitImportName(const MCSymbolWasm *Sym, StringRef ImportName) { - OS << "\t.import_name\t" << Sym->getName() << ", " - << ImportName << '\n'; + OS << "\t.import_name\t" << Sym->getName() << ", "; + emitNameWithQuoting(OS, ImportName); + OS << '\n'; } void WebAssemblyTargetAsmStreamer::emitExportName(const MCSymbolWasm *Sym, StringRef ExportName) { - OS << "\t.export_name\t" << Sym->getName() << ", " - << ExportName << '\n'; + OS << "\t.export_name\t" << Sym->getName() << ", "; + emitNameWithQuoting(OS, ExportName); + OS << '\n'; } void WebAssemblyTargetAsmStreamer::emitIndIdx(const MCExpr *Value) { diff --git a/llvm/test/MC/WebAssembly/export-name.s b/llvm/test/MC/WebAssembly/export-name.s index 51e1bcf73dba2..915cd3307a4b0 100644 --- a/llvm/test/MC/WebAssembly/export-name.s +++ b/llvm/test/MC/WebAssembly/export-name.s @@ -8,7 +8,14 @@ foo: .export_name foo, bar end_function +baz: + .globl baz + .functype baz () -> () + .export_name baz, "[baz]" + end_function + # CHECK: .export_name foo, bar +# CHECK: .export_name baz, "[baz]" # CHECK-OBJ: - Type: EXPORT # CHECK-OBJ-NEXT: Exports: @@ -24,3 +31,8 @@ foo: # CHECK-OBJ-NEXT: Name: foo # CHECK-OBJ-NEXT: Flags: [ EXPORTED ] # CHECK-OBJ-NEXT: Function: 0 +# CHECK-OBJ-NEXT: - Index: 1 +# CHECK-OBJ-NEXT: Kind: FUNCTION +# CHECK-OBJ-NEXT: Name: baz +# CHECK-OBJ-NEXT: Flags: [ EXPORTED ] +# CHECK-OBJ-NEXT: Function: 1 diff --git a/llvm/test/MC/WebAssembly/import-module.s b/llvm/test/MC/WebAssembly/import-module.s index 5d28d5b9c0b92..75090001755a9 100644 --- a/llvm/test/MC/WebAssembly/import-module.s +++ b/llvm/test/MC/WebAssembly/import-module.s @@ -3,16 +3,22 @@ .functype foo () -> () .functype plain () -> () +.functype __wasm_component_model_builtin_context_get_0 () -> (i32) test: .functype test () -> () call foo call plain + call __wasm_component_model_builtin_context_get_0 + drop end_function .import_module foo, bar .import_name foo, qux + .import_module __wasm_component_model_builtin_context_get_0, "$root" + .import_name __wasm_component_model_builtin_context_get_0, "[context-get-0]" + # CHECK-ASM: .import_module foo, bar # CHECK-ASM: .import_name foo, qux @@ -26,9 +32,17 @@ test: # CHECK-NEXT: Field: plain # CHECK-NEXT: Kind: FUNCTION +# CHECK: - Module: '$root' +# CHECK-NEXT: Field: '[context-get-0]' +# CHECK-NEXT: Kind: FUNCTION +# CHECK-NEXT: SigIndex: 1 + # CHECK: - Type: CUSTOM # CHECK: Name: foo # CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ] # CHECK: Name: plain # CHECK-NEXT: Flags: [ UNDEFINED ] + +# CHECK: Name: __wasm_component_model_builtin_context_get_0 +# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ] \ No newline at end of file From 43f756f5618414baef33d5d77db028a9ce1f2656 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 08:57:46 +0000 Subject: [PATCH 042/134] Clean up target feature decision --- clang/lib/Basic/Targets/WebAssembly.cpp | 4 ---- clang/lib/Driver/ToolChains/WebAssembly.cpp | 5 +++++ llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp | 8 -------- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp index bced84f317c76..785bec699f925 100644 --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -215,10 +215,6 @@ bool WebAssemblyTargetInfo::initFeatureMap( addBleedingEdgeFeatures(); } - if (getTriple().getOSName() == "wasip3") { - Features["component-model-thread-context"] = true; - } - return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 6d3619b00471b..4618a62f01cd6 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -320,6 +320,11 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, options::OPT_fno_use_init_array, true)) CC1Args.push_back("-fno-use-init-array"); + if (WantsComponentModelThreadContext(getTriple(), DriverArgs)) { + CC1Args.push_back("-target-feature"); + CC1Args.push_back("+component-model-thread-context"); + } + // '-pthread' implies bulk-memory, and, if shared memory is also used, // also implies atomics, mutable-globals, and sign-ext. if (WantsPthread(getTriple(), DriverArgs)) { diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp index fa99249840dd9..b0a8be810caa5 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp @@ -40,14 +40,6 @@ WebAssemblySubtarget::initializeSubtargetDependencies(StringRef CPU, ParseSubtargetFeatures(CPU, /*TuneCPU*/ CPU, FS); - // WASIP3 implies using the component model thread context intrinsics by default. - if (!FS.contains("component-model-thread-context") && - !HasComponentModelThreadContext && - TargetTriple.getOSName() == "wasip3") { - ToggleFeature(WebAssembly::FeatureComponentModelThreadContext); - HasComponentModelThreadContext = true; - } - FeatureBitset Bits = getFeatureBits(); // bulk-memory implies bulk-memory-opt From 4ffe62386876ceb65bb0a8cb808a045274bd190f Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 09:01:36 +0000 Subject: [PATCH 043/134] Use llvm::Triple::WASIp3 rather than a string --- clang/lib/Driver/ToolChains/WebAssembly.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 4618a62f01cd6..84b9b00bf4c23 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -83,7 +83,7 @@ static bool WantsComponentModelThreadContext(const llvm::Triple &Triple, const A // If the target is WASIP3, then enable the // component-model-thread-context feature by default, unless explicitly // disabled. - return Triple.getOSName() == "wasip3" && + return Triple.getOS() == llvm::Triple::WASIp3 && Args.hasFlag(options::OPT_mcomponent_model_thread_context, options::OPT_mno_component_model_thread_context, true); } From 36c39bff010e1da9aca7f05632435b5dc12385b0 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 09:16:39 +0000 Subject: [PATCH 044/134] More driver tests --- clang/test/Driver/wasm-toolchain.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/clang/test/Driver/wasm-toolchain.c b/clang/test/Driver/wasm-toolchain.c index a1c726a0aae09..7dbf1d6ce6aa5 100644 --- a/clang/test/Driver/wasm-toolchain.c +++ b/clang/test/Driver/wasm-toolchain.c @@ -303,3 +303,15 @@ // RUN: | FileCheck -check-prefix=LINK_WALI_BASIC %s // LINK_WALI_BASIC: "-cc1" {{.*}} "-o" "[[temp:[^"]*]]" // LINK_WALI_BASIC: wasm-ld{{.*}}" "-L/foo/lib/wasm32-linux-muslwali" "crt1.o" "[[temp]]" "-lc" "{{.*[/\\]}}libclang_rt.builtins.a" "-o" "a.out" + +// `wasm32-wasip3` passes `+component-model-thread-context` by default. + +// RUN: %clang -### --target=wasm32-wasip3 --sysroot=/foo %s 2>&1 \ +// RUN: | FileCheck -check-prefix=LINK_WASIP3_THREAD_CONTEXT %s +// LINK_WASIP3_THREAD_CONTEXT: "-cc1" {{.*}} "-target-feature" "+component-model-thread-context" + +// `wasm32-wasip3` does not pass `+component-model-thread-context` when `-mno-component-model-thread-context` is used. + +// RUN: %clang -### --target=wasm32-wasip3 --sysroot=/foo -mno-component-model-thread-context %s 2>&1 \ +// RUN: | FileCheck -check-prefix=LINK_WASIP3_NO_THREAD_CONTEXT %s +// LINK_WASIP3_NO_THREAD_CONTEXT: "-cc1" {{.*}} "-target-feature" "-component-model-thread-context" From d9535100967bc9227e23d4ad18370449ec7ae478 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 09:57:54 +0000 Subject: [PATCH 045/134] Fix tests --- .../CodeGen/WebAssembly/memory64-feature.ll | 5 ++- llvm/test/CodeGen/WebAssembly/multivalue.ll | 5 ++- .../CodeGen/WebAssembly/mutable-globals.ll | 5 ++- .../CodeGen/WebAssembly/reference-types.ll | 5 ++- llvm/test/CodeGen/WebAssembly/tailcall.ll | 5 ++- .../WebAssembly/target-features-attrs.ll | 14 +++++-- .../WebAssembly/target-features-cpus.ll | 29 ++++++++++---- .../WebAssembly/target-features-tls.ll | 40 ++++++++++++++++++- 8 files changed, 90 insertions(+), 18 deletions(-) diff --git a/llvm/test/CodeGen/WebAssembly/memory64-feature.ll b/llvm/test/CodeGen/WebAssembly/memory64-feature.ll index bd277dfdc37d3..c27756a00b4f7 100644 --- a/llvm/test/CodeGen/WebAssembly/memory64-feature.ll +++ b/llvm/test/CodeGen/WebAssembly/memory64-feature.ll @@ -9,7 +9,10 @@ define void @foo() { } ; CHECK-LABEL: .custom_section.target_features -; CHECK-NEXT: .int8 1 +; CHECK-NEXT: .int8 2 +; CHECK-NEXT: .int8 45 +; CHECK-NEXT: .int8 30 +; CHECK-NEXT: .ascii "component-model-thread-context" ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 8 ; CHECK-NEXT: .ascii "memory64" diff --git a/llvm/test/CodeGen/WebAssembly/multivalue.ll b/llvm/test/CodeGen/WebAssembly/multivalue.ll index 5001db7e57a1e..2b64ebf2f1680 100644 --- a/llvm/test/CodeGen/WebAssembly/multivalue.ll +++ b/llvm/test/CodeGen/WebAssembly/multivalue.ll @@ -252,7 +252,10 @@ loop: } ; CHECK-LABEL: .section .custom_section.target_features -; CHECK-NEXT: .int8 2 +; CHECK-NEXT: .int8 3 +; CHECK-NEXT: .int8 45 +; CHECK-NEXT: .int8 30 +; CHECK-NEXT: .ascii "component-model-thread-context" ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 10 ; CHECK-NEXT: .ascii "multivalue" diff --git a/llvm/test/CodeGen/WebAssembly/mutable-globals.ll b/llvm/test/CodeGen/WebAssembly/mutable-globals.ll index 93962f7e6d92c..24e28c52f98cc 100644 --- a/llvm/test/CodeGen/WebAssembly/mutable-globals.ll +++ b/llvm/test/CodeGen/WebAssembly/mutable-globals.ll @@ -9,7 +9,10 @@ define void @foo() { } ; CHECK-LABEL: .custom_section.target_features -; CHECK-NEXT: .int8 1 +; CHECK-NEXT: .int8 2 +; CHECK-NEXT: .int8 45 +; CHECK-NEXT: .int8 30 +; CHECK-NEXT: .ascii "component-model-thread-context" ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 15 ; CHECK-NEXT: .ascii "mutable-globals" diff --git a/llvm/test/CodeGen/WebAssembly/reference-types.ll b/llvm/test/CodeGen/WebAssembly/reference-types.ll index 3df383b023726..dbe1a4b029312 100644 --- a/llvm/test/CodeGen/WebAssembly/reference-types.ll +++ b/llvm/test/CodeGen/WebAssembly/reference-types.ll @@ -8,10 +8,13 @@ define void @reference-types() { } ; CHECK: .section .custom_section.target_features,"",@ -; CHECK-NEXT: .int8 2 +; CHECK-NEXT: .int8 3 ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 22 ; CHECK-NEXT: .ascii "call-indirect-overlong" +; CHECK-NEXT: .int8 45 +; CHECK-NEXT: .int8 30 +; CHECK-NEXT: .ascii "component-model-thread-context" ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 15 ; CHECK-NEXT: .ascii "reference-types" diff --git a/llvm/test/CodeGen/WebAssembly/tailcall.ll b/llvm/test/CodeGen/WebAssembly/tailcall.ll index 84bd142462e37..ce94fc9a22615 100644 --- a/llvm/test/CodeGen/WebAssembly/tailcall.ll +++ b/llvm/test/CodeGen/WebAssembly/tailcall.ll @@ -584,7 +584,10 @@ define i32 @unique_caller(ptr %p) { } ; CHECK-LABEL: .section .custom_section.target_features -; CHECK-NEXT: .int8 1 +; CHECK-NEXT: .int8 2 +; CHECK-NEXT: .int8 45 +; CHECK-NEXT: .int8 30 +; CHECK-NEXT: .ascii "component-model-thread-context" ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 9 ; CHECK-NEXT: .ascii "tail-call" diff --git a/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll b/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll index 0e46b96591816..cec038aae490d 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll @@ -53,15 +53,18 @@ attributes #2 = { "target-features"="+reference-types" } ; CHECK: i32.store ; Features in function attributes: -; +atomics, +nontrapping-fptoint, +reference-types +; +atomics, +nontrapping-fptoint, +reference-types, -component-model-thread-context ; CHECK-LABEL: .custom_section.target_features,"",@ -; CHECK-NEXT: .int8 4 +; CHECK-NEXT: .int8 5 ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 7 ; CHECK-NEXT: .ascii "atomics" ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 22 ; CHECK-NEXT: .ascii "call-indirect-overlong" +; CHECK-NEXT: .int8 45 +; CHECK-NEXT: .int8 30 +; CHECK-NEXT: .ascii "component-model-thread-context" ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 19 ; CHECK-NEXT: .ascii "nontrapping-fptoint" @@ -70,15 +73,18 @@ attributes #2 = { "target-features"="+reference-types" } ; CHECK-NEXT: .ascii "reference-types" ; Features in function attributes + features specified by -mattr= option: -; +atomics, +nontrapping-fptoint, +reference-types, +simd128 +; +atomics, +nontrapping-fptoint, +reference-types, +simd128, -component-model-thread-context ; SIMD128-LABEL: .custom_section.target_features,"",@ -; SIMD128-NEXT: .int8 5 +; SIMD128-NEXT: .int8 6 ; SIMD128-NEXT: .int8 43 ; SIMD128-NEXT: .int8 7 ; SIMD128-NEXT: .ascii "atomics" ; SIMD128-NEXT: .int8 43 ; SIMD128-NEXT: .int8 22 ; SIMD128-NEXT: .ascii "call-indirect-overlong" +; SIMD128-NEXT: .int8 45 +; SIMD128-NEXT: .int8 30 +; SIMD128-NEXT: .ascii "component-model-thread-context" ; SIMD128-NEXT: .int8 43 ; SIMD128-NEXT: .int8 19 ; SIMD128-NEXT: .ascii "nontrapping-fptoint" diff --git a/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll b/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll index 4a4973b034637..ff82e2ae6894a 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll @@ -9,12 +9,17 @@ target triple = "wasm32-unknown-unknown" -; mvp: should not contain the target features section -; MVP-NOT: .custom_section.target_features,"",@ +; mvp: -component_model_thread_context +; MVP-LABEL: .section .custom_section.target_features,"",@ +; MVP-NEXT: .int8 1 +; MVP-NEXT: .int8 45 +; MVP-NEXT: .int8 30 +; MVP-NEXT: .ascii "component-model-thread-context" +; MVP-NEXT: .text -; generic: +call-indirect-overlong, +multivalue, +mutable-globals, +reference-types, +sign-ext +; generic: +call-indirect-overlong, +multivalue, +mutable-globals, +reference-types, +sign-ext, -component-model-thread-context ; GENERIC-LABEL: .custom_section.target_features,"",@ -; GENERIC-NEXT: .int8 8 +; GENERIC-NEXT: .int8 9 ; GENERIC-NEXT: .int8 43 ; GENERIC-NEXT: .int8 11 ; GENERIC-NEXT: .ascii "bulk-memory" @@ -24,6 +29,9 @@ target triple = "wasm32-unknown-unknown" ; GENERIC-NEXT: .int8 43 ; GENERIC-NEXT: .int8 22 ; GENERIC-NEXT: .ascii "call-indirect-overlong" +; GENERIC-NEXT: .int8 45 +; GENERIC-NEXT: .int8 30 +; GENERIC-NEXT: .ascii "component-model-thread-context" ; GENERIC-NEXT: .int8 43 ; GENERIC-NEXT: .int8 10 ; GENERIC-NEXT: .ascii "multivalue" @@ -41,15 +49,18 @@ target triple = "wasm32-unknown-unknown" ; GENERIC-NEXT: .ascii "sign-ext" ; lime1: +bulk-memory-opt, +call-indirect-overlong, +extended-const, +multivalue, -; +mutable-globals, +nontrapping-fptoint, +sign-ext +; +mutable-globals, +nontrapping-fptoint, +sign-ext, -component-model-thread-context ; LIME1-LABEL: .custom_section.target_features,"",@ -; LIME1-NEXT: .int8 7 +; LIME1-NEXT: .int8 8 ; LIME1-NEXT: .int8 43 ; LIME1-NEXT: .int8 15 ; LIME1-NEXT: .ascii "bulk-memory-opt" ; LIME1-NEXT: .int8 43 ; LIME1-NEXT: .int8 22 ; LIME1-NEXT: .ascii "call-indirect-overlong" +; LIME1-NEXT: .int8 45 +; LIME1-NEXT: .int8 30 +; LIME1-NEXT: .ascii "component-model-thread-context" ; LIME1-NEXT: .int8 43 ; LIME1-NEXT: .int8 14 ; LIME1-NEXT: .ascii "extended-const" @@ -71,8 +82,9 @@ target triple = "wasm32-unknown-unknown" ; +extended-const, +fp16, +gc, +multimemory, +multivalue, ; +mutable-globals, +nontrapping-fptoint, +relaxed-simd, ; +reference-types, +simd128, +sign-ext, +tail-call +; -component-model-thread-context ; BLEEDING-EDGE-LABEL: .section .custom_section.target_features,"",@ -; BLEEDING-EDGE-NEXT: .int8 17 +; BLEEDING-EDGE-NEXT: .int8 18 ; BLEEDING-EDGE-NEXT: .int8 43 ; BLEEDING-EDGE-NEXT: .int8 7 ; BLEEDING-EDGE-NEXT: .ascii "atomics" @@ -85,6 +97,9 @@ target triple = "wasm32-unknown-unknown" ; BLEEDING-EDGE-NEXT: .int8 43 ; BLEEDING-EDGE-NEXT: .int8 22 ; BLEEDING-EDGE-NEXT: .ascii "call-indirect-overlong" +; BLEEDING-EDGE-NEXT: .int8 45 +; BLEEDING-EDGE-NEXT: .int8 30 +; BLEEDING-EDGE-NEXT: .ascii "component-model-thread-context" ; BLEEDING-EDGE-NEXT: .int8 43 ; BLEEDING-EDGE-NEXT: .int8 18 ; BLEEDING-EDGE-NEXT: .ascii "exception-handling" diff --git a/llvm/test/CodeGen/WebAssembly/target-features-tls.ll b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll index 4abe01a73aeee..5730d2fd9a57d 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-tls.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll @@ -1,5 +1,7 @@ ; RUN: llc < %s -mcpu=mvp -mattr=-bulk-memory,atomics | FileCheck %s --check-prefixes NO-BULK-MEM ; RUN: llc < %s -mcpu=mvp -mattr=+bulk-memory,atomics | FileCheck %s --check-prefixes BULK-MEM +; RUN: llc < %s -mcpu=mvp -mattr=+component-model-thread-context,-bulk-memory,atomics | FileCheck %s --check-prefixes NO-BULK-MEM-CMTC +; RUN: llc < %s -mcpu=mvp -mattr=+component-model-thread-context,bulk-memory,atomics | FileCheck %s --check-prefixes BULK-MEM-CMTC ; Test that the target features section contains -atomics or +atomics ; for modules that have thread local storage in their source. @@ -10,18 +12,21 @@ target triple = "wasm32-unknown-unknown" ; -bulk-memory ; NO-BULK-MEM-LABEL: .custom_section.target_features,"",@ -; NO-BULK-MEM-NEXT: .int8 2 +; NO-BULK-MEM-NEXT: .int8 3 ; NO-BULK-MEM-NEXT: .int8 43 ; NO-BULK-MEM-NEXT: .int8 7 ; NO-BULK-MEM-NEXT: .ascii "atomics" ; NO-BULK-MEM-NEXT: .int8 45 +; NO-BULK-MEM-NEXT: .int8 30 +; NO-BULK-MEM-NEXT: .ascii "component-model-thread-context" +; NO-BULK-MEM-NEXT: .int8 45 ; NO-BULK-MEM-NEXT: .int8 10 ; NO-BULK-MEM-NEXT: .ascii "shared-mem" ; NO-BULK-MEM-NEXT: .bss.foo,"",@ ; +bulk-memory ; BULK-MEM-LABEL: .custom_section.target_features,"",@ -; BULK-MEM-NEXT: .int8 3 +; BULK-MEM-NEXT: .int8 4 ; BULK-MEM-NEXT: .int8 43 ; BULK-MEM-NEXT: .int8 7 ; BULK-MEM-NEXT: .ascii "atomics" @@ -31,4 +36,35 @@ target triple = "wasm32-unknown-unknown" ; BULK-MEM-NEXT: .int8 43 ; BULK-MEM-NEXT: .int8 15 ; BULK-MEM-NEXT: .ascii "bulk-memory-opt" +; BULK-MEM-NEXT: .int8 45 +; BULK-MEM-NEXT: .int8 30 +; BULK-MEM-NEXT: .ascii "component-model-thread-context" ; BULK-MEM-NEXT: .tbss.foo,"T",@ + +; -bulk-memory,+component-model-thread-context +; NO-BULK-MEM-CMTC-LABEL: .custom_section.target_features,"",@ +; NO-BULK-MEM-CMTC-NEXT: .int8 2 +; NO-BULK-MEM-CMTC-NEXT: .int8 43 +; NO-BULK-MEM-CMTC-NEXT: .int8 7 +; NO-BULK-MEM-CMTC-NEXT: .ascii "atomics" +; NO-BULK-MEM-CMTC-NEXT: .int8 43 +; NO-BULK-MEM-CMTC-NEXT: .int8 30 +; NO-BULK-MEM-CMTC-NEXT: .ascii "component-model-thread-context" +; NO-BULK-MEM-CMTC-NEXT: .tbss.foo,"T",@ + +; +bulk-memory,+component-model-thread-context +; BULK-MEM-CMTC-LABEL: .custom_section.target_features,"",@ +; BULK-MEM-CMTC-NEXT: .int8 4 +; BULK-MEM-CMTC-NEXT: .int8 43 +; BULK-MEM-CMTC-NEXT: .int8 7 +; BULK-MEM-CMTC-NEXT: .ascii "atomics" +; BULK-MEM-CMTC-NEXT: .int8 43 +; BULK-MEM-CMTC-NEXT: .int8 11 +; BULK-MEM-CMTC-NEXT: .ascii "bulk-memory" +; BULK-MEM-CMTC-NEXT: .int8 43 +; BULK-MEM-CMTC-NEXT: .int8 15 +; BULK-MEM-CMTC-NEXT: .ascii "bulk-memory-opt" +; BULK-MEM-CMTC-NEXT: .int8 43 +; BULK-MEM-CMTC-NEXT: .int8 30 +; BULK-MEM-CMTC-NEXT: .ascii "component-model-thread-context" +; BULK-MEM-CMTC-NEXT: .tbss.foo,"T",@ \ No newline at end of file From 0656bbf5ee8a1e798645b3dd8636e29ccdaf5549 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 10:07:10 +0000 Subject: [PATCH 046/134] Strip thread locals if no bulk memory --- llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index b484468d95a1e..3c620b4bda6f8 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -294,6 +294,9 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { if (!Features[WebAssembly::FeatureAtomics]) { StrippedAtomics = stripAtomics(M); } + if (!Features[WebAssembly::FeatureBulkMemory]) { + StrippedTLS = stripThreadLocals(M); + } } else { if (!Features[WebAssembly::FeatureAtomics]) { StrippedAtomics = stripAtomics(M); From c5190fff2cbdb40b076d861fd0cb2047cd7e8680 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 10:07:22 +0000 Subject: [PATCH 047/134] Thread pointer test --- llvm/test/CodeGen/WebAssembly/thread_pointer.ll | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/llvm/test/CodeGen/WebAssembly/thread_pointer.ll b/llvm/test/CodeGen/WebAssembly/thread_pointer.ll index 18716988673db..7655859c2938a 100644 --- a/llvm/test/CodeGen/WebAssembly/thread_pointer.ll +++ b/llvm/test/CodeGen/WebAssembly/thread_pointer.ll @@ -1,6 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=wasm32-unknown-unknown | FileCheck %s --check-prefix=WASM32 ; RUN: llc < %s -mtriple=wasm64-unknown-unknown | FileCheck %s --check-prefix=WASM64 +; RUN: llc < %s -mtriple=wasm32-unknown-unknown -mattr=+component-model-thread-context | FileCheck %s --check-prefix=WASM32-CMTC declare ptr @llvm.thread.pointer() @@ -16,6 +17,13 @@ define ptr @thread_pointer() nounwind { ; WASM64-NEXT: # %bb.0: ; WASM64-NEXT: global.get __tls_base ; WASM64-NEXT: # fallthrough-return +; +; WASM32-CMTC-LABEL: thread_pointer: +; WASM32-CMTC: .functype thread_pointer () -> (i32) +; WASM32-CMTC-NEXT: # %bb.0: +; WASM32-CMTC-NEXT: call __wasm_component_model_builtin_context_get_1 +; WASM32-CMTC-NEXT: # fallthrough-return +; %1 = tail call ptr @llvm.thread.pointer() ret ptr %1 } From 6e0c9c036ac2ea0949f71d3b7e3ac089a548d5ac Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 10:14:50 +0000 Subject: [PATCH 048/134] TLS local exec test --- .../CodeGen/WebAssembly/tls-local-exec.ll | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll b/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll index dc0d40c7973ad..4e2a7fd79e9c7 100644 --- a/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll +++ b/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll @@ -1,13 +1,16 @@ ; Run the tests with the `localexec` TLS mode specified. ; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,TLS %s ; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS %s +; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+component-model-thread-context,bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS-CMTC %s ; Also, run the same tests without a specified TLS mode--this should still emit `localexec` code on non-Emscripten targtes which don't currently support dynamic linking. ; RUN: sed -e 's/\[\[TLS_MODE\]\]//' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,TLS %s ; RUN: sed -e 's/\[\[TLS_MODE\]\]//' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS %s +; RUN: sed -e 's/\[\[TLS_MODE\]\]//' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+component-model-thread-context,bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS-CMTC %s ; Finally, when bulk memory is disabled, no TLS code should be generated. ; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=-bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,NO-TLS %s +; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+component-model-thread-context,-bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,NO-TLS %s target triple = "wasm32-unknown-unknown" ; CHECK-LABEL: address_of_tls: @@ -18,6 +21,11 @@ define i32 @address_of_tls() { ; TLS-NEXT: i32.add ; TLS-NEXT: return + ; TLS-CMTC-DAG: call __wasm_component_model_builtin_context_get_1 + ; TLS-CMTC-DAG: i32.const tls@TLSREL + ; TLS-CMTC-NEXT: i32.add + ; TLS-CMTC-NEXT: return + ; NO-TLS-NEXT: i32.const tls ; NO-TLS-NEXT: return %p = call ptr @llvm.threadlocal.address.p0(ptr @tls) @@ -33,6 +41,11 @@ define i32 @address_of_tls_external() { ; TLS-NEXT: i32.add ; TLS-NEXT: return + ; TLS-CMTC-DAG: call __wasm_component_model_builtin_context_get_1 + ; TLS-CMTC-DAG: i32.const tls_external@TLSREL + ; TLS-CMTC-NEXT: i32.add + ; TLS-CMTC-NEXT: return + ; NO-TLS-NEXT: i32.const tls_external ; NO-TLS-NEXT: return %p = call ptr @llvm.threadlocal.address.p0(ptr @tls_external) @@ -48,6 +61,11 @@ define ptr @ptr_to_tls() { ; TLS-NEXT: i32.add ; TLS-NEXT: return + ; TLS-CMTC-DAG: call __wasm_component_model_builtin_context_get_1 + ; TLS-CMTC-DAG: i32.const tls@TLSREL + ; TLS-CMTC-NEXT: i32.add + ; TLS-CMTC-NEXT: return + ; NO-TLS-NEXT: i32.const tls ; NO-TLS-NEXT: return %p = call ptr @llvm.threadlocal.address.p0(ptr @tls) @@ -63,6 +81,12 @@ define i32 @tls_load() { ; TLS-NEXT: i32.load 0 ; TLS-NEXT: return + ; TLS-CMTC-DAG: call __wasm_component_model_builtin_context_get_1 + ; TLS-CMTC-DAG: i32.const tls@TLSREL + ; TLS-CMTC-NEXT: i32.add + ; TLS-CMTC-NEXT: i32.load 0 + ; TLS-CMTC-NEXT: return + ; NO-TLS-NEXT: i32.const 0 ; NO-TLS-NEXT: i32.load tls ; NO-TLS-NEXT: return @@ -80,6 +104,12 @@ define void @tls_store(i32 %x) { ; TLS-NEXT: i32.store 0 ; TLS-NEXT: return + ; TLS-CMTC-DAG: call __wasm_component_model_builtin_context_get_1 + ; TLS-CMTC-DAG: i32.const tls@TLSREL + ; TLS-CMTC-NEXT: i32.add + ; TLS-CMTC-NEXT: i32.store 0 + ; TLS-CMTC-NEXT: return + ; NO-TLS-NEXT: i32.const 0 ; NO-TLS-NEXT: i32.store tls ; NO-TLS-NEXT: return @@ -99,6 +129,7 @@ define i32 @tls_size() { ; CHECK: .type tls,@object ; TLS-NEXT: .section .tbss.tls,"T",@ +; TLS-CMTC-NEXT: .section .tbss.tls,"T",@ ; NO-TLS-NEXT: .section .bss.tls,"",@ ; CHECK-NEXT: .p2align 2 ; CHECK-NEXT: tls: From 3386a110968c5bcda20dada319f326a9214ce6d4 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 10:26:25 +0000 Subject: [PATCH 049/134] Add stack abi test --- llvm/test/CodeGen/WebAssembly/stack-abi.ll | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 llvm/test/CodeGen/WebAssembly/stack-abi.ll diff --git a/llvm/test/CodeGen/WebAssembly/stack-abi.ll b/llvm/test/CodeGen/WebAssembly/stack-abi.ll new file mode 100644 index 0000000000000..4f434082c85b2 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/stack-abi.ll @@ -0,0 +1,24 @@ +; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+component-model-thread-context | FileCheck --check-prefix=CMTC %s +; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=-component-model-thread-context | FileCheck --check-prefix=GLOBAL %s + +declare void @force_sp_save() +define void @use_stack() #0 { + %1 = alloca i32, align 4 + %2 = alloca ptr, align 4 + store ptr %1, ptr %2, align 4 + call void @force_sp_save() + ret void +} + +; CMTC-LABEL: use_stack: +; CMTC: call __wasm_component_model_builtin_context_get_0 +; CMTC: call __wasm_component_model_builtin_context_set_0 +; CMTC-NOT: global.get __stack_pointer +; CMTC-NOT: global.set __stack_pointer + +; GLOBAL-LABEL: use_stack: +; GLOBAL: global.get __stack_pointer +; GLOBAL: global.set __stack_pointer +; GLOBAL-NOT: call __wasm_component_model_builtin_context_get_0 +; GLOBAL-NOT: call __wasm_component_model_builtin_context_set_0 + From 57755921a327960069811bc5a61ee8a2aa00e06b Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 10:41:51 +0000 Subject: [PATCH 050/134] Shared memory fixes --- lld/wasm/Writer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 23a9f3ddf8623..119206017ce12 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1167,7 +1167,7 @@ void Writer::createSyntheticInitFunctions() { "__wasm_init_memory", WASM_SYMBOL_VISIBILITY_HIDDEN, make(nullSignature, "__wasm_init_memory")); ctx.sym.initMemory->markLive(); - if (ctx.isMultithreaded()) { + if (ctx.arg.sharedMemory) { // This global is assigned during __wasm_init_memory in the shared memory // case. ctx.sym.tlsBase->markLive(); From 4d7a81e0f0d2cdc7ac7188ce3ed4482154c37b89 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 11:11:32 +0000 Subject: [PATCH 051/134] Enable component model context in WASIP3 in LLVM --- .../WebAssembly/WebAssemblySubtarget.cpp | 9 +++ .../target-features-thread-context.ll | 70 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp index b0a8be810caa5..20bd0c3b1b923 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp @@ -40,6 +40,15 @@ WebAssemblySubtarget::initializeSubtargetDependencies(StringRef CPU, ParseSubtargetFeatures(CPU, /*TuneCPU*/ CPU, FS); + // WASIP3 implies using the component model thread context intrinsics by + // default, unless explicitly disabled. + if (!FS.contains("component-model-thread-context") && + !HasComponentModelThreadContext && + TargetTriple.getOS() == Triple::WASIp3) { + ToggleFeature(WebAssembly::FeatureComponentModelThreadContext); + HasComponentModelThreadContext = true; + } + FeatureBitset Bits = getFeatureBits(); // bulk-memory implies bulk-memory-opt diff --git a/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll b/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll new file mode 100644 index 0000000000000..9592c35081c2a --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll @@ -0,0 +1,70 @@ +; RUN: llc < %s -mtriple=wasm32-wasip3 | FileCheck %s --check-prefix=WASIP3 +; RUN: llc < %s -mtriple=wasm32-wasip3 -mattr=-component-model-thread-context | FileCheck %s --check-prefix=EXPLICIT-DISABLE +; RUN: llc < %s -mtriple=wasm32-wasip1 | FileCheck %s --check-prefix=WASIP1 +; RUN: llc < %s -mtriple=wasm32-wasip2 | FileCheck %s --check-prefix=WASIP2 + +; Test that wasip3 target automatically enables component-model-thread-context + +; WASIP3: .section .custom_section.target_features,"",@ +; WASIP3-NEXT: .int8 9 +; WASIP3-NEXT: .int8 43 +; WASIP3-NEXT: .int8 11 +; WASIP3-NEXT: .ascii "bulk-memory" +; WASIP3-NEXT: .int8 43 +; WASIP3-NEXT: .int8 15 +; WASIP3-NEXT: .ascii "bulk-memory-opt" +; WASIP3-NEXT: .int8 43 +; WASIP3-NEXT: .int8 22 +; WASIP3-NEXT: .ascii "call-indirect-overlong" +; WASIP3-NEXT: .int8 43 +; WASIP3-NEXT: .int8 30 +; WASIP3-NEXT: .ascii "component-model-thread-context" + +; EXPLICIT-DISABLE: .section .custom_section.target_features,"",@ +; EXPLICIT-DISABLE-NEXT: .int8 9 +; EXPLICIT-DISABLE-NEXT: .int8 43 +; EXPLICIT-DISABLE-NEXT: .int8 11 +; EXPLICIT-DISABLE-NEXT: .ascii "bulk-memory" +; EXPLICIT-DISABLE-NEXT: .int8 43 +; EXPLICIT-DISABLE-NEXT: .int8 15 +; EXPLICIT-DISABLE-NEXT: .ascii "bulk-memory-opt" +; EXPLICIT-DISABLE-NEXT: .int8 43 +; EXPLICIT-DISABLE-NEXT: .int8 22 +; EXPLICIT-DISABLE-NEXT: .ascii "call-indirect-overlong" +; EXPLICIT-DISABLE-NEXT: .int8 45 +; EXPLICIT-DISABLE-NEXT: .int8 30 +; EXPLICIT-DISABLE-NEXT: .ascii "component-model-thread-context" + +; WASIP1: .section .custom_section.target_features,"",@ +; WASIP1-NEXT: .int8 9 +; WASIP1-NEXT: .int8 43 +; WASIP1-NEXT: .int8 11 +; WASIP1-NEXT: .ascii "bulk-memory" +; WASIP1-NEXT: .int8 43 +; WASIP1-NEXT: .int8 15 +; WASIP1-NEXT: .ascii "bulk-memory-opt" +; WASIP1-NEXT: .int8 43 +; WASIP1-NEXT: .int8 22 +; WASIP1-NEXT: .ascii "call-indirect-overlong" +; WASIP1-NEXT: .int8 45 +; WASIP1-NEXT: .int8 30 +; WASIP1-NEXT: .ascii "component-model-thread-context" + +; WASIP2: .section .custom_section.target_features,"",@ +; WASIP2-NEXT: .int8 9 +; WASIP2-NEXT: .int8 43 +; WASIP2-NEXT: .int8 11 +; WASIP2-NEXT: .ascii "bulk-memory" +; WASIP2-NEXT: .int8 43 +; WASIP2-NEXT: .int8 15 +; WASIP2-NEXT: .ascii "bulk-memory-opt" +; WASIP2-NEXT: .int8 43 +; WASIP2-NEXT: .int8 22 +; WASIP2-NEXT: .ascii "call-indirect-overlong" +; WASIP2-NEXT: .int8 45 +; WASIP2-NEXT: .int8 30 +; WASIP2-NEXT: .ascii "component-model-thread-context" + +define void @test() { + ret void +} \ No newline at end of file From 7a447417f1096222c2a09db3adf88db373519206 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 11:48:15 +0000 Subject: [PATCH 052/134] Tighten up linker changes --- lld/wasm/Driver.cpp | 2 +- lld/wasm/Writer.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 22a2c5ba17e07..0c50e12f66e32 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -985,7 +985,7 @@ static void createPostLTOSymbols() { ctx.sym.tableBase->markLive(); } else { // For non-PIC code - ctx.sym.stackPointer = createGlobalVariable(stack_pointer_name, true); + ctx.sym.stackPointer = createGlobalVariable(stack_pointer_name, !ctx.componentModelThreadContext); ctx.sym.stackPointer->markLive(); } diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 119206017ce12..fca033f7b5658 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1181,8 +1181,10 @@ void Writer::createSyntheticInitFunctions() { make(nullSignature, "__wasm_apply_global_tls_relocs")); ctx.sym.applyGlobalTLSRelocs->markLive(); - // TLS relocations depend on the __tls_base symbols - ctx.sym.tlsBase->markLive(); + // Shared memory TLS relocations depend on the __tls_base symbols + if (ctx.arg.sharedMemory) { + ctx.sym.tlsBase->markLive(); + } } auto hasTLSRelocs = [](const OutputSegment *segment) { From 4c62c814ca8ec2929b4c561da64b093017f2b1b8 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 21:25:05 +0000 Subject: [PATCH 053/134] Fix LLVM tests --- llvm/test/CodeGen/WebAssembly/target-features-tls.ll | 7 +++++-- llvm/test/MC/WebAssembly/array-fill.ll | 7 ++++++- llvm/test/MC/WebAssembly/assembler-binary.ll | 7 ++++++- llvm/test/MC/WebAssembly/bss.ll | 7 ++++++- llvm/test/MC/WebAssembly/comdat.ll | 7 ++++++- llvm/test/MC/WebAssembly/debug-info.ll | 6 ++++++ llvm/test/MC/WebAssembly/debug-info64.ll | 6 ++++++ llvm/test/MC/WebAssembly/explicit-sections.ll | 5 +++++ llvm/test/MC/WebAssembly/export-name-invalid.s | 2 +- llvm/test/MC/WebAssembly/global-ctor-dtor.ll | 5 +++++ llvm/test/MC/WebAssembly/import-module-invalid.s | 2 +- llvm/test/MC/WebAssembly/import-name-invalid.s | 2 +- llvm/test/MC/WebAssembly/unnamed-data.ll | 5 +++++ llvm/test/MC/WebAssembly/visibility.ll | 5 +++++ 14 files changed, 64 insertions(+), 9 deletions(-) diff --git a/llvm/test/CodeGen/WebAssembly/target-features-tls.ll b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll index 5730d2fd9a57d..e9d42036a0772 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-tls.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll @@ -43,14 +43,17 @@ target triple = "wasm32-unknown-unknown" ; -bulk-memory,+component-model-thread-context ; NO-BULK-MEM-CMTC-LABEL: .custom_section.target_features,"",@ -; NO-BULK-MEM-CMTC-NEXT: .int8 2 +; NO-BULK-MEM-CMTC-NEXT: .int8 3 ; NO-BULK-MEM-CMTC-NEXT: .int8 43 ; NO-BULK-MEM-CMTC-NEXT: .int8 7 ; NO-BULK-MEM-CMTC-NEXT: .ascii "atomics" ; NO-BULK-MEM-CMTC-NEXT: .int8 43 ; NO-BULK-MEM-CMTC-NEXT: .int8 30 ; NO-BULK-MEM-CMTC-NEXT: .ascii "component-model-thread-context" -; NO-BULK-MEM-CMTC-NEXT: .tbss.foo,"T",@ +; NO-BULK-MEM-CMTC-NEXT: .int8 45 +; NO-BULK-MEM-CMTC-NEXT: .int8 10 +; NO-BULK-MEM-CMTC-NEXT: .ascii "shared-mem" +; NO-BULK-MEM-CMTC-NEXT: .bss.foo,"",@ ; +bulk-memory,+component-model-thread-context ; BULK-MEM-CMTC-LABEL: .custom_section.target_features,"",@ diff --git a/llvm/test/MC/WebAssembly/array-fill.ll b/llvm/test/MC/WebAssembly/array-fill.ll index 4725d4eda065b..0ef4754fc89d6 100644 --- a/llvm/test/MC/WebAssembly/array-fill.ll +++ b/llvm/test/MC/WebAssembly/array-fill.ll @@ -23,4 +23,9 @@ target triple = "wasm32-unknown-unknown" ; CHECK-NEXT: Name: .data ; CHECK-NEXT: Alignment: 0 ; CHECK-NEXT: Flags: [ ] -; CHECK-NEXT: ... +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: target_features +; CHECK-NEXT: Features: +; CHECK-NEXT: - Prefix: DISALLOWED +; CHECK-NEXT: Name: component-model-thread-context +; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/assembler-binary.ll b/llvm/test/MC/WebAssembly/assembler-binary.ll index 32f7d679b8968..7981b01354120 100644 --- a/llvm/test/MC/WebAssembly/assembler-binary.ll +++ b/llvm/test/MC/WebAssembly/assembler-binary.ll @@ -78,4 +78,9 @@ entry: ; CHECK-NEXT: Name: bar ; CHECK-NEXT: Flags: [ UNDEFINED ] ; CHECK-NEXT: Function: 0 -; CHECK-NEXT: ... +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: target_features +; CHECK-NEXT: Features: +; CHECK-NEXT: - Prefix: DISALLOWED +; CHECK-NEXT: Name: component-model-thread-context +; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/bss.ll b/llvm/test/MC/WebAssembly/bss.ll index 4f0c7c8525562..c0b15fc85d389 100644 --- a/llvm/test/MC/WebAssembly/bss.ll +++ b/llvm/test/MC/WebAssembly/bss.ll @@ -78,4 +78,9 @@ target triple = "wasm32-unknown-unknown" ; CHECK-NEXT: Name: .bss.bar ; CHECK-NEXT: Alignment: 0 ; CHECK-NEXT: Flags: [ ] -; CHECK-NEXT: ... +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: target_features +; CHECK-NEXT: Features: +; CHECK-NEXT: - Prefix: DISALLOWED +; CHECK-NEXT: Name: component-model-thread-context +; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/comdat.ll b/llvm/test/MC/WebAssembly/comdat.ll index 0886301597471..2d68bf9baf81b 100644 --- a/llvm/test/MC/WebAssembly/comdat.ll +++ b/llvm/test/MC/WebAssembly/comdat.ll @@ -119,7 +119,12 @@ define linkonce_odr i32 @sharedFn() #1 comdat($sharedComdat) { ; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Kind: DATA ; CHECK-NEXT: Index: 0 -; CHECK-NEXT: ... +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: target_features +; CHECK-NEXT: Features: +; CHECK-NEXT: - Prefix: DISALLOWED +; CHECK-NEXT: Name: component-model-thread-context +; CHECK-NEXT: ... ; ASM: .section .text.basicInlineFn,"G",@,basicInlineFn,comdat diff --git a/llvm/test/MC/WebAssembly/debug-info.ll b/llvm/test/MC/WebAssembly/debug-info.ll index a65ce0ee83920..a9b8ee71ad352 100644 --- a/llvm/test/MC/WebAssembly/debug-info.ll +++ b/llvm/test/MC/WebAssembly/debug-info.ll @@ -141,6 +141,12 @@ ; CHECK-NEXT: Offset: 1164 ; CHECK-NEXT: Name: producers ; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CUSTOM (0x0) +; CHECK-NEXT: Size: 33 +; CHECK-NEXT: Offset: 1257 +; CHECK-NEXT: Name: target_features +; CHECK-NEXT: } ; CHECK-NEXT:] ; CHECK-NEXT:Relocations [ ; CHECK-NEXT: Section (7) DATA { diff --git a/llvm/test/MC/WebAssembly/debug-info64.ll b/llvm/test/MC/WebAssembly/debug-info64.ll index d0081164d73ee..b0a0b9de1d458 100644 --- a/llvm/test/MC/WebAssembly/debug-info64.ll +++ b/llvm/test/MC/WebAssembly/debug-info64.ll @@ -147,6 +147,12 @@ ; CHECK-NEXT: Offset: 1317 ; CHECK-NEXT: Name: target_features ; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CUSTOM (0x0) +; CHECK-NEXT: Size: 33 +; CHECK-NEXT: Offset: 1257 +; CHECK-NEXT: Name: target_features +; CHECK-NEXT: } ; CHECK-NEXT: ] ; CHECK-NEXT: Relocations [ ; CHECK-NEXT: Section (7) DATA { diff --git a/llvm/test/MC/WebAssembly/explicit-sections.ll b/llvm/test/MC/WebAssembly/explicit-sections.ll index a65172b22d467..8ca3b434b7997 100644 --- a/llvm/test/MC/WebAssembly/explicit-sections.ll +++ b/llvm/test/MC/WebAssembly/explicit-sections.ll @@ -70,4 +70,9 @@ target triple = "wasm32-unknown-unknown" ; CHECK-NEXT: Name: .sec2 ; CHECK-NEXT: Alignment: 3 ; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: target_features +; CHECK-NEXT: Features: +; CHECK-NEXT: - Prefix: DISALLOWED +; CHECK-NEXT: Name: component-model-thread-context ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/export-name-invalid.s b/llvm/test/MC/WebAssembly/export-name-invalid.s index ad322ce949f5e..1272bf66fa143 100644 --- a/llvm/test/MC/WebAssembly/export-name-invalid.s +++ b/llvm/test/MC/WebAssembly/export-name-invalid.s @@ -6,7 +6,7 @@ # CHECK: [[#@LINE+1]]:17: error: Expected ,, instead got: .export_name foo -# CHECK: [[#@LINE+1]]:18: error: Expected identifier, got: +# CHECK: [[#@LINE+1]]:18: error: Expected string or identifier, got: .export_name foo, # CHECK: [[#@LINE+1]]:22: error: Expected EOL, instead got: , diff --git a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll index f1ec71da1ebb6..a8300e865997d 100644 --- a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll +++ b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll @@ -184,4 +184,9 @@ declare void @func3() ; CHECK-NEXT: Symbol: 10 ; CHECK-NEXT: - Priority: 65535 ; CHECK-NEXT: Symbol: 7 +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: target_features +; CHECK-NEXT: Features: +; CHECK-NEXT: - Prefix: DISALLOWED +; CHECK-NEXT: Name: component-model-thread-context ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/import-module-invalid.s b/llvm/test/MC/WebAssembly/import-module-invalid.s index a9f93e83dba39..daf18f2e6a505 100644 --- a/llvm/test/MC/WebAssembly/import-module-invalid.s +++ b/llvm/test/MC/WebAssembly/import-module-invalid.s @@ -6,7 +6,7 @@ # CHECK: [[#@LINE+1]]:19: error: Expected ,, instead got: .import_module foo -# CHECK: [[#@LINE+1]]:20: error: Expected identifier, got: +# CHECK: [[#@LINE+1]]:20: error: Expected string or identifier, got: .import_module foo, # CHECK: [[#@LINE+1]]:24: error: Expected EOL, instead got: , diff --git a/llvm/test/MC/WebAssembly/import-name-invalid.s b/llvm/test/MC/WebAssembly/import-name-invalid.s index da8ed0d4617b0..df709f6380a06 100644 --- a/llvm/test/MC/WebAssembly/import-name-invalid.s +++ b/llvm/test/MC/WebAssembly/import-name-invalid.s @@ -6,7 +6,7 @@ # CHECK: [[#@LINE+1]]:17: error: Expected ,, instead got: .import_name foo -# CHECK: [[#@LINE+1]]:18: error: Expected identifier, got: +# CHECK: [[#@LINE+1]]:18: error: Expected string or identifier, got: .import_name foo, # CHECK: [[#@LINE+1]]:22: error: Expected EOL, instead got: , diff --git a/llvm/test/MC/WebAssembly/unnamed-data.ll b/llvm/test/MC/WebAssembly/unnamed-data.ll index 0887622277bb3..c476e95f02d3a 100644 --- a/llvm/test/MC/WebAssembly/unnamed-data.ll +++ b/llvm/test/MC/WebAssembly/unnamed-data.ll @@ -87,4 +87,9 @@ target triple = "wasm32-unknown-unknown" ; CHECK-NEXT: Name: .data.b ; CHECK-NEXT: Alignment: 3 ; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: target_features +; CHECK-NEXT: Features: +; CHECK-NEXT: - Prefix: DISALLOWED +; CHECK-NEXT: Name: component-model-thread-context ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/visibility.ll b/llvm/test/MC/WebAssembly/visibility.ll index 69b273ecbf25e..9e5d97cd128a5 100644 --- a/llvm/test/MC/WebAssembly/visibility.ll +++ b/llvm/test/MC/WebAssembly/visibility.ll @@ -25,4 +25,9 @@ entry: ; CHECK-NEXT: Name: hiddenVis ; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] ; CHECK-NEXT: Function: 1 +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: target_features +; CHECK-NEXT: Features: +; CHECK-NEXT: - Prefix: DISALLOWED +; CHECK-NEXT: Name: component-model-thread-context ; CHECK-NEXT: ... From e9fa9fc30d84a504241499f60c088be1512b3c0c Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 23 Feb 2026 09:42:51 +0000 Subject: [PATCH 054/134] Remove unused code --- lld/wasm/Config.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h index 2c4954e68bab4..be04827dd1930 100644 --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -135,8 +135,6 @@ struct Config { llvm::SmallVector buildIdVector; }; -enum class ThreadContextAbi { Undetermined, Globals, ComponentModelBuiltins }; - // The Ctx object hold all other (non-configuration) global state. struct Ctx { Config arg; From 10ed134e52430839cb7ac2d3e14db448339678b4 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 23 Feb 2026 09:43:30 +0000 Subject: [PATCH 055/134] Change asserts for symbol creation --- lld/wasm/SymbolTable.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp index 9bd93f317c3c5..e4ca7c56a7602 100644 --- a/lld/wasm/SymbolTable.cpp +++ b/lld/wasm/SymbolTable.cpp @@ -222,7 +222,7 @@ DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name, uint32_t flags, InputFunction *function) { LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << name << "\n"); - assert(!find(name)); + assert(!find(name) || find(name)->isUndefined()); ctx.syntheticFunctions.emplace_back(function); return replaceSymbol(insertName(name).first, name, flags, nullptr, function); @@ -250,7 +250,7 @@ DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name, DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef name, uint32_t flags) { LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << name << "\n"); - assert(!find(name)); + assert(!find(name) || find(name)->isUndefined()); return replaceSymbol(insertName(name).first, name, flags | WASM_SYMBOL_ABSOLUTE); } @@ -259,7 +259,7 @@ DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef name, uint32_t flags, InputGlobal *global) { LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << name << " -> " << global << "\n"); - assert(!find(name)); + assert(!find(name) || find(name)->isUndefined()); ctx.syntheticGlobals.emplace_back(global); return replaceSymbol(insertName(name).first, name, flags, nullptr, global); From 2ee984530db4198312dae546fb626e67af1486b7 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 23 Feb 2026 09:44:54 +0000 Subject: [PATCH 056/134] Fix frame debug info --- .../WebAssembly/WebAssemblyFrameLowering.cpp | 23 +++++++++++++------ .../WebAssembly/WebAssemblyLateEHPrepare.cpp | 10 ++++---- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index eb176161d1fdf..532155c30b2ad 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -135,13 +135,21 @@ bool WebAssemblyFrameLowering::needsSPForLocalFrame( any_of(MRI.use_operands(getSPReg(MF)), [](MachineOperand &MO) { return !MO.isImplicit(); }); + // With component model thread context, we need SP in the prolog when debug + // info is present so we can allocate a local for DWARF to reference. + bool NeedsSPForDebug = MF.getFunction().getSubprogram() && + MF.getSubtarget() + .hasComponentModelThreadContext(); + + + return MFI.getStackSize() || MFI.adjustsStack() || hasFP(MF) || - HasExplicitSPUse; + HasExplicitSPUse || NeedsSPForDebug; } // In function with EH pads, we need to make a copy of the value of -// __stack_pointer global in SP32/64 register, in order to use it when -// restoring __stack_pointer after an exception is caught. +// the stack pointer in the SP32/64 register, in order to use it when +// restoring the stack pointer after an exception is caught. bool WebAssemblyFrameLowering::needsPrologForEH( const MachineFunction &MF) const { auto EHType = MF.getTarget().getMCAsmInfo()->getExceptionHandlingType(); @@ -151,13 +159,14 @@ bool WebAssemblyFrameLowering::needsPrologForEH( /// Returns true if this function needs a local user-space stack pointer. /// Unlike a machine stack pointer, the wasm user stack pointer is a global -/// variable, so it is loaded into a register in the prolog. +/// variable or stored in the component model thread context, so it is loaded +/// into a register in the prolog. bool WebAssemblyFrameLowering::needsSP(const MachineFunction &MF) const { return needsSPForLocalFrame(MF) || needsPrologForEH(MF); } /// Returns true if the local user-space stack pointer needs to be written back -/// to __stack_pointer global by this function (this is not meaningful if +/// to the stack pointer global/thread context by this function (this is not meaningful if /// needsSP is false). If false, the stack red zone can be used and only a local /// SP is needed. bool WebAssemblyFrameLowering::needsSPWriteback( @@ -294,8 +303,8 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, if (ST.hasComponentModelThreadContext()) { 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); + BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CALL), SPReg) + .addExternalSymbol(SPSymbol); } else { const char *ES = "__stack_pointer"; auto *SPSymbol = MF.createExternalSymbolName(ES); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp index 24d5c19399bdb..9396cd23662d4 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp @@ -377,8 +377,8 @@ bool WebAssemblyLateEHPrepare::removeUnnecessaryUnreachables( } // After the stack is unwound due to a thrown exception, the __stack_pointer -// global can point to an invalid address. This inserts instructions that -// restore __stack_pointer global. +// global/context[0] can point to an invalid address. This inserts instructions that +// restore the stack pointer state.. bool WebAssemblyLateEHPrepare::restoreStackPointer(MachineFunction &MF) { const auto *FrameLowering = static_cast( MF.getSubtarget().getFrameLowering()); @@ -391,11 +391,11 @@ bool WebAssemblyLateEHPrepare::restoreStackPointer(MachineFunction &MF) { continue; Changed = true; - // Insert __stack_pointer restoring instructions at the beginning of each EH + // Insert stack pointer restoring instructions at the beginning of each EH // pad, after the catch instruction. Here it is safe to assume that SP32 - // holds the latest value of __stack_pointer, because the only exception for + // holds the latest value of the stack pointer, because the only exception for // this case is when a function uses the red zone, but that only happens - // with leaf functions, and we don't restore __stack_pointer in leaf + // with leaf functions, and we don't restore the stack pointer in leaf // functions anyway. auto InsertPos = MBB.begin(); // Skip EH_LABELs in the beginning of an EH pad if present. From 557bfac15a7b32ae6e6fa73ad429ef2be3f403c7 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 23 Feb 2026 10:10:53 +0000 Subject: [PATCH 057/134] Tighten up linker changes --- lld/wasm/Writer.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index fca033f7b5658..c4074269f510a 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1033,7 +1033,12 @@ static StringRef getOutputDataSegmentName(const InputChunk &seg) { OutputSegment *Writer::createOutputSegment(StringRef name) { LLVM_DEBUG(dbgs() << "new segment: " << name << "\n"); OutputSegment *s = make(name); - if (ctx.isMultithreaded()) + // In the shared memory case, all data segments must be passive since they will be initialized once + // by the main thread and then shared with other threads. In the non-shared memory case, we use + // passive segments only for TLS segments, so that they can be reused, and for .bss segments, which + // don't need to be included in the binary at all. + bool passiveForCMTC = ctx.componentModelThreadContext && (s->isTLS() || s->name.startswith(".bss")); + if (ctx.arg.sharedMemory || passiveForCMTC) s->initFlags = WASM_DATA_SEGMENT_IS_PASSIVE; if (!ctx.arg.relocatable && name.starts_with(".bss")) s->isBss = true; @@ -1158,10 +1163,10 @@ void Writer::createSyntheticInitFunctions() { createApplyDataRelocationsFunction(); // Passive segments are used to avoid memory being reinitialized on each - // thread's instantiation. These passive segments are initialized and - // dropped in __wasm_init_memory, which is registered as the start function - // We also initialize bss segments (using memory.fill) as part of this - // function. + // thread's instantiation for wasi-threads, and for TLS when using cooperative threads. + // These passive segments are initialized and dropped in __wasm_init_memory, which is + // registered as the start function. + // We also initialize bss segments (using memory.fill) as part of this function. if (hasPassiveInitializedSegments()) { ctx.sym.initMemory = symtab->addSyntheticFunction( "__wasm_init_memory", WASM_SYMBOL_VISIBILITY_HIDDEN, @@ -1354,9 +1359,9 @@ void Writer::createInitMemoryFunction() { } // When we initialize the TLS segment we also set the `__tls_base` - // global. This allows the runtime to use this static copy of the - // TLS data for the first/main thread. - if (ctx.arg.sharedMemory && s->isTLS()) { + // global/thread.context[1]. This allows the runtime to use this + // static copy of the TLS data for the first/main thread. + if (ctx.isMultithreaded() && s->isTLS()) { if (ctx.isPic) { // Cache the result of the addionion in local 0 writeU8(os, WASM_OPCODE_LOCAL_TEE, "local.tee"); From 61c25c826423ccab735540be70c65167b8eca27b Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 23 Feb 2026 10:16:41 +0000 Subject: [PATCH 058/134] Typo --- lld/wasm/Writer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index c4074269f510a..7d7b4cbec039e 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1037,7 +1037,7 @@ OutputSegment *Writer::createOutputSegment(StringRef name) { // by the main thread and then shared with other threads. In the non-shared memory case, we use // passive segments only for TLS segments, so that they can be reused, and for .bss segments, which // don't need to be included in the binary at all. - bool passiveForCMTC = ctx.componentModelThreadContext && (s->isTLS() || s->name.startswith(".bss")); + bool passiveForCMTC = ctx.componentModelThreadContext && (s->isTLS() || s->name.starts_with(".bss")); if (ctx.arg.sharedMemory || passiveForCMTC) s->initFlags = WASM_DATA_SEGMENT_IS_PASSIVE; if (!ctx.arg.relocatable && name.starts_with(".bss")) From 0fe07f018d6bea8f15fa3b2bf9962f415caaa18f Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 23 Feb 2026 13:53:09 +0000 Subject: [PATCH 059/134] Improve TLS test --- lld/test/wasm/tls-component-model.s | 64 +++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/lld/test/wasm/tls-component-model.s b/lld/test/wasm/tls-component-model.s index 3f10d497b237f..71e6442435426 100644 --- a/lld/test/wasm/tls-component-model.s +++ b/lld/test/wasm/tls-component-model.s @@ -1,19 +1,37 @@ # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s # RUN: wasm-ld -no-gc-sections -o %t.wasm %t.o # RUN: obj2yaml %t.wasm | FileCheck %s -# RUN: llvm-objdump -d --no-show-raw-insn %t.wasm | FileCheck %s --check-prefix=DIS +# RUN: llvm-objdump -d --no-print-imm-hex --no-show-raw-insn %t.wasm | FileCheck %s --check-prefix=DIS + +.functype __wasm_component_model_builtin_context_get_1 () -> (i32) +.import_module __wasm_component_model_builtin_context_get_1, "$root" +.import_name __wasm_component_model_builtin_context_get_1, "[context-get-1]" .globl _start _start: .functype _start () -> (i32) - global.get tls_sym@GOT@TLS + call __wasm_component_model_builtin_context_get_1 + i32.const tls1@TLSREL + i32.add + i32.load 0 + call __wasm_component_model_builtin_context_get_1 + i32.const tls2@TLSREL + i32.add + i32.load 0 + i32.add end_function -.section .tdata.tls_sym,"",@ -.globl tls_sym -tls_sym: +.section .tdata.tls1,"",@ +.globl tls1 +tls1: .int32 1 - .size tls_sym, 4 + .size tls1, 4 + +.section .tdata.tls2,"",@ +.globl tls2 +tls2: + .int32 2 + .size tls2, 4 .section .custom_section.target_features,"",@ .int8 2 @@ -25,5 +43,35 @@ tls_sym: .ascii "bulk-memory" -# CHECK: Name: __init_tls_base -# DIS: __wasm_init_tls \ No newline at end of file +# CHECK: GlobalNames: +# CHECK-NEXT: - Index: 0 +# CHECK-NEXT: Name: __init_stack_pointer +# CHECK-NEXT: - Index: 1 +# CHECK-NEXT: Name: __init_tls_base +# CHECK-NEXT: - Index: 2 +# CHECK-NEXT: Name: __tls_size +# CHECK-NEXT: - Index: 3 +# CHECK-NEXT: Name: __tls_align + +# DIS-LABEL: <__wasm_init_memory>: +# DIS-EMPTY: +# DIS-NEXT: i32.const 65536 +# DIS-NEXT: i32.const 65536 +# DIS-NEXT: call 1 +# DIS-NEXT: i32.const 0 +# DIS-NEXT: i32.const 8 +# DIS-NEXT: memory.init 0, 0 +# DIS-NEXT: end + +# DIS-LABEL: <_start>: +# DIS-EMPTY: +# DIS-NEXT: call 0 +# DIS-NEXT: i32.const 0 +# DIS-NEXT: i32.add +# DIS-NEXT: i32.load 0 +# DIS-NEXT: call 0 +# DIS-NEXT: i32.const 4 +# DIS-NEXT: i32.add +# DIS-NEXT: i32.load 0 +# DIS-NEXT: i32.add +# DIS-NEXT: end \ No newline at end of file From 7a58fcea7d3d8f267a3daad1382d2683feeda5f3 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 23 Feb 2026 16:42:25 +0000 Subject: [PATCH 060/134] Fix TLS in shared objects --- llvm/lib/Object/WasmObjectFile.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index bd69941e5664e..098902fdfe5a0 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -1486,6 +1486,15 @@ Error WasmObjectFile::parseExportSection(ReadContext &Ctx) { wasm::WasmSymbolInfo Info; Info.Name = Ex.Name; Info.Flags = 0; + // For shared objects, look up flags (e.g. TLS) from dylink export info + if (HasDylinkSection) { + for (const auto &ExportInfo : DylinkInfo.ExportInfo) { + if (ExportInfo.Name == Ex.Name) { + Info.Flags = ExportInfo.Flags; + break; + } + } + } switch (Ex.Kind) { case wasm::WASM_EXTERNAL_FUNCTION: { if (!isValidFunctionIndex(Ex.Index)) From 8047c7634ef1cfddd78e5bc15c0ad7972cf08ef8 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 23 Feb 2026 16:44:09 +0000 Subject: [PATCH 061/134] Update comment --- .../Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h index 5dc0e3aa91622..403ce3bfcb504 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -106,7 +106,8 @@ enum TOF { MO_MEMORY_BASE_REL, // On a symbol operand this indicates that the immediate is the symbol - // address relative the __tls_base wasm global. + // address relative to the TLS base. This is stored in thread.context[1] + // when using the component model thread context, and the __tls_base global otherwise. // Only applicable to data symbols. MO_TLS_BASE_REL, From 24cb457d6615fbc39e03099690da0fc096b1246b Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 23 Feb 2026 17:53:43 +0000 Subject: [PATCH 062/134] Remove symbol file changes for now --- llvm/lib/Object/WasmObjectFile.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 098902fdfe5a0..bd69941e5664e 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -1486,15 +1486,6 @@ Error WasmObjectFile::parseExportSection(ReadContext &Ctx) { wasm::WasmSymbolInfo Info; Info.Name = Ex.Name; Info.Flags = 0; - // For shared objects, look up flags (e.g. TLS) from dylink export info - if (HasDylinkSection) { - for (const auto &ExportInfo : DylinkInfo.ExportInfo) { - if (ExportInfo.Name == Ex.Name) { - Info.Flags = ExportInfo.Flags; - break; - } - } - } switch (Ex.Kind) { case wasm::WASM_EXTERNAL_FUNCTION: { if (!isValidFunctionIndex(Ex.Index)) From d11664a233eb8b9947675b4f23772cf7d128c5a4 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 3 Mar 2026 16:05:42 +0000 Subject: [PATCH 063/134] Clang format --- clang/lib/Basic/Targets/WebAssembly.cpp | 10 +- clang/lib/Driver/ToolChains/WebAssembly.cpp | 8 +- lld/wasm/Config.h | 7 +- lld/wasm/Driver.cpp | 91 ++++++++++--------- lld/wasm/Options.td | 7 +- lld/wasm/Writer.cpp | 34 ++++--- .../MCTargetDesc/WebAssemblyMCTargetDesc.h | 6 +- .../WebAssembly/WebAssemblyFrameLowering.cpp | 23 +++-- .../WebAssembly/WebAssemblyFrameLowering.h | 7 +- .../WebAssembly/WebAssemblyLateEHPrepare.cpp | 12 +-- .../WebAssembly/WebAssemblySubtarget.cpp | 8 +- .../Target/WebAssembly/WebAssemblySubtarget.h | 4 +- .../WebAssembly/WebAssemblyTargetMachine.cpp | 8 +- .../Target/WebAssembly/WebAssemblyUtilities.h | 4 +- 14 files changed, 126 insertions(+), 103 deletions(-) diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp index 785bec699f925..a8bc7c13ffc78 100644 --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -418,11 +418,11 @@ WebAssemblyTargetInfo::getTargetBuiltins() const { void WebAssemblyTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts, const TargetInfo *Aux) { TargetInfo::adjust(Diags, Opts, Aux); - // If not using component model threading intrinsics, turn off POSIXThreads - // and ThreadModel so that we don't predefine _REENTRANT or __STDCPP_THREADS__ - // if we will eventually end up stripping atomics because they are unsupported. - if (!HasComponentModelThreadContext && - (!HasAtomics || !HasBulkMemory)) { + // If not using component model threading intrinsics, turn off POSIXThreads + // and ThreadModel so that we don't predefine _REENTRANT or __STDCPP_THREADS__ + // if we will eventually end up stripping atomics because they are + // unsupported. + if (!HasComponentModelThreadContext && (!HasAtomics || !HasBulkMemory)) { Opts.POSIXThreads = false; Opts.setThreadModel(LangOptions::ThreadModelKind::Single); Opts.ThreadsafeStatics = false; diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 84b9b00bf4c23..151d289d17e13 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -79,17 +79,19 @@ static bool WantsPthread(const llvm::Triple &Triple, const ArgList &Args) { return WantsPthread; } -static bool WantsComponentModelThreadContext(const llvm::Triple &Triple, const ArgList &Args) { +static bool WantsComponentModelThreadContext(const llvm::Triple &Triple, + const ArgList &Args) { // If the target is WASIP3, then enable the // component-model-thread-context feature by default, unless explicitly // disabled. return Triple.getOS() == llvm::Triple::WASIp3 && Args.hasFlag(options::OPT_mcomponent_model_thread_context, - options::OPT_mno_component_model_thread_context, true); + options::OPT_mno_component_model_thread_context, true); } static bool WantsSharedMemory(const llvm::Triple &Triple, const ArgList &Args) { - return WantsPthread(Triple, Args) && !WantsComponentModelThreadContext(Triple, Args); + return WantsPthread(Triple, Args) && + !WantsComponentModelThreadContext(Triple, Args); } void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h index be04827dd1930..ac8734d9c0e7f 100644 --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -280,12 +280,15 @@ struct Ctx { 0> whyExtractRecords; - // Whether to use component model thread context intrinsics for the stack pointer and TLS base. + // Whether to use component model thread context intrinsics for the stack + // pointer and TLS base. bool componentModelThreadContext = false; Ctx(); void reset(); - bool isMultithreaded() const { return componentModelThreadContext || arg.sharedMemory; } + bool isMultithreaded() const { + return componentModelThreadContext || arg.sharedMemory; + } }; extern Ctx ctx; diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 0c50e12f66e32..6687733bd8b77 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -966,8 +966,9 @@ static void createPostLTOSymbols() { bool is64 = ctx.arg.is64.value_or(false); - auto stack_pointer_name = - ctx.componentModelThreadContext ? "__init_stack_pointer" : "__stack_pointer"; + auto stack_pointer_name = ctx.componentModelThreadContext + ? "__init_stack_pointer" + : "__stack_pointer"; if (ctx.isPic) { ctx.sym.stackPointer = createUndefinedGlobal(stack_pointer_name, ctx.arg.is64.value_or(false) @@ -985,15 +986,18 @@ static void createPostLTOSymbols() { ctx.sym.tableBase->markLive(); } else { // For non-PIC code - ctx.sym.stackPointer = createGlobalVariable(stack_pointer_name, !ctx.componentModelThreadContext); + ctx.sym.stackPointer = createGlobalVariable( + stack_pointer_name, !ctx.componentModelThreadContext); ctx.sym.stackPointer->markLive(); } if (ctx.isMultithreaded()) { // TLS symbols are all hidden/dso-local - auto tls_base_name = ctx.componentModelThreadContext ? "__init_tls_base" : "__tls_base"; - ctx.sym.tlsBase = createGlobalVariable(tls_base_name, !ctx.componentModelThreadContext, - WASM_SYMBOL_VISIBILITY_HIDDEN); + auto tls_base_name = + ctx.componentModelThreadContext ? "__init_tls_base" : "__tls_base"; + ctx.sym.tlsBase = + createGlobalVariable(tls_base_name, !ctx.componentModelThreadContext, + WASM_SYMBOL_VISIBILITY_HIDDEN); ctx.sym.tlsSize = createGlobalVariable("__tls_size", false, WASM_SYMBOL_VISIBILITY_HIDDEN); ctx.sym.tlsAlign = createGlobalVariable("__tls_align", false, @@ -1316,68 +1320,73 @@ static void determineThreadContextABI(ArrayRef files) { // A complication is that a user may attempt to link together object files // compiled with different versions of LLVM, where one does not specifiy // -component-model-thread-context when using the global thread context ABI. - // They may also attempt to link object files with the global ABI compiled with - // older LLVM versions, but link them with a newer wasm-ld. To ensure the correct behavior - // in both of these cases, we treat the import of a __stack_pointer global from the env module - // as an indication that the global thread context ABI is being used. + // They may also attempt to link object files with the global ABI compiled + // with older LLVM versions, but link them with a newer wasm-ld. To ensure the + // correct behavior in both of these cases, we treat the import of a + // __stack_pointer global from the env module as an indication that the global + // thread context ABI is being used. - enum class ThreadContextABI { - Undetermined, - ComponentModelBuiltins, - Globals - }; + enum class ThreadContextABI { Undetermined, ComponentModelBuiltins, Globals }; ThreadContextABI threadContextABI = ThreadContextABI::Undetermined; for (ObjFile *obj : files) { auto targetFeatures = obj->getWasmObj()->getTargetFeatures(); - auto threadContextFeature = llvm::find_if(targetFeatures, - [](const auto &f) { - return f.Name == "component-model-thread-context"; - }); + auto threadContextFeature = + llvm::find_if(targetFeatures, [](const auto &f) { + return f.Name == "component-model-thread-context"; + }); - bool usesComponentModelThreadContext = threadContextFeature != targetFeatures.end() && - threadContextFeature->Prefix == WASM_FEATURE_PREFIX_USED; + bool usesComponentModelThreadContext = + threadContextFeature != targetFeatures.end() && + threadContextFeature->Prefix == WASM_FEATURE_PREFIX_USED; if (threadContextFeature == targetFeatures.end()) { - // If the feature is not explicitly used or disallowed, check for the presence of a __stack_pointer - // import in this specific file to determine if the global thread context ABI is being used. - bool hasStackPointerImport = llvm::any_of(obj->getSymbols(), [](const auto &sym) { - return sym && sym->getName() == "__stack_pointer" && - sym->kind() == Symbol::UndefinedGlobalKind && - sym->importModule && sym->importModule == "env"; - }); + // If the feature is not explicitly used or disallowed, check for the + // presence of a __stack_pointer import in this specific file to determine + // if the global thread context ABI is being used. + bool hasStackPointerImport = + llvm::any_of(obj->getSymbols(), [](const auto &sym) { + return sym && sym->getName() == "__stack_pointer" && + sym->kind() == Symbol::UndefinedGlobalKind && + sym->importModule && sym->importModule == "env"; + }); if (!hasStackPointerImport) { - // No __stack_pointer import, so this is probably an object file compiled from assembly or - // some other source that doesn't care about the thread context ABI. As such, we let it pass. + // No __stack_pointer import, so this is probably an object file + // compiled from assembly or some other source that doesn't care about + // the thread context ABI. As such, we let it pass. continue; } // Treat this as using the globals ABI usesComponentModelThreadContext = false; - } + } if (usesComponentModelThreadContext) { if (threadContextABI == ThreadContextABI::Undetermined) { threadContextABI = ThreadContextABI::ComponentModelBuiltins; } else if (threadContextABI != ThreadContextABI::ComponentModelBuiltins) { - error("thread context ABI mismatch: " + obj->getName() + - " uses component-model-thread-context but other files disallow it"); + error( + "thread context ABI mismatch: " + obj->getName() + + " uses component-model-thread-context but other files disallow it"); } } else { if (threadContextABI == ThreadContextABI::Undetermined) { threadContextABI = ThreadContextABI::Globals; } else if (threadContextABI != ThreadContextABI::Globals) { - error("thread context ABI mismatch: " + obj->getName() + - " disallows component-model-thread-context but other files use it"); + error( + "thread context ABI mismatch: " + obj->getName() + + " disallows component-model-thread-context but other files use it"); } } } - + // If the ABI is undetermined at this point, default to the globals ABI - ctx.componentModelThreadContext = (threadContextABI == ThreadContextABI::ComponentModelBuiltins); + ctx.componentModelThreadContext = + (threadContextABI == ThreadContextABI::ComponentModelBuiltins); if (ctx.arg.sharedMemory && ctx.componentModelThreadContext) { - error("--shared-memory is currently incompatible with component model thread context intrinsics"); + error("--shared-memory is currently incompatible with component model " + "thread context intrinsics"); } } @@ -1555,9 +1564,9 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { if (errorCount()) return; - // Now that LTO is complete and all object files are available, determine the - // thread context ABI and create symbols (__stack_pointer, __tls_base, etc.) based - // on the determined ABI. + // Now that LTO is complete and all object files are available, determine the + // thread context ABI and create symbols (__stack_pointer, __tls_base, etc.) + // based on the determined ABI. determineThreadContextABI(ctx.objectFiles); createPostLTOSymbols(); diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td index a9def1bc47c9a..4b6d800854a08 100644 --- a/lld/wasm/Options.td +++ b/lld/wasm/Options.td @@ -190,8 +190,11 @@ def allow_undefined_file: J<"allow-undefined-file=">, def allow_undefined_file_s: Separate<["-"], "allow-undefined-file">, Alias; -def component_model_thread_context: FF<"component-model-thread-context">, - HelpText<"Use component model thread context intrinsics instead of global variables for the stack pointer and thread local storage">; +def component_model_thread_context + : FF<"component-model-thread-context">, + HelpText< + "Use component model thread context intrinsics instead of global " + "variables for the stack pointer and thread local storage">; defm export: Eq<"export", "Force a symbol to be exported">; diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 7d7b4cbec039e..f7334672dad2b 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -651,10 +651,12 @@ void Writer::populateTargetFeatures() { if (tlsUsed) { if (!allowed.contains("bulk-memory")) { - error("bulk-memory feature must be used in order to use thread-local storage"); + error("bulk-memory feature must be used in order to use thread-local " + "storage"); } if (!ctx.componentModelThreadContext && !allowed.contains("atomics")) { - error("atomics feature must be used in order to use thread-local storage"); + error( + "atomics feature must be used in order to use thread-local storage"); } } @@ -1033,11 +1035,13 @@ static StringRef getOutputDataSegmentName(const InputChunk &seg) { OutputSegment *Writer::createOutputSegment(StringRef name) { LLVM_DEBUG(dbgs() << "new segment: " << name << "\n"); OutputSegment *s = make(name); - // In the shared memory case, all data segments must be passive since they will be initialized once - // by the main thread and then shared with other threads. In the non-shared memory case, we use - // passive segments only for TLS segments, so that they can be reused, and for .bss segments, which - // don't need to be included in the binary at all. - bool passiveForCMTC = ctx.componentModelThreadContext && (s->isTLS() || s->name.starts_with(".bss")); + // In the shared memory case, all data segments must be passive since they + // will be initialized once by the main thread and then shared with other + // threads. In the non-shared memory case, we use passive segments only for + // TLS segments, so that they can be reused, and for .bss segments, which + // don't need to be included in the binary at all. + bool passiveForCMTC = ctx.componentModelThreadContext && + (s->isTLS() || s->name.starts_with(".bss")); if (ctx.arg.sharedMemory || passiveForCMTC) s->initFlags = WASM_DATA_SEGMENT_IS_PASSIVE; if (!ctx.arg.relocatable && name.starts_with(".bss")) @@ -1163,10 +1167,10 @@ void Writer::createSyntheticInitFunctions() { createApplyDataRelocationsFunction(); // Passive segments are used to avoid memory being reinitialized on each - // thread's instantiation for wasi-threads, and for TLS when using cooperative threads. - // These passive segments are initialized and dropped in __wasm_init_memory, which is - // registered as the start function. - // We also initialize bss segments (using memory.fill) as part of this function. + // thread's instantiation for wasi-threads, and for TLS when using cooperative + // threads. These passive segments are initialized and dropped in + // __wasm_init_memory, which is registered as the start function. We also + // initialize bss segments (using memory.fill) as part of this function. if (hasPassiveInitializedSegments()) { ctx.sym.initMemory = symtab->addSyntheticFunction( "__wasm_init_memory", WASM_SYMBOL_VISIBILITY_HIDDEN, @@ -1359,7 +1363,7 @@ void Writer::createInitMemoryFunction() { } // When we initialize the TLS segment we also set the `__tls_base` - // global/thread.context[1]. This allows the runtime to use this + // global/thread.context[1]. This allows the runtime to use this // static copy of the TLS data for the first/main thread. if (ctx.isMultithreaded() && s->isTLS()) { if (ctx.isPic) { @@ -1639,8 +1643,10 @@ void Writer::createInitTLSFunction() { writeUleb128(os, 0, "num locals"); if (tlsSeg) { - // When using component model thread context intrinsics, we don't set the TLS base - //inside __init_tls; this should be done as part of the thread startup stub. + // When using component model thread context intrinsics, we don't set the + // TLS base + // inside __init_tls; this should be done as part of the thread startup + // stub. if (!ctx.componentModelThreadContext) { writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); writeUleb128(os, 0, "local index"); diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h index 403ce3bfcb504..d642ef2ccf2a4 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -106,9 +106,9 @@ enum TOF { MO_MEMORY_BASE_REL, // On a symbol operand this indicates that the immediate is the symbol - // address relative to the TLS base. This is stored in thread.context[1] - // when using the component model thread context, and the __tls_base global otherwise. - // Only applicable to data symbols. + // address relative to the TLS base. This is stored in thread.context[1] + // when using the component model thread context, and the __tls_base global + // otherwise. Only applicable to data symbols. MO_TLS_BASE_REL, // On a symbol operand this indicates that the immediate is the symbol diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index 532155c30b2ad..77489f6f8e517 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -137,11 +137,9 @@ bool WebAssemblyFrameLowering::needsSPForLocalFrame( // With component model thread context, we need SP in the prolog when debug // info is present so we can allocate a local for DWARF to reference. - bool NeedsSPForDebug = MF.getFunction().getSubprogram() && - MF.getSubtarget() - .hasComponentModelThreadContext(); - - + bool NeedsSPForDebug = + MF.getFunction().getSubprogram() && + MF.getSubtarget().hasComponentModelThreadContext(); return MFI.getStackSize() || MFI.adjustsStack() || hasFP(MF) || HasExplicitSPUse || NeedsSPForDebug; @@ -159,16 +157,16 @@ bool WebAssemblyFrameLowering::needsPrologForEH( /// Returns true if this function needs a local user-space stack pointer. /// Unlike a machine stack pointer, the wasm user stack pointer is a global -/// variable or stored in the component model thread context, so it is loaded +/// variable or stored in the component model thread context, so it is loaded /// into a register in the prolog. bool WebAssemblyFrameLowering::needsSP(const MachineFunction &MF) const { return needsSPForLocalFrame(MF) || needsPrologForEH(MF); } /// Returns true if the local user-space stack pointer needs to be written back -/// to the stack pointer global/thread context by this function (this is not meaningful if -/// needsSP is false). If false, the stack red zone can be used and only a local -/// SP is needed. +/// to the stack pointer global/thread context by this function (this is not +/// meaningful if needsSP is false). If false, the stack red zone can be used +/// and only a local SP is needed. bool WebAssemblyFrameLowering::needsSPWriteback( const MachineFunction &MF) const { auto &MFI = MF.getFrameInfo(); @@ -241,7 +239,8 @@ void WebAssemblyFrameLowering::writeBackSP( MachineBasicBlock::iterator &InsertStore, const DebugLoc &DL) const { const auto *TII = MF.getSubtarget().getInstrInfo(); - if (MF.getSubtarget().hasComponentModelThreadContext()) { + if (MF.getSubtarget() + .hasComponentModelThreadContext()) { const char *ES = "__wasm_component_model_builtin_context_set_0"; auto *SPSymbol = MF.createExternalSymbolName(ES); BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::CALL)) @@ -303,8 +302,8 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, if (ST.hasComponentModelThreadContext()) { 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); + BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CALL), SPReg) + .addExternalSymbol(SPSymbol); } else { const char *ES = "__stack_pointer"; auto *SPSymbol = MF.createExternalSymbolName(ES); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h index e567345e93773..98133d48a9eaa 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h @@ -48,10 +48,9 @@ class WebAssemblyFrameLowering final : public TargetFrameLowering { bool needsPrologForEH(const MachineFunction &MF) const; /// 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; + void writeBackSP(unsigned SrcReg, MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator &InsertStore, + const DebugLoc &DL) const; // Returns the index of the WebAssembly local to which the stack object // FrameIndex in MF should be allocated, or std::nullopt. diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp index 9396cd23662d4..c846215ce0e7c 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp @@ -377,8 +377,8 @@ bool WebAssemblyLateEHPrepare::removeUnnecessaryUnreachables( } // After the stack is unwound due to a thrown exception, the __stack_pointer -// global/context[0] can point to an invalid address. This inserts instructions that -// restore the stack pointer state.. +// global/context[0] can point to an invalid address. This inserts instructions +// that restore the stack pointer state.. bool WebAssemblyLateEHPrepare::restoreStackPointer(MachineFunction &MF) { const auto *FrameLowering = static_cast( MF.getSubtarget().getFrameLowering()); @@ -393,8 +393,8 @@ bool WebAssemblyLateEHPrepare::restoreStackPointer(MachineFunction &MF) { // Insert stack pointer restoring instructions at the beginning of each EH // pad, after the catch instruction. Here it is safe to assume that SP32 - // holds the latest value of the stack pointer, because the only exception for - // this case is when a function uses the red zone, but that only happens + // holds the latest value of the stack pointer, because the only exception + // for this case is when a function uses the red zone, but that only happens // with leaf functions, and we don't restore the stack pointer in leaf // functions anyway. auto InsertPos = MBB.begin(); @@ -405,8 +405,8 @@ 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->writeBackSP(FrameLowering->getSPReg(MF), MF, MBB, - InsertPos, MBB.begin()->getDebugLoc()); + FrameLowering->writeBackSP(FrameLowering->getSPReg(MF), MF, MBB, InsertPos, + MBB.begin()->getDebugLoc()); } return Changed; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp index 20bd0c3b1b923..662e01022cc87 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp @@ -38,12 +38,12 @@ WebAssemblySubtarget::initializeSubtargetDependencies(StringRef CPU, if (CPU.empty()) CPU = "generic"; - ParseSubtargetFeatures(CPU, /*TuneCPU*/ CPU, FS); - + ParseSubtargetFeatures(CPU, /*TuneCPU*/ CPU, FS); + // WASIP3 implies using the component model thread context intrinsics by // default, unless explicitly disabled. - if (!FS.contains("component-model-thread-context") && - !HasComponentModelThreadContext && + if (!FS.contains("component-model-thread-context") && + !HasComponentModelThreadContext && TargetTriple.getOS() == Triple::WASIp3) { ToggleFeature(WebAssembly::FeatureComponentModelThreadContext); HasComponentModelThreadContext = true; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h index 05009b388a4db..4b82172e29e39 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h @@ -112,7 +112,9 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo { bool hasBulkMemoryOpt() const { return HasBulkMemoryOpt; } bool hasCallIndirectOverlong() const { return HasCallIndirectOverlong; } bool hasCompactImports() const { return HasCompactImports; } - bool hasComponentModelThreadContext() const { return HasComponentModelThreadContext; } + bool hasComponentModelThreadContext() const { + return HasComponentModelThreadContext; + } bool hasExceptionHandling() const { return HasExceptionHandling; } bool hasExtendedConst() const { return HasExtendedConst; } bool hasFP16() const { return HasFP16; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index 3c620b4bda6f8..f8d3b4a69ea57 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -268,8 +268,8 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { // 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, unless the target - // is using component model threading intrinsics which allow thread local storage - // without atomics, in which case only strip atomics. + // is using component model threading intrinsics which allow thread local + // storage without atomics, in which case only strip atomics. static char ID; WebAssemblyTargetMachine *WasmTM; @@ -289,7 +289,7 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { bool StrippedTLS = false; if (Features[WebAssembly::FeatureComponentModelThreadContext]) { - // Using component model threading intrinsics allows TLS without + // Using component model threading intrinsics allows TLS without // atomics, so don't strip TLS even if atomics are disabled. if (!Features[WebAssembly::FeatureAtomics]) { StrippedAtomics = stripAtomics(M); @@ -432,7 +432,7 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { M.addModuleFlag(Module::ModFlagBehavior::Error, "wasm-feature-shared-mem", wasm::WASM_FEATURE_PREFIX_DISALLOWED); } - + // Mark component-model-thread-context as disallowed when not in use to // prevent linking object files with incompatible threading ABIs. if (!Features[WebAssembly::FeatureComponentModelThreadContext]) { diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h index 5b4e9cff19a55..c7de7f9971cdc 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h @@ -77,8 +77,8 @@ bool canLowerMultivalueReturn(const WebAssemblySubtarget *Subtarget); bool canLowerReturn(size_t ResultSize, const WebAssemblySubtarget *Subtarget); // Get the TLS base value for the current target -// If using component model threading intrinsics: calls __wasm_component_model_builtin_context_get_1 -// Otherwise: global.get __tls_base +// If using component model threading intrinsics: calls +// __wasm_component_model_builtin_context_get_1 Otherwise: global.get __tls_base MachineSDNode *getTLSBase(SelectionDAG &DAG, const SDLoc &DL, const WebAssemblySubtarget *Subtarget); From f04b74ac5341c24f9f4a72d1c69df5056c7f800f Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 3 Mar 2026 16:21:02 +0000 Subject: [PATCH 064/134] Format --- .../WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp index 916a42664279f..c6f3959d02af5 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -25,10 +25,12 @@ using namespace llvm; static bool shouldQuoteName(StringRef Name) { // Wasm export/import names and import module names can contain characters // that are not allowed in identifiers, so we need to quote them. - auto isValidStartChar = [](char C) { return isalpha(C) || C == '_' || C == '.'; }; + auto isValidStartChar = [](char C) { + return isalpha(C) || C == '_' || C == '.'; + }; auto isValidChar = [&](char C) { return isValidStartChar(C) || isdigit(C); }; return !(Name.size() > 0 && isValidStartChar(Name.front())) || - llvm::any_of(Name, [&](char C) { return !isValidChar(C); }); + llvm::any_of(Name, [&](char C) { return !isValidChar(C); }); } WebAssemblyTargetStreamer::WebAssemblyTargetStreamer(MCStreamer &S) From 6bdff2ce19001dd9f137dd86beb14ba5de7dbb44 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 3 Mar 2026 17:32:14 +0000 Subject: [PATCH 065/134] Fix tests --- .../MCTargetDesc/WebAssemblyTargetStreamer.cpp | 2 +- llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp | 2 +- llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp | 6 +++--- llvm/test/MC/WebAssembly/debug-info64.ll | 8 +------- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp index c6f3959d02af5..bb643a956b6c4 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -29,7 +29,7 @@ static bool shouldQuoteName(StringRef Name) { return isalpha(C) || C == '_' || C == '.'; }; auto isValidChar = [&](char C) { return isValidStartChar(C) || isdigit(C); }; - return !(Name.size() > 0 && isValidStartChar(Name.front())) || + return !(Name.size() > 0 && isValidStartChar(Name.front())) || llvm::any_of(Name, [&](char C) { return !isValidChar(C); }); } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp index d083eefe9b29d..3e5656487f87b 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp @@ -308,7 +308,7 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) { switch (IntNo) { case Intrinsic::wasm_tls_base: { MachineSDNode *TLSBase = - llvm::WebAssembly::getTLSBase(*CurDAG, DL, Subtarget); + llvm::WebAssembly::getTLSBase(*CurDAG, DL, Subtarget, Node->getOperand(0)); ReplaceNode(Node, TLSBase); return; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index 1c8aeae8bc1cb..b3db5e8b08625 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -196,7 +196,7 @@ bool WebAssembly::canLowerReturn(size_t ResultSize, } MachineSDNode *WebAssembly::getTLSBase(SelectionDAG &DAG, const SDLoc &DL, - const WebAssemblySubtarget *Subtarget) { + const WebAssemblySubtarget *Subtarget, const SDValue &Chain) { MVT PtrVT = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32; auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 : WebAssembly::GLOBAL_GET_I32; @@ -206,9 +206,9 @@ MachineSDNode *WebAssembly::getTLSBase(SelectionDAG &DAG, const SDLoc &DL, WebAssembly::CALL, DL, PtrVT, MVT::Other, DAG.getTargetExternalSymbol( "__wasm_component_model_builtin_context_get_1", PtrVT), - DAG.getEntryNode()); + Chain); } else { return DAG.getMachineNode(GlobalGetIns, DL, PtrVT, - DAG.getTargetExternalSymbol("__tls_base", PtrVT)); + DAG.getTargetExternalSymbol("__tls_base", PtrVT), Chain); } } \ No newline at end of file diff --git a/llvm/test/MC/WebAssembly/debug-info64.ll b/llvm/test/MC/WebAssembly/debug-info64.ll index b0a0b9de1d458..9ed067f571cbc 100644 --- a/llvm/test/MC/WebAssembly/debug-info64.ll +++ b/llvm/test/MC/WebAssembly/debug-info64.ll @@ -143,16 +143,10 @@ ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) -; CHECK-NEXT: Size: 11 +; CHECK-NEXT: Size: 43 ; CHECK-NEXT: Offset: 1317 ; CHECK-NEXT: Name: target_features ; CHECK-NEXT: } -; CHECK-NEXT: Section { -; CHECK-NEXT: Type: CUSTOM (0x0) -; CHECK-NEXT: Size: 33 -; CHECK-NEXT: Offset: 1257 -; CHECK-NEXT: Name: target_features -; CHECK-NEXT: } ; CHECK-NEXT: ] ; CHECK-NEXT: Relocations [ ; CHECK-NEXT: Section (7) DATA { From a637ae1c4cc63a843889125445649641e2cae132 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 3 Mar 2026 17:34:56 +0000 Subject: [PATCH 066/134] fmt --- llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp | 4 ++-- llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp index 3e5656487f87b..8040191c69c04 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp @@ -307,8 +307,8 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) { MVT PtrVT = TLI.getPointerTy(CurDAG->getDataLayout()); switch (IntNo) { case Intrinsic::wasm_tls_base: { - MachineSDNode *TLSBase = - llvm::WebAssembly::getTLSBase(*CurDAG, DL, Subtarget, Node->getOperand(0)); + MachineSDNode *TLSBase = llvm::WebAssembly::getTLSBase( + *CurDAG, DL, Subtarget, Node->getOperand(0)); ReplaceNode(Node, TLSBase); return; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index b3db5e8b08625..0d58f204f5154 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -196,7 +196,8 @@ bool WebAssembly::canLowerReturn(size_t ResultSize, } MachineSDNode *WebAssembly::getTLSBase(SelectionDAG &DAG, const SDLoc &DL, - const WebAssemblySubtarget *Subtarget, const SDValue &Chain) { + const WebAssemblySubtarget *Subtarget, + const SDValue &Chain) { MVT PtrVT = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32; auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 : WebAssembly::GLOBAL_GET_I32; @@ -209,6 +210,7 @@ MachineSDNode *WebAssembly::getTLSBase(SelectionDAG &DAG, const SDLoc &DL, Chain); } else { return DAG.getMachineNode(GlobalGetIns, DL, PtrVT, - DAG.getTargetExternalSymbol("__tls_base", PtrVT), Chain); + DAG.getTargetExternalSymbol("__tls_base", PtrVT), + Chain); } } \ No newline at end of file From 0bf18a6e8b6b45bb36aff5e2a20d7b8376ef6817 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 3 Mar 2026 17:47:09 +0000 Subject: [PATCH 067/134] Add chain to TLS base --- llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp | 8 ++++---- llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index 0d58f204f5154..f4c5716c9d7a8 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -197,20 +197,20 @@ bool WebAssembly::canLowerReturn(size_t ResultSize, MachineSDNode *WebAssembly::getTLSBase(SelectionDAG &DAG, const SDLoc &DL, const WebAssemblySubtarget *Subtarget, - const SDValue &Chain) { + const SDValue *Chain) { MVT PtrVT = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32; auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 : WebAssembly::GLOBAL_GET_I32; - + ArrayRef Ops = Chain ? ArrayRef(*Chain) : ArrayRef(); if (Subtarget->hasComponentModelThreadContext()) { return DAG.getMachineNode( WebAssembly::CALL, DL, PtrVT, MVT::Other, DAG.getTargetExternalSymbol( "__wasm_component_model_builtin_context_get_1", PtrVT), - Chain); + Ops); } else { return DAG.getMachineNode(GlobalGetIns, DL, PtrVT, DAG.getTargetExternalSymbol("__tls_base", PtrVT), - Chain); + Ops); } } \ No newline at end of file diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h index c7de7f9971cdc..80e9ffa4ab668 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h @@ -80,7 +80,8 @@ bool canLowerReturn(size_t ResultSize, const WebAssemblySubtarget *Subtarget); // If using component model threading intrinsics: calls // __wasm_component_model_builtin_context_get_1 Otherwise: global.get __tls_base MachineSDNode *getTLSBase(SelectionDAG &DAG, const SDLoc &DL, - const WebAssemblySubtarget *Subtarget); + const WebAssemblySubtarget *Subtarget, + const SDValue *Chain = nullptr); } // end namespace WebAssembly From 6c9c276e5083b0b2c0a7e03f59c60590460385a0 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 3 Mar 2026 17:47:48 +0000 Subject: [PATCH 068/134] fmt --- llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index f4c5716c9d7a8..1fc346a4dc032 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -201,7 +201,8 @@ MachineSDNode *WebAssembly::getTLSBase(SelectionDAG &DAG, const SDLoc &DL, MVT PtrVT = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32; auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 : WebAssembly::GLOBAL_GET_I32; - ArrayRef Ops = Chain ? ArrayRef(*Chain) : ArrayRef(); + ArrayRef Ops = + Chain ? ArrayRef(*Chain) : ArrayRef(); if (Subtarget->hasComponentModelThreadContext()) { return DAG.getMachineNode( WebAssembly::CALL, DL, PtrVT, MVT::Other, From f019ea951284040f2fb694a0879a0f9b18153566 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 3 Mar 2026 17:52:14 +0000 Subject: [PATCH 069/134] Change chain impl --- .../WebAssembly/WebAssemblyUtilities.cpp | 20 ++++++++++--------- .../Target/WebAssembly/WebAssemblyUtilities.h | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index 1fc346a4dc032..8f13e48d11f36 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -197,21 +197,23 @@ bool WebAssembly::canLowerReturn(size_t ResultSize, MachineSDNode *WebAssembly::getTLSBase(SelectionDAG &DAG, const SDLoc &DL, const WebAssemblySubtarget *Subtarget, - const SDValue *Chain) { + const SDValue Chain) { MVT PtrVT = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32; auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 : WebAssembly::GLOBAL_GET_I32; ArrayRef Ops = Chain ? ArrayRef(*Chain) : ArrayRef(); if (Subtarget->hasComponentModelThreadContext()) { - return DAG.getMachineNode( - WebAssembly::CALL, DL, PtrVT, MVT::Other, - DAG.getTargetExternalSymbol( - "__wasm_component_model_builtin_context_get_1", PtrVT), - Ops); +if (Chain.getNode()) + return DAG.getMachineNode(WebAssembly::CALL, DL, {PtrVT, MVT::Other}, + {CallTarget, Chain}); + return DAG.getMachineNode(WebAssembly::CALL, DL, PtrVT, CallTarget); + } else { - return DAG.getMachineNode(GlobalGetIns, DL, PtrVT, - DAG.getTargetExternalSymbol("__tls_base", PtrVT), - Ops); + SDValue TLSBaseSym = DAG.getTargetExternalSymbol("__tls_base", PtrVT); + if (Chain.getNode()) + return DAG.getMachineNode(GlobalGetIns, DL, PtrVT, {TLSBaseSym, Chain}); + return DAG.getMachineNode(GlobalGetIns, DL, PtrVT, TLSBaseSym); + } } \ No newline at end of file diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h index 80e9ffa4ab668..24e0cb7173269 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h @@ -81,7 +81,7 @@ bool canLowerReturn(size_t ResultSize, const WebAssemblySubtarget *Subtarget); // __wasm_component_model_builtin_context_get_1 Otherwise: global.get __tls_base MachineSDNode *getTLSBase(SelectionDAG &DAG, const SDLoc &DL, const WebAssemblySubtarget *Subtarget, - const SDValue *Chain = nullptr); + const SDValue Chain = SDValue()); } // end namespace WebAssembly From de9424cf66cb128d612bbd34799044075ea63174 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 3 Mar 2026 17:56:44 +0000 Subject: [PATCH 070/134] Correct chain --- llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index 8f13e48d11f36..97ecd37b10fdc 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -204,16 +204,15 @@ MachineSDNode *WebAssembly::getTLSBase(SelectionDAG &DAG, const SDLoc &DL, ArrayRef Ops = Chain ? ArrayRef(*Chain) : ArrayRef(); if (Subtarget->hasComponentModelThreadContext()) { -if (Chain.getNode()) - return DAG.getMachineNode(WebAssembly::CALL, DL, {PtrVT, MVT::Other}, - {CallTarget, Chain}); + if (Chain.getNode()) + return DAG.getMachineNode(WebAssembly::CALL, DL, PtrVT, MVT::Other, + CallTarget, Chain); return DAG.getMachineNode(WebAssembly::CALL, DL, PtrVT, CallTarget); } else { SDValue TLSBaseSym = DAG.getTargetExternalSymbol("__tls_base", PtrVT); if (Chain.getNode()) - return DAG.getMachineNode(GlobalGetIns, DL, PtrVT, {TLSBaseSym, Chain}); + return DAG.getMachineNode(GlobalGetIns, DL, PtrVT, MVT::Other, TLSBaseSym, Chain); return DAG.getMachineNode(GlobalGetIns, DL, PtrVT, TLSBaseSym); - } } \ No newline at end of file From 59547558ad58ce036bd73fae3a904e33e84dad8c Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 3 Mar 2026 17:57:02 +0000 Subject: [PATCH 071/134] fmt --- llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index 97ecd37b10fdc..d31d17c6b7006 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -212,7 +212,8 @@ MachineSDNode *WebAssembly::getTLSBase(SelectionDAG &DAG, const SDLoc &DL, } else { SDValue TLSBaseSym = DAG.getTargetExternalSymbol("__tls_base", PtrVT); if (Chain.getNode()) - return DAG.getMachineNode(GlobalGetIns, DL, PtrVT, MVT::Other, TLSBaseSym, Chain); + return DAG.getMachineNode(GlobalGetIns, DL, PtrVT, MVT::Other, TLSBaseSym, + Chain); return DAG.getMachineNode(GlobalGetIns, DL, PtrVT, TLSBaseSym); } } \ No newline at end of file From 1f9e903f668a238acb0857722222fc97ed550b1b Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 3 Mar 2026 17:59:35 +0000 Subject: [PATCH 072/134] Simplify getTLSBase --- .../WebAssembly/WebAssemblyUtilities.cpp | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index d31d17c6b7006..02b8b01bf7631 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -197,23 +197,23 @@ bool WebAssembly::canLowerReturn(size_t ResultSize, MachineSDNode *WebAssembly::getTLSBase(SelectionDAG &DAG, const SDLoc &DL, const WebAssemblySubtarget *Subtarget, - const SDValue Chain) { + SDValue Chain) { MVT PtrVT = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32; - auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 - : WebAssembly::GLOBAL_GET_I32; - ArrayRef Ops = - Chain ? ArrayRef(*Chain) : ArrayRef(); - if (Subtarget->hasComponentModelThreadContext()) { - if (Chain.getNode()) - return DAG.getMachineNode(WebAssembly::CALL, DL, PtrVT, MVT::Other, - CallTarget, Chain); - return DAG.getMachineNode(WebAssembly::CALL, DL, PtrVT, CallTarget); + unsigned Opcode; + const char *SymName; + if (Subtarget->hasComponentModelThreadContext()) { + Opcode = WebAssembly::CALL; + SymName = "__wasm_component_model_builtin_context_get_1"; } else { - SDValue TLSBaseSym = DAG.getTargetExternalSymbol("__tls_base", PtrVT); - if (Chain.getNode()) - return DAG.getMachineNode(GlobalGetIns, DL, PtrVT, MVT::Other, TLSBaseSym, - Chain); - return DAG.getMachineNode(GlobalGetIns, DL, PtrVT, TLSBaseSym); + Opcode = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 + : WebAssembly::GLOBAL_GET_I32; + SymName = "__tls_base"; } + + SDValue Sym = DAG.getTargetExternalSymbol(SymName, PtrVT); + + if (Chain.getNode()) + return DAG.getMachineNode(Opcode, DL, {PtrVT, MVT::Other}, {Sym, Chain}); + return DAG.getMachineNode(Opcode, DL, PtrVT, Sym); } \ No newline at end of file From f61837aa77d50c5fc64bf664869772de09d42c98 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 3 Mar 2026 17:59:54 +0000 Subject: [PATCH 073/134] fmt --- llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index 02b8b01bf7631..af83eb9e2e9bb 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -207,7 +207,7 @@ MachineSDNode *WebAssembly::getTLSBase(SelectionDAG &DAG, const SDLoc &DL, SymName = "__wasm_component_model_builtin_context_get_1"; } else { Opcode = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 - : WebAssembly::GLOBAL_GET_I32; + : WebAssembly::GLOBAL_GET_I32; SymName = "__tls_base"; } From bde41fc6f9f52548eab90eec5be2400b9c85abf0 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 3 Mar 2026 18:16:12 +0000 Subject: [PATCH 074/134] Add missing include --- llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h index 24e0cb7173269..7a508fd9b0873 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h @@ -16,6 +16,7 @@ #define LLVM_LIB_TARGET_WEBASSEMBLY_UTILS_WEBASSEMBLYUTILITIES_H #include "llvm/Support/CommandLine.h" +#include "llvm/CodeGen/SelectionDAGNodes.h" namespace llvm { From daf5b03a9da7f5ba72bf172860cb25422f76b9a6 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 4 Mar 2026 08:37:37 +0000 Subject: [PATCH 075/134] fmt --- llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h index 7a508fd9b0873..9ed46fdb9f793 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h @@ -15,8 +15,8 @@ #ifndef LLVM_LIB_TARGET_WEBASSEMBLY_UTILS_WEBASSEMBLYUTILITIES_H #define LLVM_LIB_TARGET_WEBASSEMBLY_UTILS_WEBASSEMBLYUTILITIES_H -#include "llvm/Support/CommandLine.h" #include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/Support/CommandLine.h" namespace llvm { From 41f8893e22c3999ac386cb56be7c5629b53658b5 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 4 Mar 2026 09:44:51 +0000 Subject: [PATCH 076/134] Revert archive-export changes --- lld/test/wasm/archive-export.test | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lld/test/wasm/archive-export.test b/lld/test/wasm/archive-export.test index 0feab9c67d206..c67e500e46dd2 100644 --- a/lld/test/wasm/archive-export.test +++ b/lld/test/wasm/archive-export.test @@ -1,19 +1,22 @@ Test that --export will also fetch lazy symbols from archives RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/start.s -o %t.o -RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %S/Inputs/archive1.s -o %t.a1.o -RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %S/Inputs/archive2.s -o %t.a2.o +RUN: llc -filetype=obj %S/Inputs/archive1.ll -o %t.a1.o +RUN: llc -filetype=obj %S/Inputs/archive2.ll -o %t.a2.o RUN: rm -f %t.a RUN: llvm-ar rcs %t.a %t.a1.o %t.a2.o RUN: wasm-ld --export-dynamic --export=archive2_symbol -o %t.wasm %t.a %t.o RUN: obj2yaml %t.wasm | FileCheck %s -RUN: wasm-ld --export-dynamic -o %t.noexport.wasm %t.a %t.o -RUN: obj2yaml %t.noexport.wasm | FileCheck %s -check-prefix=NOEXPORT +RUN: wasm-ld --export-dynamic -o %t.wasm %t.a %t.o +RUN: obj2yaml %t.wasm | FileCheck %s -check-prefix=NOEXPORT CHECK: Exports: CHECK-NEXT: - Name: memory CHECK-NEXT: Kind: MEMORY CHECK-NEXT: Index: 0 +CHECK-NEXT: - Name: __stack_pointer +CHECK-NEXT: Kind: GLOBAL +CHECK-NEXT: Index: 0 CHECK-NEXT: - Name: foo CHECK-NEXT: Kind: FUNCTION CHECK-NEXT: Index: 1 @@ -26,9 +29,6 @@ CHECK-NEXT: Index: 3 CHECK-NEXT: - Name: _start CHECK-NEXT: Kind: FUNCTION CHECK-NEXT: Index: 0 -CHECK-NEXT: - Name: __stack_pointer -CHECK-NEXT: Kind: GLOBAL -CHECK-NEXT: Index: 0 CHECK-NEXT: - Type: CODE NOEXPORT: Exports: From 90c342f8bfe1c4a7fde1f154234aac9b9e71585c Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 4 Mar 2026 10:33:23 +0000 Subject: [PATCH 077/134] Revert archive-export changes --- lld/test/wasm/archive-export.test | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lld/test/wasm/archive-export.test b/lld/test/wasm/archive-export.test index c67e500e46dd2..7059812c929f2 100644 --- a/lld/test/wasm/archive-export.test +++ b/lld/test/wasm/archive-export.test @@ -1,22 +1,19 @@ Test that --export will also fetch lazy symbols from archives RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/start.s -o %t.o -RUN: llc -filetype=obj %S/Inputs/archive1.ll -o %t.a1.o -RUN: llc -filetype=obj %S/Inputs/archive2.ll -o %t.a2.o +RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %S/Inputs/archive1.s -o %t.a1.o +RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %S/Inputs/archive2.s -o %t.a2.o RUN: rm -f %t.a RUN: llvm-ar rcs %t.a %t.a1.o %t.a2.o RUN: wasm-ld --export-dynamic --export=archive2_symbol -o %t.wasm %t.a %t.o RUN: obj2yaml %t.wasm | FileCheck %s -RUN: wasm-ld --export-dynamic -o %t.wasm %t.a %t.o -RUN: obj2yaml %t.wasm | FileCheck %s -check-prefix=NOEXPORT +RUN: wasm-ld --export-dynamic -o %t.noexport.wasm %t.a %t.o +RUN: obj2yaml %t.noexport.wasm | FileCheck %s -check-prefix=NOEXPORT CHECK: Exports: CHECK-NEXT: - Name: memory CHECK-NEXT: Kind: MEMORY CHECK-NEXT: Index: 0 -CHECK-NEXT: - Name: __stack_pointer -CHECK-NEXT: Kind: GLOBAL -CHECK-NEXT: Index: 0 CHECK-NEXT: - Name: foo CHECK-NEXT: Kind: FUNCTION CHECK-NEXT: Index: 1 From 13d3870930024318aa3e14cdc825713f653bc73d Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 4 Mar 2026 10:37:44 +0000 Subject: [PATCH 078/134] Revert tailcail changes --- llvm/test/CodeGen/WebAssembly/tailcall.ll | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/llvm/test/CodeGen/WebAssembly/tailcall.ll b/llvm/test/CodeGen/WebAssembly/tailcall.ll index e255c8b94276a..aea853fdd8e7e 100644 --- a/llvm/test/CodeGen/WebAssembly/tailcall.ll +++ b/llvm/test/CodeGen/WebAssembly/tailcall.ll @@ -582,10 +582,4 @@ define i32 @unique_caller(ptr %p) { } ; CHECK-LABEL: .section .custom_section.target_features -; CHECK-NEXT: .int8 2 -; CHECK-NEXT: .int8 45 -; CHECK-NEXT: .int8 30 -; CHECK-NEXT: .ascii "component-model-thread-context" -; CHECK-NEXT: .int8 43 -; CHECK-NEXT: .int8 9 -; CHECK-NEXT: .ascii "tail-call" +; CHECK: .ascii "tail-call" From f75cb64f41c8eae2b8a13ffe6c6974ca6a420c51 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 4 Mar 2026 21:43:08 +0000 Subject: [PATCH 079/134] Revert tail call change --- llvm/test/CodeGen/WebAssembly/tailcall.ll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/test/CodeGen/WebAssembly/tailcall.ll b/llvm/test/CodeGen/WebAssembly/tailcall.ll index aea853fdd8e7e..df066f4a53057 100644 --- a/llvm/test/CodeGen/WebAssembly/tailcall.ll +++ b/llvm/test/CodeGen/WebAssembly/tailcall.ll @@ -582,4 +582,4 @@ define i32 @unique_caller(ptr %p) { } ; CHECK-LABEL: .section .custom_section.target_features -; CHECK: .ascii "tail-call" +; CHECK: .ascii "tail-call" From e1992e8299b428176c15f752fa00c9eb472f5161 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 4 Mar 2026 21:46:16 +0000 Subject: [PATCH 080/134] Review comments --- .../Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h | 2 +- llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h index d642ef2ccf2a4..a27261a1218ed 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -106,7 +106,7 @@ enum TOF { MO_MEMORY_BASE_REL, // On a symbol operand this indicates that the immediate is the symbol - // address relative to the TLS base. This is stored in thread.context[1] + // address relative to the TLS base. This is stored in context.get(1) // when using the component model thread context, and the __tls_base global // otherwise. Only applicable to data symbols. MO_TLS_BASE_REL, diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index af83eb9e2e9bb..4d5b5cb64625f 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -216,4 +216,4 @@ MachineSDNode *WebAssembly::getTLSBase(SelectionDAG &DAG, const SDLoc &DL, if (Chain.getNode()) return DAG.getMachineNode(Opcode, DL, {PtrVT, MVT::Other}, {Sym, Chain}); return DAG.getMachineNode(Opcode, DL, PtrVT, Sym); -} \ No newline at end of file +} From c3d46dc891d00c320902425e1d781135db9da894 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Thu, 5 Mar 2026 08:47:42 +0000 Subject: [PATCH 081/134] Newlines --- lld/test/wasm/Inputs/disallow-component-model-thread-context.s | 2 +- lld/test/wasm/stack-pointer-abi.s | 2 +- lld/test/wasm/tls-component-model.s | 2 +- llvm/test/MC/WebAssembly/import-module.s | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lld/test/wasm/Inputs/disallow-component-model-thread-context.s b/lld/test/wasm/Inputs/disallow-component-model-thread-context.s index 1af0292d2ec4b..16893a31dd568 100644 --- a/lld/test/wasm/Inputs/disallow-component-model-thread-context.s +++ b/lld/test/wasm/Inputs/disallow-component-model-thread-context.s @@ -3,4 +3,4 @@ .int8 1 .int8 45 .int8 30 - .ascii "component-model-thread-context" \ No newline at end of file + .ascii "component-model-thread-context" diff --git a/lld/test/wasm/stack-pointer-abi.s b/lld/test/wasm/stack-pointer-abi.s index fdffe30ce295a..a6bc14caa8708 100644 --- a/lld/test/wasm/stack-pointer-abi.s +++ b/lld/test/wasm/stack-pointer-abi.s @@ -12,4 +12,4 @@ _start: end_function # COMPONENT-MODEL: Name: __init_stack_pointer -# GLOBAL: Name: __stack_pointer \ No newline at end of file +# GLOBAL: Name: __stack_pointer diff --git a/lld/test/wasm/tls-component-model.s b/lld/test/wasm/tls-component-model.s index 71e6442435426..6c0ab4ad79921 100644 --- a/lld/test/wasm/tls-component-model.s +++ b/lld/test/wasm/tls-component-model.s @@ -74,4 +74,4 @@ tls2: # DIS-NEXT: i32.add # DIS-NEXT: i32.load 0 # DIS-NEXT: i32.add -# DIS-NEXT: end \ No newline at end of file +# DIS-NEXT: end diff --git a/llvm/test/MC/WebAssembly/import-module.s b/llvm/test/MC/WebAssembly/import-module.s index 75090001755a9..5aa41f166e6c7 100644 --- a/llvm/test/MC/WebAssembly/import-module.s +++ b/llvm/test/MC/WebAssembly/import-module.s @@ -45,4 +45,4 @@ test: # CHECK-NEXT: Flags: [ UNDEFINED ] # CHECK: Name: __wasm_component_model_builtin_context_get_0 -# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ] \ No newline at end of file +# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ] From 9ecceef62c1d8b419a4052cd9feed09eec8d4afc Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Thu, 5 Mar 2026 08:47:53 +0000 Subject: [PATCH 082/134] Newlines --- llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll | 2 +- llvm/test/CodeGen/WebAssembly/target-features-tls.ll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll b/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll index 9592c35081c2a..db383e74b8283 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll @@ -67,4 +67,4 @@ define void @test() { ret void -} \ No newline at end of file +} diff --git a/llvm/test/CodeGen/WebAssembly/target-features-tls.ll b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll index e9d42036a0772..870711ff0971b 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-tls.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll @@ -70,4 +70,4 @@ target triple = "wasm32-unknown-unknown" ; BULK-MEM-CMTC-NEXT: .int8 43 ; BULK-MEM-CMTC-NEXT: .int8 30 ; BULK-MEM-CMTC-NEXT: .ascii "component-model-thread-context" -; BULK-MEM-CMTC-NEXT: .tbss.foo,"T",@ \ No newline at end of file +; BULK-MEM-CMTC-NEXT: .tbss.foo,"T",@ From 9d296ecb47f1bb9e72b36871a8461bf0b8cb4a65 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Thu, 5 Mar 2026 08:54:08 +0000 Subject: [PATCH 083/134] Remove changes from other PR --- .../AsmParser/WebAssemblyAsmParser.cpp | 23 ++----------- .../WebAssemblyTargetStreamer.cpp | 33 ++++--------------- .../test/MC/WebAssembly/export-name-invalid.s | 2 +- llvm/test/MC/WebAssembly/export-name.s | 12 ------- .../MC/WebAssembly/import-module-invalid.s | 2 +- llvm/test/MC/WebAssembly/import-module.s | 14 -------- .../test/MC/WebAssembly/import-name-invalid.s | 2 +- 7 files changed, 12 insertions(+), 76 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp index b48abe85aca91..9175b2731dac0 100644 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -415,23 +415,6 @@ 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(); - return Name; - } - error("Expected string or identifier, got: ", Lexer.getTok()); - return StringRef(); - } - bool parseRegTypeList(SmallVectorImpl &Types) { while (Lexer.is(AsmToken::Identifier)) { auto Type = WebAssembly::parseType(Lexer.getTok().getString()); @@ -1058,7 +1041,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser { return ParseStatus::Failure; if (expect(AsmToken::Comma, ",")) return ParseStatus::Failure; - auto ExportName = expectStringOrIdent(); + auto ExportName = expectIdent(); if (ExportName.empty()) return ParseStatus::Failure; auto *WasmSym = @@ -1074,7 +1057,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser { return ParseStatus::Failure; if (expect(AsmToken::Comma, ",")) return ParseStatus::Failure; - auto ImportModule = expectStringOrIdent(); + auto ImportModule = expectIdent(); if (ImportModule.empty()) return ParseStatus::Failure; auto *WasmSym = @@ -1090,7 +1073,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser { return ParseStatus::Failure; if (expect(AsmToken::Comma, ",")) return ParseStatus::Failure; - StringRef ImportName = expectStringOrIdent(); + auto ImportName = expectIdent(); if (ImportName.empty()) return ParseStatus::Failure; auto *WasmSym = diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp index bb643a956b6c4..c18de5fc1939e 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -22,17 +22,6 @@ #include "llvm/Support/FormattedStream.h" using namespace llvm; -static bool shouldQuoteName(StringRef Name) { - // Wasm export/import names and import module names can contain characters - // that are not allowed in identifiers, so we need to quote them. - auto isValidStartChar = [](char C) { - return isalpha(C) || C == '_' || C == '.'; - }; - auto isValidChar = [&](char C) { return isValidStartChar(C) || isdigit(C); }; - return !(Name.size() > 0 && isValidStartChar(Name.front())) || - llvm::any_of(Name, [&](char C) { return !isValidChar(C); }); -} - WebAssemblyTargetStreamer::WebAssemblyTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {} @@ -105,32 +94,22 @@ void WebAssemblyTargetAsmStreamer::emitTagType(const MCSymbolWasm *Sym) { OS << "\n"; } -static void emitNameWithQuoting(formatted_raw_ostream &OS, StringRef Name) { - if (shouldQuoteName(Name)) - OS << '"' << Name << '"'; - else - OS << Name; -} - void WebAssemblyTargetAsmStreamer::emitImportModule(const MCSymbolWasm *Sym, StringRef ImportModule) { - OS << "\t.import_module\t" << Sym->getName() << ", "; - emitNameWithQuoting(OS, ImportModule); - OS << '\n'; + OS << "\t.import_module\t" << Sym->getName() << ", " + << ImportModule << '\n'; } void WebAssemblyTargetAsmStreamer::emitImportName(const MCSymbolWasm *Sym, StringRef ImportName) { - OS << "\t.import_name\t" << Sym->getName() << ", "; - emitNameWithQuoting(OS, ImportName); - OS << '\n'; + OS << "\t.import_name\t" << Sym->getName() << ", " + << ImportName << '\n'; } void WebAssemblyTargetAsmStreamer::emitExportName(const MCSymbolWasm *Sym, StringRef ExportName) { - OS << "\t.export_name\t" << Sym->getName() << ", "; - emitNameWithQuoting(OS, ExportName); - OS << '\n'; + OS << "\t.export_name\t" << Sym->getName() << ", " + << ExportName << '\n'; } void WebAssemblyTargetAsmStreamer::emitIndIdx(const MCExpr *Value) { diff --git a/llvm/test/MC/WebAssembly/export-name-invalid.s b/llvm/test/MC/WebAssembly/export-name-invalid.s index 1272bf66fa143..ad322ce949f5e 100644 --- a/llvm/test/MC/WebAssembly/export-name-invalid.s +++ b/llvm/test/MC/WebAssembly/export-name-invalid.s @@ -6,7 +6,7 @@ # CHECK: [[#@LINE+1]]:17: error: Expected ,, instead got: .export_name foo -# CHECK: [[#@LINE+1]]:18: error: Expected string or identifier, got: +# CHECK: [[#@LINE+1]]:18: error: Expected identifier, got: .export_name foo, # CHECK: [[#@LINE+1]]:22: error: Expected EOL, instead got: , diff --git a/llvm/test/MC/WebAssembly/export-name.s b/llvm/test/MC/WebAssembly/export-name.s index 915cd3307a4b0..51e1bcf73dba2 100644 --- a/llvm/test/MC/WebAssembly/export-name.s +++ b/llvm/test/MC/WebAssembly/export-name.s @@ -8,14 +8,7 @@ foo: .export_name foo, bar end_function -baz: - .globl baz - .functype baz () -> () - .export_name baz, "[baz]" - end_function - # CHECK: .export_name foo, bar -# CHECK: .export_name baz, "[baz]" # CHECK-OBJ: - Type: EXPORT # CHECK-OBJ-NEXT: Exports: @@ -31,8 +24,3 @@ baz: # CHECK-OBJ-NEXT: Name: foo # CHECK-OBJ-NEXT: Flags: [ EXPORTED ] # CHECK-OBJ-NEXT: Function: 0 -# CHECK-OBJ-NEXT: - Index: 1 -# CHECK-OBJ-NEXT: Kind: FUNCTION -# CHECK-OBJ-NEXT: Name: baz -# CHECK-OBJ-NEXT: Flags: [ EXPORTED ] -# CHECK-OBJ-NEXT: Function: 1 diff --git a/llvm/test/MC/WebAssembly/import-module-invalid.s b/llvm/test/MC/WebAssembly/import-module-invalid.s index daf18f2e6a505..a9f93e83dba39 100644 --- a/llvm/test/MC/WebAssembly/import-module-invalid.s +++ b/llvm/test/MC/WebAssembly/import-module-invalid.s @@ -6,7 +6,7 @@ # CHECK: [[#@LINE+1]]:19: error: Expected ,, instead got: .import_module foo -# CHECK: [[#@LINE+1]]:20: error: Expected string or identifier, got: +# CHECK: [[#@LINE+1]]:20: error: Expected identifier, got: .import_module foo, # CHECK: [[#@LINE+1]]:24: error: Expected EOL, instead got: , diff --git a/llvm/test/MC/WebAssembly/import-module.s b/llvm/test/MC/WebAssembly/import-module.s index 5aa41f166e6c7..5d28d5b9c0b92 100644 --- a/llvm/test/MC/WebAssembly/import-module.s +++ b/llvm/test/MC/WebAssembly/import-module.s @@ -3,22 +3,16 @@ .functype foo () -> () .functype plain () -> () -.functype __wasm_component_model_builtin_context_get_0 () -> (i32) test: .functype test () -> () call foo call plain - call __wasm_component_model_builtin_context_get_0 - drop end_function .import_module foo, bar .import_name foo, qux - .import_module __wasm_component_model_builtin_context_get_0, "$root" - .import_name __wasm_component_model_builtin_context_get_0, "[context-get-0]" - # CHECK-ASM: .import_module foo, bar # CHECK-ASM: .import_name foo, qux @@ -32,17 +26,9 @@ test: # CHECK-NEXT: Field: plain # CHECK-NEXT: Kind: FUNCTION -# CHECK: - Module: '$root' -# CHECK-NEXT: Field: '[context-get-0]' -# CHECK-NEXT: Kind: FUNCTION -# CHECK-NEXT: SigIndex: 1 - # CHECK: - Type: CUSTOM # CHECK: Name: foo # CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ] # CHECK: Name: plain # CHECK-NEXT: Flags: [ UNDEFINED ] - -# CHECK: Name: __wasm_component_model_builtin_context_get_0 -# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ] diff --git a/llvm/test/MC/WebAssembly/import-name-invalid.s b/llvm/test/MC/WebAssembly/import-name-invalid.s index df709f6380a06..da8ed0d4617b0 100644 --- a/llvm/test/MC/WebAssembly/import-name-invalid.s +++ b/llvm/test/MC/WebAssembly/import-name-invalid.s @@ -6,7 +6,7 @@ # CHECK: [[#@LINE+1]]:17: error: Expected ,, instead got: .import_name foo -# CHECK: [[#@LINE+1]]:18: error: Expected string or identifier, got: +# CHECK: [[#@LINE+1]]:18: error: Expected identifier, got: .import_name foo, # CHECK: [[#@LINE+1]]:22: error: Expected EOL, instead got: , From 95fc53a9ba35f5a150f09ec2f32fc4cbb95d374a Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Thu, 5 Mar 2026 08:54:22 +0000 Subject: [PATCH 084/134] Comments --- lld/wasm/Writer.cpp | 2 +- llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index f7334672dad2b..110216a62096d 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1363,7 +1363,7 @@ void Writer::createInitMemoryFunction() { } // When we initialize the TLS segment we also set the `__tls_base` - // global/thread.context[1]. This allows the runtime to use this + // global/context.get(1). This allows the runtime to use this // static copy of the TLS data for the first/main thread. if (ctx.isMultithreaded() && s->isTLS()) { if (ctx.isPic) { diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp index c846215ce0e7c..c0fa65abcba7a 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp @@ -377,7 +377,7 @@ bool WebAssemblyLateEHPrepare::removeUnnecessaryUnreachables( } // After the stack is unwound due to a thrown exception, the __stack_pointer -// global/context[0] can point to an invalid address. This inserts instructions +// global/context.get(0) can point to an invalid address. This inserts instructions // that restore the stack pointer state.. bool WebAssemblyLateEHPrepare::restoreStackPointer(MachineFunction &MF) { const auto *FrameLowering = static_cast( From ae859d08c2691ca1b46245188eacdb23e4a7d50e Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Thu, 5 Mar 2026 09:07:32 +0000 Subject: [PATCH 085/134] split-file --- .../disallow-component-model-thread-context.s | 6 ---- lld/test/wasm/Inputs/stack-pointer.s | 11 ------ .../use-component-model-thread-context.s | 6 ---- lld/test/wasm/stack-pointer-abi.s | 31 +++++++++++++---- lld/test/wasm/thread-context-abi-mismatch.s | 34 ++++++++++++++++--- 5 files changed, 53 insertions(+), 35 deletions(-) delete mode 100644 lld/test/wasm/Inputs/disallow-component-model-thread-context.s delete mode 100644 lld/test/wasm/Inputs/stack-pointer.s delete mode 100644 lld/test/wasm/Inputs/use-component-model-thread-context.s diff --git a/lld/test/wasm/Inputs/disallow-component-model-thread-context.s b/lld/test/wasm/Inputs/disallow-component-model-thread-context.s deleted file mode 100644 index 16893a31dd568..0000000000000 --- a/lld/test/wasm/Inputs/disallow-component-model-thread-context.s +++ /dev/null @@ -1,6 +0,0 @@ -# Mark the feature as DISALLOWED -.section .custom_section.target_features,"",@ - .int8 1 - .int8 45 - .int8 30 - .ascii "component-model-thread-context" diff --git a/lld/test/wasm/Inputs/stack-pointer.s b/lld/test/wasm/Inputs/stack-pointer.s deleted file mode 100644 index cfd76578a5e07..0000000000000 --- a/lld/test/wasm/Inputs/stack-pointer.s +++ /dev/null @@ -1,11 +0,0 @@ -.globaltype __stack_pointer, i32 - -.globl _start -_start: - .functype _start () -> (i32) - global.get __stack_pointer - i32.const 16 - i32.sub - drop - i32.const 0 - end_function \ No newline at end of file diff --git a/lld/test/wasm/Inputs/use-component-model-thread-context.s b/lld/test/wasm/Inputs/use-component-model-thread-context.s deleted file mode 100644 index 1c9554edb7e55..0000000000000 --- a/lld/test/wasm/Inputs/use-component-model-thread-context.s +++ /dev/null @@ -1,6 +0,0 @@ -# Mark the feature as USED -.section .custom_section.target_features,"",@ - .int8 1 - .int8 43 - .int8 30 - .ascii "component-model-thread-context" \ No newline at end of file diff --git a/lld/test/wasm/stack-pointer-abi.s b/lld/test/wasm/stack-pointer-abi.s index a6bc14caa8708..e03e9867c403b 100644 --- a/lld/test/wasm/stack-pointer-abi.s +++ b/lld/test/wasm/stack-pointer-abi.s @@ -1,15 +1,32 @@ -# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t-component-model.o %S/Inputs/use-component-model-thread-context.s -# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t-global.o %S/Inputs/disallow-component-model-thread-context.s -# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s -# RUN: wasm-ld --component-model-thread-context -o %t-component-model.wasm %t-component-model.o %t.o -# RUN: obj2yaml %t-component-model.wasm | FileCheck %s --check-prefix=COMPONENT-MODEL -# RUN: wasm-ld -o %t-original.wasm %t-global.o %t.o -# RUN: obj2yaml %t-original.wasm | FileCheck %s --check-prefix=GLOBAL +# RUN: split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/use.o %t/use.s +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/disallow.o %t/disallow.s +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/start.o %t/start.s +# RUN: wasm-ld --component-model-thread-context -o %t/component-model.wasm %t/use.o %t/start.o +# RUN: obj2yaml %t/component-model.wasm | FileCheck %s --check-prefix=COMPONENT-MODEL +# RUN: wasm-ld -o %t/global.wasm %t/disallow.o %t/start.o +# RUN: obj2yaml %t/global.wasm | FileCheck %s --check-prefix=GLOBAL +#--- start.s .globl _start _start: .functype _start () -> () end_function +#--- disallow.s +.section .custom_section.target_features,"",@ + .int8 1 + .int8 45 + .int8 30 + .ascii "component-model-thread-context" + +#--- use.s + +.section .custom_section.target_features,"",@ + .int8 1 + .int8 43 + .int8 30 + .ascii "component-model-thread-context" + # COMPONENT-MODEL: Name: __init_stack_pointer # GLOBAL: Name: __stack_pointer diff --git a/lld/test/wasm/thread-context-abi-mismatch.s b/lld/test/wasm/thread-context-abi-mismatch.s index 3fe89a353134b..b067b7c580caf 100644 --- a/lld/test/wasm/thread-context-abi-mismatch.s +++ b/lld/test/wasm/thread-context-abi-mismatch.s @@ -1,20 +1,24 @@ # Test that linking object files with mismatched thread context ABIs fails with an error. +# RUN: split-file %s %t + # Test that the presence of an import of __stack_pointer from the env module is treated # as an indication that the global thread context ABI is being used, even if the # component-model-thread-context feature is not disallowed. -# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t-with.o %s -# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t-without.o %S/Inputs/stack-pointer.s -# RUN: not wasm-ld %t-with.o %t-without.o -o %t.wasm 2>&1 | FileCheck %s +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/start.o %t/start.s +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/stack-pointer.o %t/stack-pointer.s +# RUN: not wasm-ld %t/start.o %t/stack-pointer.o -o %t/fail.wasm 2>&1 | FileCheck %s # Test that explicitly disallowing the component-model-thread-context feature causes linking to fail # with an error when other files use the feature. -# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t-disallow.o %S/Inputs/disallow-component-model-thread-context.s -# RUN: not wasm-ld %t-with.o %t-disallow.o -o %t.wasm 2>&1 | FileCheck %s +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/disallow.o %t/disallow.s +# RUN: not wasm-ld %t/start.o %t/disallow.o -o %t/fail.wasm 2>&1 | FileCheck %s # CHECK: error: thread context ABI mismatch: {{.*}} disallows component-model-thread-context but other files use it + +#--- start.s .globl _start _start: .functype _start () -> () @@ -26,3 +30,23 @@ _start: .int8 43 .int8 30 .ascii "component-model-thread-context" + +#--- stack-pointer.s +.globaltype __stack_pointer, i32 + +.globl _start +_start: + .functype _start () -> (i32) + global.get __stack_pointer + i32.const 16 + i32.sub + drop + i32.const 0 + end_function + +#--- disallow.s +.section .custom_section.target_features,"",@ + .int8 1 + .int8 45 + .int8 30 + .ascii "component-model-thread-context" From abc859d4ddca4b7bd6c27a3502c5d2ed21d7a63c Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Thu, 5 Mar 2026 09:25:45 +0000 Subject: [PATCH 086/134] Don't disable feature for MVP cpu --- .../Target/WebAssembly/WebAssemblyTargetMachine.cpp | 7 ++++--- llvm/test/CodeGen/WebAssembly/memory64-feature.ll | 5 +---- llvm/test/CodeGen/WebAssembly/multivalue.ll | 5 +---- llvm/test/CodeGen/WebAssembly/mutable-globals.ll | 5 +---- llvm/test/CodeGen/WebAssembly/reference-types.ll | 5 +---- llvm/test/CodeGen/WebAssembly/target-features-attrs.ll | 10 ++-------- llvm/test/CodeGen/WebAssembly/target-features-tls.ll | 10 ++-------- 7 files changed, 12 insertions(+), 35 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index f8d3b4a69ea57..db6c0ad48c28f 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -311,7 +311,7 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { stripAtomics(M); } - recordFeatures(M, Features, StrippedAtomics || StrippedTLS); + recordFeatures(M, WasmTM->getTargetCPU(), Features, StrippedAtomics || StrippedTLS); // Conservatively assume we have made some change return true; @@ -414,7 +414,7 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { return Stripped; } - void recordFeatures(Module &M, const FeatureBitset &Features, bool Stripped) { + void recordFeatures(Module &M, StringRef CPU, const FeatureBitset &Features, bool Stripped) { for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) { if (Features[KV.Value]) { // Mark features as used @@ -435,7 +435,8 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { // Mark component-model-thread-context as disallowed when not in use to // prevent linking object files with incompatible threading ABIs. - if (!Features[WebAssembly::FeatureComponentModelThreadContext]) { + // This is implicit for MVP since the feature is not supported at all. + if (CPU != "mvp" && !Features[WebAssembly::FeatureComponentModelThreadContext]) { M.addModuleFlag(Module::ModFlagBehavior::Error, "wasm-feature-component-model-thread-context", wasm::WASM_FEATURE_PREFIX_DISALLOWED); diff --git a/llvm/test/CodeGen/WebAssembly/memory64-feature.ll b/llvm/test/CodeGen/WebAssembly/memory64-feature.ll index c27756a00b4f7..bd277dfdc37d3 100644 --- a/llvm/test/CodeGen/WebAssembly/memory64-feature.ll +++ b/llvm/test/CodeGen/WebAssembly/memory64-feature.ll @@ -9,10 +9,7 @@ define void @foo() { } ; CHECK-LABEL: .custom_section.target_features -; CHECK-NEXT: .int8 2 -; CHECK-NEXT: .int8 45 -; CHECK-NEXT: .int8 30 -; CHECK-NEXT: .ascii "component-model-thread-context" +; CHECK-NEXT: .int8 1 ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 8 ; CHECK-NEXT: .ascii "memory64" diff --git a/llvm/test/CodeGen/WebAssembly/multivalue.ll b/llvm/test/CodeGen/WebAssembly/multivalue.ll index 018e144545277..537adff3f3405 100644 --- a/llvm/test/CodeGen/WebAssembly/multivalue.ll +++ b/llvm/test/CodeGen/WebAssembly/multivalue.ll @@ -252,10 +252,7 @@ loop: } ; CHECK-LABEL: .section .custom_section.target_features -; CHECK-NEXT: .int8 3 -; CHECK-NEXT: .int8 45 -; CHECK-NEXT: .int8 30 -; CHECK-NEXT: .ascii "component-model-thread-context" +; CHECK-NEXT: .int8 2 ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 10 ; CHECK-NEXT: .ascii "multivalue" diff --git a/llvm/test/CodeGen/WebAssembly/mutable-globals.ll b/llvm/test/CodeGen/WebAssembly/mutable-globals.ll index 24e28c52f98cc..93962f7e6d92c 100644 --- a/llvm/test/CodeGen/WebAssembly/mutable-globals.ll +++ b/llvm/test/CodeGen/WebAssembly/mutable-globals.ll @@ -9,10 +9,7 @@ define void @foo() { } ; CHECK-LABEL: .custom_section.target_features -; CHECK-NEXT: .int8 2 -; CHECK-NEXT: .int8 45 -; CHECK-NEXT: .int8 30 -; CHECK-NEXT: .ascii "component-model-thread-context" +; CHECK-NEXT: .int8 1 ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 15 ; CHECK-NEXT: .ascii "mutable-globals" diff --git a/llvm/test/CodeGen/WebAssembly/reference-types.ll b/llvm/test/CodeGen/WebAssembly/reference-types.ll index dbe1a4b029312..3df383b023726 100644 --- a/llvm/test/CodeGen/WebAssembly/reference-types.ll +++ b/llvm/test/CodeGen/WebAssembly/reference-types.ll @@ -8,13 +8,10 @@ define void @reference-types() { } ; CHECK: .section .custom_section.target_features,"",@ -; CHECK-NEXT: .int8 3 +; CHECK-NEXT: .int8 2 ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 22 ; CHECK-NEXT: .ascii "call-indirect-overlong" -; CHECK-NEXT: .int8 45 -; CHECK-NEXT: .int8 30 -; CHECK-NEXT: .ascii "component-model-thread-context" ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 15 ; CHECK-NEXT: .ascii "reference-types" diff --git a/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll b/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll index cec038aae490d..8e70c0607adb1 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll @@ -55,16 +55,13 @@ attributes #2 = { "target-features"="+reference-types" } ; Features in function attributes: ; +atomics, +nontrapping-fptoint, +reference-types, -component-model-thread-context ; CHECK-LABEL: .custom_section.target_features,"",@ -; CHECK-NEXT: .int8 5 +; CHECK-NEXT: .int8 4 ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 7 ; CHECK-NEXT: .ascii "atomics" ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 22 ; CHECK-NEXT: .ascii "call-indirect-overlong" -; CHECK-NEXT: .int8 45 -; CHECK-NEXT: .int8 30 -; CHECK-NEXT: .ascii "component-model-thread-context" ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 19 ; CHECK-NEXT: .ascii "nontrapping-fptoint" @@ -75,16 +72,13 @@ attributes #2 = { "target-features"="+reference-types" } ; Features in function attributes + features specified by -mattr= option: ; +atomics, +nontrapping-fptoint, +reference-types, +simd128, -component-model-thread-context ; SIMD128-LABEL: .custom_section.target_features,"",@ -; SIMD128-NEXT: .int8 6 +; SIMD128-NEXT: .int8 5 ; SIMD128-NEXT: .int8 43 ; SIMD128-NEXT: .int8 7 ; SIMD128-NEXT: .ascii "atomics" ; SIMD128-NEXT: .int8 43 ; SIMD128-NEXT: .int8 22 ; SIMD128-NEXT: .ascii "call-indirect-overlong" -; SIMD128-NEXT: .int8 45 -; SIMD128-NEXT: .int8 30 -; SIMD128-NEXT: .ascii "component-model-thread-context" ; SIMD128-NEXT: .int8 43 ; SIMD128-NEXT: .int8 19 ; SIMD128-NEXT: .ascii "nontrapping-fptoint" diff --git a/llvm/test/CodeGen/WebAssembly/target-features-tls.ll b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll index 870711ff0971b..946d5cb5691b4 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-tls.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll @@ -12,21 +12,18 @@ target triple = "wasm32-unknown-unknown" ; -bulk-memory ; NO-BULK-MEM-LABEL: .custom_section.target_features,"",@ -; NO-BULK-MEM-NEXT: .int8 3 +; NO-BULK-MEM-NEXT: .int8 2 ; NO-BULK-MEM-NEXT: .int8 43 ; NO-BULK-MEM-NEXT: .int8 7 ; NO-BULK-MEM-NEXT: .ascii "atomics" ; NO-BULK-MEM-NEXT: .int8 45 -; NO-BULK-MEM-NEXT: .int8 30 -; NO-BULK-MEM-NEXT: .ascii "component-model-thread-context" -; NO-BULK-MEM-NEXT: .int8 45 ; NO-BULK-MEM-NEXT: .int8 10 ; NO-BULK-MEM-NEXT: .ascii "shared-mem" ; NO-BULK-MEM-NEXT: .bss.foo,"",@ ; +bulk-memory ; BULK-MEM-LABEL: .custom_section.target_features,"",@ -; BULK-MEM-NEXT: .int8 4 +; BULK-MEM-NEXT: .int8 3 ; BULK-MEM-NEXT: .int8 43 ; BULK-MEM-NEXT: .int8 7 ; BULK-MEM-NEXT: .ascii "atomics" @@ -36,9 +33,6 @@ target triple = "wasm32-unknown-unknown" ; BULK-MEM-NEXT: .int8 43 ; BULK-MEM-NEXT: .int8 15 ; BULK-MEM-NEXT: .ascii "bulk-memory-opt" -; BULK-MEM-NEXT: .int8 45 -; BULK-MEM-NEXT: .int8 30 -; BULK-MEM-NEXT: .ascii "component-model-thread-context" ; BULK-MEM-NEXT: .tbss.foo,"T",@ ; -bulk-memory,+component-model-thread-context From 3749d9eb57eb29ef5ec7d14fb3e21212f21c81cc Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Thu, 5 Mar 2026 09:25:54 +0000 Subject: [PATCH 087/134] Don't disable feature for MVP cpu --- llvm/test/CodeGen/WebAssembly/target-features-cpus.ll | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll b/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll index ff82e2ae6894a..0081a1d661f4e 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll @@ -9,13 +9,8 @@ target triple = "wasm32-unknown-unknown" -; mvp: -component_model_thread_context -; MVP-LABEL: .section .custom_section.target_features,"",@ -; MVP-NEXT: .int8 1 -; MVP-NEXT: .int8 45 -; MVP-NEXT: .int8 30 -; MVP-NEXT: .ascii "component-model-thread-context" -; MVP-NEXT: .text +; mvp: should not contain the target features section +; MVP-NOT: .custom_section.target_features,"",@ ; generic: +call-indirect-overlong, +multivalue, +mutable-globals, +reference-types, +sign-ext, -component-model-thread-context ; GENERIC-LABEL: .custom_section.target_features,"",@ From 0028170132e4a58ad344bf2368133bd1c5094418 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Thu, 5 Mar 2026 09:30:20 +0000 Subject: [PATCH 088/134] fmt --- .../Target/WebAssembly/WebAssemblyLateEHPrepare.cpp | 4 ++-- .../Target/WebAssembly/WebAssemblyTargetMachine.cpp | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp index c0fa65abcba7a..74a8d5a775d2c 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp @@ -377,8 +377,8 @@ bool WebAssemblyLateEHPrepare::removeUnnecessaryUnreachables( } // After the stack is unwound due to a thrown exception, the __stack_pointer -// global/context.get(0) can point to an invalid address. This inserts instructions -// that restore the stack pointer state.. +// global/context.get(0) can point to an invalid address. This inserts +// instructions that restore the stack pointer state.. bool WebAssemblyLateEHPrepare::restoreStackPointer(MachineFunction &MF) { const auto *FrameLowering = static_cast( MF.getSubtarget().getFrameLowering()); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index db6c0ad48c28f..c9c7b593a4e15 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -311,7 +311,8 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { stripAtomics(M); } - recordFeatures(M, WasmTM->getTargetCPU(), Features, StrippedAtomics || StrippedTLS); + recordFeatures(M, WasmTM->getTargetCPU(), Features, + StrippedAtomics || StrippedTLS); // Conservatively assume we have made some change return true; @@ -414,7 +415,8 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { return Stripped; } - void recordFeatures(Module &M, StringRef CPU, const FeatureBitset &Features, bool Stripped) { + void recordFeatures(Module &M, StringRef CPU, const FeatureBitset &Features, + bool Stripped) { for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) { if (Features[KV.Value]) { // Mark features as used @@ -435,8 +437,9 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { // Mark component-model-thread-context as disallowed when not in use to // prevent linking object files with incompatible threading ABIs. - // This is implicit for MVP since the feature is not supported at all. - if (CPU != "mvp" && !Features[WebAssembly::FeatureComponentModelThreadContext]) { + // This is implicit for MVP since the feature is not supported at all. + if (CPU != "mvp" && + !Features[WebAssembly::FeatureComponentModelThreadContext]) { M.addModuleFlag(Module::ModFlagBehavior::Error, "wasm-feature-component-model-thread-context", wasm::WASM_FEATURE_PREFIX_DISALLOWED); From f9f40b71a52bdf3bcc2dd9dc781d00140f694d90 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Thu, 5 Mar 2026 10:00:52 +0000 Subject: [PATCH 089/134] Revert test changes --- llvm/test/MC/WebAssembly/array-fill.ll | 5 ----- llvm/test/MC/WebAssembly/assembler-binary.ll | 5 ----- llvm/test/MC/WebAssembly/bss.ll | 5 ----- llvm/test/MC/WebAssembly/comdat.ll | 5 ----- llvm/test/MC/WebAssembly/debug-info.ll | 6 ------ llvm/test/MC/WebAssembly/debug-info64.ll | 2 +- llvm/test/MC/WebAssembly/explicit-sections.ll | 5 ----- llvm/test/MC/WebAssembly/global-ctor-dtor.ll | 5 ----- llvm/test/MC/WebAssembly/unnamed-data.ll | 5 ----- llvm/test/MC/WebAssembly/visibility.ll | 5 ----- 10 files changed, 1 insertion(+), 47 deletions(-) diff --git a/llvm/test/MC/WebAssembly/array-fill.ll b/llvm/test/MC/WebAssembly/array-fill.ll index 0ef4754fc89d6..487da325e181f 100644 --- a/llvm/test/MC/WebAssembly/array-fill.ll +++ b/llvm/test/MC/WebAssembly/array-fill.ll @@ -23,9 +23,4 @@ target triple = "wasm32-unknown-unknown" ; CHECK-NEXT: Name: .data ; CHECK-NEXT: Alignment: 0 ; CHECK-NEXT: Flags: [ ] -; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: target_features -; CHECK-NEXT: Features: -; CHECK-NEXT: - Prefix: DISALLOWED -; CHECK-NEXT: Name: component-model-thread-context ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/assembler-binary.ll b/llvm/test/MC/WebAssembly/assembler-binary.ll index 7981b01354120..994235ccafec7 100644 --- a/llvm/test/MC/WebAssembly/assembler-binary.ll +++ b/llvm/test/MC/WebAssembly/assembler-binary.ll @@ -78,9 +78,4 @@ entry: ; CHECK-NEXT: Name: bar ; CHECK-NEXT: Flags: [ UNDEFINED ] ; CHECK-NEXT: Function: 0 -; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: target_features -; CHECK-NEXT: Features: -; CHECK-NEXT: - Prefix: DISALLOWED -; CHECK-NEXT: Name: component-model-thread-context ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/bss.ll b/llvm/test/MC/WebAssembly/bss.ll index c0b15fc85d389..a704f70357521 100644 --- a/llvm/test/MC/WebAssembly/bss.ll +++ b/llvm/test/MC/WebAssembly/bss.ll @@ -78,9 +78,4 @@ target triple = "wasm32-unknown-unknown" ; CHECK-NEXT: Name: .bss.bar ; CHECK-NEXT: Alignment: 0 ; CHECK-NEXT: Flags: [ ] -; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: target_features -; CHECK-NEXT: Features: -; CHECK-NEXT: - Prefix: DISALLOWED -; CHECK-NEXT: Name: component-model-thread-context ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/comdat.ll b/llvm/test/MC/WebAssembly/comdat.ll index 2d68bf9baf81b..1b2644dee46ff 100644 --- a/llvm/test/MC/WebAssembly/comdat.ll +++ b/llvm/test/MC/WebAssembly/comdat.ll @@ -119,11 +119,6 @@ define linkonce_odr i32 @sharedFn() #1 comdat($sharedComdat) { ; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Kind: DATA ; CHECK-NEXT: Index: 0 -; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: target_features -; CHECK-NEXT: Features: -; CHECK-NEXT: - Prefix: DISALLOWED -; CHECK-NEXT: Name: component-model-thread-context ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/debug-info.ll b/llvm/test/MC/WebAssembly/debug-info.ll index a9b8ee71ad352..a65ce0ee83920 100644 --- a/llvm/test/MC/WebAssembly/debug-info.ll +++ b/llvm/test/MC/WebAssembly/debug-info.ll @@ -141,12 +141,6 @@ ; CHECK-NEXT: Offset: 1164 ; CHECK-NEXT: Name: producers ; CHECK-NEXT: } -; CHECK-NEXT: Section { -; CHECK-NEXT: Type: CUSTOM (0x0) -; CHECK-NEXT: Size: 33 -; CHECK-NEXT: Offset: 1257 -; CHECK-NEXT: Name: target_features -; CHECK-NEXT: } ; CHECK-NEXT:] ; CHECK-NEXT:Relocations [ ; CHECK-NEXT: Section (7) DATA { diff --git a/llvm/test/MC/WebAssembly/debug-info64.ll b/llvm/test/MC/WebAssembly/debug-info64.ll index 9ed067f571cbc..d0081164d73ee 100644 --- a/llvm/test/MC/WebAssembly/debug-info64.ll +++ b/llvm/test/MC/WebAssembly/debug-info64.ll @@ -143,7 +143,7 @@ ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) -; CHECK-NEXT: Size: 43 +; CHECK-NEXT: Size: 11 ; CHECK-NEXT: Offset: 1317 ; CHECK-NEXT: Name: target_features ; CHECK-NEXT: } diff --git a/llvm/test/MC/WebAssembly/explicit-sections.ll b/llvm/test/MC/WebAssembly/explicit-sections.ll index 8ca3b434b7997..a65172b22d467 100644 --- a/llvm/test/MC/WebAssembly/explicit-sections.ll +++ b/llvm/test/MC/WebAssembly/explicit-sections.ll @@ -70,9 +70,4 @@ target triple = "wasm32-unknown-unknown" ; CHECK-NEXT: Name: .sec2 ; CHECK-NEXT: Alignment: 3 ; CHECK-NEXT: Flags: [ ] -; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: target_features -; CHECK-NEXT: Features: -; CHECK-NEXT: - Prefix: DISALLOWED -; CHECK-NEXT: Name: component-model-thread-context ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll index a8300e865997d..f1ec71da1ebb6 100644 --- a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll +++ b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll @@ -184,9 +184,4 @@ declare void @func3() ; CHECK-NEXT: Symbol: 10 ; CHECK-NEXT: - Priority: 65535 ; CHECK-NEXT: Symbol: 7 -; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: target_features -; CHECK-NEXT: Features: -; CHECK-NEXT: - Prefix: DISALLOWED -; CHECK-NEXT: Name: component-model-thread-context ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/unnamed-data.ll b/llvm/test/MC/WebAssembly/unnamed-data.ll index c476e95f02d3a..0887622277bb3 100644 --- a/llvm/test/MC/WebAssembly/unnamed-data.ll +++ b/llvm/test/MC/WebAssembly/unnamed-data.ll @@ -87,9 +87,4 @@ target triple = "wasm32-unknown-unknown" ; CHECK-NEXT: Name: .data.b ; CHECK-NEXT: Alignment: 3 ; CHECK-NEXT: Flags: [ ] -; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: target_features -; CHECK-NEXT: Features: -; CHECK-NEXT: - Prefix: DISALLOWED -; CHECK-NEXT: Name: component-model-thread-context ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/visibility.ll b/llvm/test/MC/WebAssembly/visibility.ll index 9e5d97cd128a5..69b273ecbf25e 100644 --- a/llvm/test/MC/WebAssembly/visibility.ll +++ b/llvm/test/MC/WebAssembly/visibility.ll @@ -25,9 +25,4 @@ entry: ; CHECK-NEXT: Name: hiddenVis ; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] ; CHECK-NEXT: Function: 1 -; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: target_features -; CHECK-NEXT: Features: -; CHECK-NEXT: - Prefix: DISALLOWED -; CHECK-NEXT: Name: component-model-thread-context ; CHECK-NEXT: ... From 9908d720ed4be424ffa03d2f5b1413c710b4f1e9 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 9 Mar 2026 13:14:31 +0000 Subject: [PATCH 090/134] Remove merge artifact --- clang/test/Preprocessor/wasm-target-features.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/clang/test/Preprocessor/wasm-target-features.c b/clang/test/Preprocessor/wasm-target-features.c index 74cfe89fa99f6..2134f83f743d6 100644 --- a/clang/test/Preprocessor/wasm-target-features.c +++ b/clang/test/Preprocessor/wasm-target-features.c @@ -240,15 +240,6 @@ // // BLEEDING-EDGE-NO-SIMD128-NOT: #define __wasm_simd128__ 1{{$}} -// RUN: %clang -E -dM %s -o - 2>&1 \ -// RUN: -target wasm32-unknown-unknown -mwide-arithmetic \ -// RUN: | FileCheck %s -check-prefix=WIDE-ARITHMETIC -// RUN: %clang -E -dM %s -o - 2>&1 \ -// RUN: -target wasm64-unknown-unknown -mwide-arithmetic \ -// RUN: | FileCheck %s -check-prefix=WIDE-ARITHMETIC -// -// WIDE-ARITHMETIC: #define __wasm_wide_arithmetic__ 1{{$}} - // RUN: %clang -E -dM %s -o - 2>&1 \ // RUN: -target wasm32-unknown-unknown -mcomponent-model-thread-context \ // RUN: | FileCheck %s -check-prefix=COMPONENT-MODEL-THREAD-CONTEXT From 0e1a5a994d164780d633f07a4100ab72b6e0b7d1 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 9 Mar 2026 19:16:46 +0000 Subject: [PATCH 091/134] Move writer utils --- lld/wasm/SyntheticSections.cpp | 9 +++++++++ lld/wasm/Writer.cpp | 9 +++++++++ lld/wasm/WriterUtils.cpp | 21 --------------------- lld/wasm/WriterUtils.h | 5 ----- 4 files changed, 18 insertions(+), 26 deletions(-) diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index e00f769a21ce7..44ecd7185017b 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -52,6 +52,15 @@ class SubSection { raw_string_ostream os{body}; }; +void writeGetTLSBase(const Ctx &ctx, raw_ostream &os) { + if (ctx.componentModelThreadContext) { + 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"); + } +} } // namespace bool DylinkSection::isNeeded() const { diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 110216a62096d..378e36a006920 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -123,6 +123,15 @@ class Writer { llvm::SmallDenseMap segmentMap; }; +void writeSetTLSBase(const Ctx &ctx, raw_ostream &os) { + if (ctx.componentModelThreadContext) { + 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"); + } +} } // anonymous namespace void Writer::calculateCustomSections() { diff --git a/lld/wasm/WriterUtils.cpp b/lld/wasm/WriterUtils.cpp index 11b58a10f98c2..9a74783bef0b2 100644 --- a/lld/wasm/WriterUtils.cpp +++ b/lld/wasm/WriterUtils.cpp @@ -271,26 +271,5 @@ void writeExport(raw_ostream &os, const WasmExport &export_) { fatal("unsupported export type: " + Twine(export_.Kind)); } } - -void writeGetTLSBase(const Ctx &ctx, raw_ostream &os) { - if (ctx.componentModelThreadContext) { - 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.componentModelThreadContext) { - 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 cbac8d441d2b6..cabe1184b4667 100644 --- a/lld/wasm/WriterUtils.h +++ b/lld/wasm/WriterUtils.h @@ -65,11 +65,6 @@ void writeImport(raw_ostream &os, const llvm::wasm::WasmImport &import); void writeCompactImport(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); From e187d8ebd0bbbff468cbe8bbb65185941be71d01 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 9 Mar 2026 19:17:42 +0000 Subject: [PATCH 092/134] Revert WriterUtils changes --- lld/wasm/WriterUtils.cpp | 3 +-- lld/wasm/WriterUtils.h | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lld/wasm/WriterUtils.cpp b/lld/wasm/WriterUtils.cpp index 9a74783bef0b2..fee25a7255793 100644 --- a/lld/wasm/WriterUtils.cpp +++ b/lld/wasm/WriterUtils.cpp @@ -7,8 +7,6 @@ //===----------------------------------------------------------------------===// #include "WriterUtils.h" -#include "Config.h" -#include "Symbols.h" #include "lld/Common/ErrorHandler.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Debug.h" @@ -271,5 +269,6 @@ void writeExport(raw_ostream &os, const WasmExport &export_) { fatal("unsupported export type: " + Twine(export_.Kind)); } } + } // namespace wasm } // namespace lld diff --git a/lld/wasm/WriterUtils.h b/lld/wasm/WriterUtils.h index cabe1184b4667..061199b168080 100644 --- a/lld/wasm/WriterUtils.h +++ b/lld/wasm/WriterUtils.h @@ -65,6 +65,7 @@ void writeImport(raw_ostream &os, const llvm::wasm::WasmImport &import); void writeCompactImport(raw_ostream &os, const llvm::wasm::WasmImport &import); void writeExport(raw_ostream &os, const llvm::wasm::WasmExport &export_); + } // namespace wasm std::string toString(llvm::wasm::ValType type); From 1ee14c445dd205d086db2860243c8397407c96e2 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 23 Mar 2026 15:08:01 +0000 Subject: [PATCH 093/134] Abstract out context.get/set builtins --- compiler-rt/lib/builtins/CMakeLists.txt | 1 + .../lib/builtins/wasm/thread_context.c | 61 +++++++++++++++++++ lld/test/wasm/tls-component-model.s | 8 +-- lld/wasm/Config.h | 8 +-- lld/wasm/Driver.cpp | 18 +++--- lld/wasm/SyntheticSections.cpp | 2 +- lld/wasm/Writer.cpp | 2 +- .../WebAssembly/WebAssemblyAsmPrinter.cpp | 25 +++----- .../WebAssembly/WebAssemblyFrameLowering.cpp | 4 +- .../WebAssembly/WebAssemblyUtilities.cpp | 2 +- .../Target/WebAssembly/WebAssemblyUtilities.h | 2 +- llvm/test/CodeGen/WebAssembly/stack-abi.ll | 8 +-- .../CodeGen/WebAssembly/thread_pointer.ll | 2 +- .../CodeGen/WebAssembly/tls-local-exec.ll | 10 +-- 14 files changed, 100 insertions(+), 53 deletions(-) create mode 100644 compiler-rt/lib/builtins/wasm/thread_context.c diff --git a/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt index 08d000fc35106..2c89bffe1bcaa 100644 --- a/compiler-rt/lib/builtins/CMakeLists.txt +++ b/compiler-rt/lib/builtins/CMakeLists.txt @@ -890,6 +890,7 @@ set(s390x_SOURCES set(wasm_SOURCES + wasm/thread_context.c ${GENERIC_TF_SOURCES} ${GENERIC_SOURCES} ) diff --git a/compiler-rt/lib/builtins/wasm/thread_context.c b/compiler-rt/lib/builtins/wasm/thread_context.c new file mode 100644 index 0000000000000..747c06c2c1764 --- /dev/null +++ b/compiler-rt/lib/builtins/wasm/thread_context.c @@ -0,0 +1,61 @@ +//===-- thread_context.c - Provide access to stack pointer and TLS base ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __wasm_get_{stack_pointer,tls_base} and +// __wasm_set_{stack_pointer,tls_base}, which are used for accessing the +// component model thread context. +// +//===----------------------------------------------------------------------===// + +#ifdef __wasm_component_model_thread_context__ + +// We define these function as naked functions with inline assembly because: +// 1. Defining them as regular C functions would cause infinite recursion in +// the prologue/epilogue code that accesses the stack pointer. +// 2. The compiler-rt build system doesn't pass the target triple when compiling +// assembly files, and making it do so would require a non-trivial amount of +// build system changes. + +__attribute__((naked)) void *__wasm_get_stack_pointer(void) { + __asm__ volatile( + ".functype __wasm_component_model_builtin_context_get_0 () -> (i32)\n" + ".import_module __wasm_component_model_builtin_context_get_0, \"$root\"\n" + ".import_name __wasm_component_model_builtin_context_get_0, " + "\"[context-get-0]\"\n" + "call __wasm_component_model_builtin_context_get_0"); +} + +__attribute__((naked)) void __wasm_set_stack_pointer(void *ptr) { + __asm__ volatile( + ".functype __wasm_component_model_builtin_context_set_0 (i32) -> ()\n" + ".import_module __wasm_component_model_builtin_context_set_0, \"$root\"\n" + ".import_name __wasm_component_model_builtin_context_set_0, " + "\"[context-set-0]\"\n" + "local.get 0\n" + "call __wasm_component_model_builtin_context_set_0"); +} + +__attribute__((naked)) void *__wasm_get_tls_base(void) { + __asm__ volatile( + ".functype __wasm_component_model_builtin_context_get_1 () -> (i32)\n" + ".import_module __wasm_component_model_builtin_context_get_1, \"$root\"\n" + ".import_name __wasm_component_model_builtin_context_get_1, " + "\"[context-get-1]\"\n" + "call __wasm_component_model_builtin_context_get_1"); +} +__attribute__((naked)) void __wasm_set_tls_base(void *ptr) { + __asm__ volatile( + ".functype __wasm_component_model_builtin_context_set_1 (i32) -> ()\n" + ".import_module __wasm_component_model_builtin_context_set_1, \"$root\"\n" + ".import_name __wasm_component_model_builtin_context_set_1, " + "\"[context-set-1]\"\n" + "local.get 0\n" + "call __wasm_component_model_builtin_context_set_1"); +} + +#endif \ No newline at end of file diff --git a/lld/test/wasm/tls-component-model.s b/lld/test/wasm/tls-component-model.s index 6c0ab4ad79921..49b66263f57a5 100644 --- a/lld/test/wasm/tls-component-model.s +++ b/lld/test/wasm/tls-component-model.s @@ -3,18 +3,16 @@ # RUN: obj2yaml %t.wasm | FileCheck %s # RUN: llvm-objdump -d --no-print-imm-hex --no-show-raw-insn %t.wasm | FileCheck %s --check-prefix=DIS -.functype __wasm_component_model_builtin_context_get_1 () -> (i32) -.import_module __wasm_component_model_builtin_context_get_1, "$root" -.import_name __wasm_component_model_builtin_context_get_1, "[context-get-1]" +.functype __wasm_get_tls_base () -> (i32) .globl _start _start: .functype _start () -> (i32) - call __wasm_component_model_builtin_context_get_1 + call __wasm_get_tls_base i32.const tls1@TLSREL i32.add i32.load 0 - call __wasm_component_model_builtin_context_get_1 + call __wasm_get_tls_base i32.const tls2@TLSREL i32.add i32.load 0 diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h index ac8734d9c0e7f..87f7fd281ee77 100644 --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -254,13 +254,13 @@ struct Ctx { // is used as a function pointer being allocated a slot. TableSymbol *indirectFunctionTable; - // __wasm_component_model_builtin_context_set_1 + // __wasm_set_tls_base // Function used to set TLS base in component model modules. - UndefinedFunction *contextSet1; + UndefinedFunction *setTLSBase; - // __wasm_component_model_builtin_context_get_1 + // __wasm_get_tls_base // Function used to get TLS base in component model modules. - UndefinedFunction *contextGet1; + UndefinedFunction *getTLSBase; }; WasmSym sym; diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 6687733bd8b77..5ef7465e069a1 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -1010,16 +1010,14 @@ static void createPostLTOSymbols() { 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(); + static WasmSignature setTLSBaseSignature{{}, {ValType::I32}}; + ctx.sym.setTLSBase = + createUndefinedFunction("__wasm_set_tls_base", std::nullopt, + std::nullopt, &setTLSBaseSignature); + static WasmSignature getTLSBaseSignature{{ValType::I32}, {}}; + ctx.sym.getTLSBase = + createUndefinedFunction("__wasm_get_tls_base", std::nullopt, + std::nullopt, &getTLSBaseSignature); } } } diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index 44ecd7185017b..456fc2d8f7078 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -55,7 +55,7 @@ class SubSection { void writeGetTLSBase(const Ctx &ctx, raw_ostream &os) { if (ctx.componentModelThreadContext) { writeU8(os, WASM_OPCODE_CALL, "call"); - writeUleb128(os, ctx.sym.contextGet1->getFunctionIndex(), "function index"); + writeUleb128(os, ctx.sym.getTLSBase->getFunctionIndex(), "function index"); } else { writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_SET"); writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "__tls_base"); diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 378e36a006920..6c04b4eaf5bd8 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -126,7 +126,7 @@ class Writer { void writeSetTLSBase(const Ctx &ctx, raw_ostream &os) { if (ctx.componentModelThreadContext) { writeU8(os, WASM_OPCODE_CALL, "call"); - writeUleb128(os, ctx.sym.contextSet1->getFunctionIndex(), "function index"); + writeUleb128(os, ctx.sym.setTLSBase->getFunctionIndex(), "function index"); } else { writeU8(os, WASM_OPCODE_GLOBAL_SET, "GLOBAL_SET"); writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "__tls_base"); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index e7062730bd520..eaef95a5ef86b 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -266,25 +266,13 @@ 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") { + } else if (Name == "__wasm_get_stack_pointer" || + Name == "__wasm_get_tls_base") { 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") { + } else if (Name == "__wasm_set_stack_pointer" || + Name == "__wasm_set_tls_base") { 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); @@ -498,7 +486,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)); @@ -607,7 +595,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 77489f6f8e517..8a5c961115c52 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -241,7 +241,7 @@ void WebAssemblyFrameLowering::writeBackSP( if (MF.getSubtarget() .hasComponentModelThreadContext()) { - const char *ES = "__wasm_component_model_builtin_context_set_0"; + const char *ES = "__wasm_set_stack_pointer"; auto *SPSymbol = MF.createExternalSymbolName(ES); BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::CALL)) .addExternalSymbol(SPSymbol) @@ -300,7 +300,7 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, SPReg = MRI.createVirtualRegister(PtrRC); if (ST.hasComponentModelThreadContext()) { - const char *ES = "__wasm_component_model_builtin_context_get_0"; + const char *ES = "__wasm_get_stack_pointer"; auto *SPSymbol = MF.createExternalSymbolName(ES); BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CALL), SPReg) .addExternalSymbol(SPSymbol); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index 4d5b5cb64625f..433e5ce987e4c 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -204,7 +204,7 @@ MachineSDNode *WebAssembly::getTLSBase(SelectionDAG &DAG, const SDLoc &DL, const char *SymName; if (Subtarget->hasComponentModelThreadContext()) { Opcode = WebAssembly::CALL; - SymName = "__wasm_component_model_builtin_context_get_1"; + SymName = "__wasm_get_tls_base"; } else { Opcode = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 : WebAssembly::GLOBAL_GET_I32; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h index 9ed46fdb9f793..9bb0fb4cc35d3 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h @@ -79,7 +79,7 @@ bool canLowerReturn(size_t ResultSize, const WebAssemblySubtarget *Subtarget); // Get the TLS base value for the current target // If using component model threading intrinsics: calls -// __wasm_component_model_builtin_context_get_1 Otherwise: global.get __tls_base +// __wasm_get_tls_base, otherwise: global.get __tls_base MachineSDNode *getTLSBase(SelectionDAG &DAG, const SDLoc &DL, const WebAssemblySubtarget *Subtarget, const SDValue Chain = SDValue()); diff --git a/llvm/test/CodeGen/WebAssembly/stack-abi.ll b/llvm/test/CodeGen/WebAssembly/stack-abi.ll index 4f434082c85b2..6b69cec44f022 100644 --- a/llvm/test/CodeGen/WebAssembly/stack-abi.ll +++ b/llvm/test/CodeGen/WebAssembly/stack-abi.ll @@ -11,14 +11,14 @@ define void @use_stack() #0 { } ; CMTC-LABEL: use_stack: -; CMTC: call __wasm_component_model_builtin_context_get_0 -; CMTC: call __wasm_component_model_builtin_context_set_0 +; CMTC: call __wasm_get_stack_pointer +; CMTC: call __wasm_set_stack_pointer ; CMTC-NOT: global.get __stack_pointer ; CMTC-NOT: global.set __stack_pointer ; GLOBAL-LABEL: use_stack: ; GLOBAL: global.get __stack_pointer ; GLOBAL: global.set __stack_pointer -; GLOBAL-NOT: call __wasm_component_model_builtin_context_get_0 -; GLOBAL-NOT: call __wasm_component_model_builtin_context_set_0 +; GLOBAL-NOT: call __wasm_get_stack_pointer +; GLOBAL-NOT: call __wasm_set_stack_pointer diff --git a/llvm/test/CodeGen/WebAssembly/thread_pointer.ll b/llvm/test/CodeGen/WebAssembly/thread_pointer.ll index 7655859c2938a..38f9ec2543c89 100644 --- a/llvm/test/CodeGen/WebAssembly/thread_pointer.ll +++ b/llvm/test/CodeGen/WebAssembly/thread_pointer.ll @@ -21,7 +21,7 @@ define ptr @thread_pointer() nounwind { ; WASM32-CMTC-LABEL: thread_pointer: ; WASM32-CMTC: .functype thread_pointer () -> (i32) ; WASM32-CMTC-NEXT: # %bb.0: -; WASM32-CMTC-NEXT: call __wasm_component_model_builtin_context_get_1 +; WASM32-CMTC-NEXT: call __wasm_get_tls_base ; WASM32-CMTC-NEXT: # fallthrough-return ; %1 = tail call ptr @llvm.thread.pointer() diff --git a/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll b/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll index 4e2a7fd79e9c7..abe0afe806651 100644 --- a/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll +++ b/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll @@ -21,7 +21,7 @@ define i32 @address_of_tls() { ; TLS-NEXT: i32.add ; TLS-NEXT: return - ; TLS-CMTC-DAG: call __wasm_component_model_builtin_context_get_1 + ; TLS-CMTC-DAG: call __wasm_get_tls_base ; TLS-CMTC-DAG: i32.const tls@TLSREL ; TLS-CMTC-NEXT: i32.add ; TLS-CMTC-NEXT: return @@ -41,7 +41,7 @@ define i32 @address_of_tls_external() { ; TLS-NEXT: i32.add ; TLS-NEXT: return - ; TLS-CMTC-DAG: call __wasm_component_model_builtin_context_get_1 + ; TLS-CMTC-DAG: call __wasm_get_tls_base ; TLS-CMTC-DAG: i32.const tls_external@TLSREL ; TLS-CMTC-NEXT: i32.add ; TLS-CMTC-NEXT: return @@ -61,7 +61,7 @@ define ptr @ptr_to_tls() { ; TLS-NEXT: i32.add ; TLS-NEXT: return - ; TLS-CMTC-DAG: call __wasm_component_model_builtin_context_get_1 + ; TLS-CMTC-DAG: call __wasm_get_tls_base ; TLS-CMTC-DAG: i32.const tls@TLSREL ; TLS-CMTC-NEXT: i32.add ; TLS-CMTC-NEXT: return @@ -81,7 +81,7 @@ define i32 @tls_load() { ; TLS-NEXT: i32.load 0 ; TLS-NEXT: return - ; TLS-CMTC-DAG: call __wasm_component_model_builtin_context_get_1 + ; TLS-CMTC-DAG: call __wasm_get_tls_base ; TLS-CMTC-DAG: i32.const tls@TLSREL ; TLS-CMTC-NEXT: i32.add ; TLS-CMTC-NEXT: i32.load 0 @@ -104,7 +104,7 @@ define void @tls_store(i32 %x) { ; TLS-NEXT: i32.store 0 ; TLS-NEXT: return - ; TLS-CMTC-DAG: call __wasm_component_model_builtin_context_get_1 + ; TLS-CMTC-DAG: call __wasm_get_tls_base ; TLS-CMTC-DAG: i32.const tls@TLSREL ; TLS-CMTC-NEXT: i32.add ; TLS-CMTC-NEXT: i32.store 0 From af1eb70a6f5878ef6f223a5ddc36ab044b27e5fe Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 23 Mar 2026 15:16:16 +0000 Subject: [PATCH 094/134] fmt --- llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index eaef95a5ef86b..feb44dfb1dac2 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -486,7 +486,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)); @@ -595,8 +595,7 @@ 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); From c661e667ed9ace6d93079b0a550137c6c7b71bf3 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 23 Mar 2026 16:46:34 +0000 Subject: [PATCH 095/134] fmt --- compiler-rt/lib/builtins/wasm/thread_context.c | 2 +- llvm/test/MC/WebAssembly/array-fill.ll | 2 +- llvm/test/MC/WebAssembly/assembler-binary.ll | 2 +- llvm/test/MC/WebAssembly/bss.ll | 2 +- llvm/test/MC/WebAssembly/comdat.ll | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler-rt/lib/builtins/wasm/thread_context.c b/compiler-rt/lib/builtins/wasm/thread_context.c index 747c06c2c1764..de64bb3035777 100644 --- a/compiler-rt/lib/builtins/wasm/thread_context.c +++ b/compiler-rt/lib/builtins/wasm/thread_context.c @@ -58,4 +58,4 @@ __attribute__((naked)) void __wasm_set_tls_base(void *ptr) { "call __wasm_component_model_builtin_context_set_1"); } -#endif \ No newline at end of file +#endif diff --git a/llvm/test/MC/WebAssembly/array-fill.ll b/llvm/test/MC/WebAssembly/array-fill.ll index 487da325e181f..4725d4eda065b 100644 --- a/llvm/test/MC/WebAssembly/array-fill.ll +++ b/llvm/test/MC/WebAssembly/array-fill.ll @@ -23,4 +23,4 @@ target triple = "wasm32-unknown-unknown" ; CHECK-NEXT: Name: .data ; CHECK-NEXT: Alignment: 0 ; CHECK-NEXT: Flags: [ ] -; CHECK-NEXT: ... +; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/assembler-binary.ll b/llvm/test/MC/WebAssembly/assembler-binary.ll index 994235ccafec7..32f7d679b8968 100644 --- a/llvm/test/MC/WebAssembly/assembler-binary.ll +++ b/llvm/test/MC/WebAssembly/assembler-binary.ll @@ -78,4 +78,4 @@ entry: ; CHECK-NEXT: Name: bar ; CHECK-NEXT: Flags: [ UNDEFINED ] ; CHECK-NEXT: Function: 0 -; CHECK-NEXT: ... +; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/bss.ll b/llvm/test/MC/WebAssembly/bss.ll index a704f70357521..4f0c7c8525562 100644 --- a/llvm/test/MC/WebAssembly/bss.ll +++ b/llvm/test/MC/WebAssembly/bss.ll @@ -78,4 +78,4 @@ target triple = "wasm32-unknown-unknown" ; CHECK-NEXT: Name: .bss.bar ; CHECK-NEXT: Alignment: 0 ; CHECK-NEXT: Flags: [ ] -; CHECK-NEXT: ... +; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/comdat.ll b/llvm/test/MC/WebAssembly/comdat.ll index 1b2644dee46ff..0886301597471 100644 --- a/llvm/test/MC/WebAssembly/comdat.ll +++ b/llvm/test/MC/WebAssembly/comdat.ll @@ -119,7 +119,7 @@ define linkonce_odr i32 @sharedFn() #1 comdat($sharedComdat) { ; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Kind: DATA ; CHECK-NEXT: Index: 0 -; CHECK-NEXT: ... +; CHECK-NEXT: ... ; ASM: .section .text.basicInlineFn,"G",@,basicInlineFn,comdat From 742ae7cd1d119d45308c54ef3985d73a0b1b6141 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 24 Mar 2026 08:18:01 +0000 Subject: [PATCH 096/134] Add comment --- lld/wasm/Config.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h index 87f7fd281ee77..002ac6e882804 100644 --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -286,6 +286,9 @@ struct Ctx { Ctx(); void reset(); + + // This will be true for both shared-memory multi-threading and green threads + // support via externally-controlled stack pointer/TLS base. bool isMultithreaded() const { return componentModelThreadContext || arg.sharedMemory; } From 9b688ca372e548c050fd025ff1afe82af381ec29 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 24 Mar 2026 08:45:48 +0000 Subject: [PATCH 097/134] Remove option --- lld/wasm/Options.td | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td index 4b6d800854a08..33ecf03176d36 100644 --- a/lld/wasm/Options.td +++ b/lld/wasm/Options.td @@ -190,12 +190,6 @@ def allow_undefined_file: J<"allow-undefined-file=">, def allow_undefined_file_s: Separate<["-"], "allow-undefined-file">, Alias; -def component_model_thread_context - : FF<"component-model-thread-context">, - HelpText< - "Use component model thread context intrinsics instead of global " - "variables for the stack pointer and thread local storage">; - defm export: Eq<"export", "Force a symbol to be exported">; defm export_if_defined: Eq<"export-if-defined", From 35707779822ca84d552b465d6d31e697b163cae0 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 24 Mar 2026 10:35:29 +0000 Subject: [PATCH 098/134] Refactor into two config options --- clang/include/clang/Options/Options.td | 4 +- clang/lib/Basic/Targets/WebAssembly.cpp | 16 ++++---- clang/lib/Basic/Targets/WebAssembly.h | 2 +- clang/lib/Driver/ToolChains/WebAssembly.cpp | 14 +++---- clang/test/Driver/wasm-features.c | 8 ++-- clang/test/Driver/wasm-toolchain.c | 10 ++--- .../test/Preprocessor/wasm-target-features.c | 6 +-- .../lib/builtins/wasm/thread_context.c | 2 +- lld/test/wasm/stack-pointer-abi.s | 6 +-- lld/test/wasm/thread-context-abi-mismatch.s | 10 ++--- lld/test/wasm/tls-component-model.s | 2 +- lld/wasm/Config.h | 20 +++++++--- lld/wasm/Driver.cpp | 39 ++++++++++--------- lld/wasm/SyntheticSections.cpp | 2 +- lld/wasm/Writer.cpp | 16 ++++---- llvm/lib/Target/WebAssembly/WebAssembly.td | 4 +- .../WebAssembly/WebAssemblyFrameLowering.cpp | 6 +-- .../WebAssembly/WebAssemblyInstrInfo.td | 8 ++-- .../WebAssembly/WebAssemblySubtarget.cpp | 8 ++-- .../Target/WebAssembly/WebAssemblySubtarget.h | 6 +-- .../WebAssembly/WebAssemblyTargetMachine.cpp | 8 ++-- .../WebAssembly/WebAssemblyUtilities.cpp | 2 +- llvm/test/CodeGen/WebAssembly/stack-abi.ll | 4 +- .../WebAssembly/target-features-attrs.ll | 4 +- .../WebAssembly/target-features-cpus.ll | 12 +++--- .../target-features-thread-context.ll | 12 +++--- .../WebAssembly/target-features-tls.ll | 12 +++--- .../CodeGen/WebAssembly/thread_pointer.ll | 2 +- .../CodeGen/WebAssembly/tls-local-exec.ll | 6 +-- 29 files changed, 130 insertions(+), 121 deletions(-) diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 3ce19912f7430..6d918d957b3ac 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -5709,8 +5709,8 @@ def mcall_indirect_overlong : Flag<["-"], "mcall-indirect-overlong">, Group, Group; def mcompact_imports : Flag<["-"], "mcompact-imports">, Group; def mno_compact_imports : Flag<["-"], "mno-compact-imports">, Group; -def mcomponent_model_thread_context : Flag<["-"], "mcomponent-model-thread-context">, Group; -def mno_component_model_thread_context : Flag<["-"], "mno-component-model-thread-context">, Group; +def mcomponent_model_threading : Flag<["-"], "mcomponent-model-threading">, Group; +def mno_component_model_threading : Flag<["-"], "mno-component-model-threading">, Group; def mexception_handing : Flag<["-"], "mexception-handling">, Group; def mno_exception_handing : Flag<["-"], "mno-exception-handling">, Group; def mextended_const : Flag<["-"], "mextended-const">, Group; diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp index 8af3ae7fa0f25..2c5f42e66bb67 100644 --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -56,7 +56,7 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const { .Case("bulk-memory", HasBulkMemory) .Case("bulk-memory-opt", HasBulkMemoryOpt) .Case("call-indirect-overlong", HasCallIndirectOverlong) - .Case("component-model-thread-context", HasComponentModelThreadContext) + .Case("component-model-threading", HasComponentModelThreading) .Case("compact-imports", HasCompactImports) .Case("exception-handling", HasExceptionHandling) .Case("extended-const", HasExtendedConst) @@ -124,8 +124,8 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__wasm_tail_call__"); if (HasWideArithmetic) Builder.defineMacro("__wasm_wide_arithmetic__"); - if (HasComponentModelThreadContext) - Builder.defineMacro("__wasm_component_model_thread_context__"); + if (HasComponentModelThreading) + Builder.defineMacro("__wasm_component_model_threading__"); // Note that not all wasm features appear here. For example, // HasCompatctImports @@ -389,12 +389,12 @@ bool WebAssemblyTargetInfo::handleTargetFeatures( HasWideArithmetic = false; continue; } - if (Feature == "+component-model-thread-context") { - HasComponentModelThreadContext = true; + if (Feature == "+component-model-threading") { + HasComponentModelThreading = true; continue; } - if (Feature == "-component-model-thread-context") { - HasComponentModelThreadContext = false; + if (Feature == "-component-model-threading") { + HasComponentModelThreading = false; continue; } @@ -434,7 +434,7 @@ void WebAssemblyTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts, // and ThreadModel so that we don't predefine _REENTRANT or __STDCPP_THREADS__ // if we will eventually end up stripping atomics because they are // unsupported. - if (!HasComponentModelThreadContext && (!HasAtomics || !HasBulkMemory)) { + if (!HasComponentModelThreading && (!HasAtomics || !HasBulkMemory)) { Opts.POSIXThreads = false; Opts.setThreadModel(LangOptions::ThreadModelKind::Single); Opts.ThreadsafeStatics = false; diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h index bd043067ba64a..2479f6ac3a090 100644 --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -63,7 +63,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo { bool HasBulkMemoryOpt = false; bool HasCallIndirectOverlong = false; bool HasCompactImports = false; - bool HasComponentModelThreadContext = false; + bool HasComponentModelThreading = false; bool HasExceptionHandling = false; bool HasExtendedConst = false; bool HasFP16 = false; diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 659d88e6a5e5e..df970aab06418 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -88,19 +88,19 @@ static bool WantsPthread(const llvm::Triple &Triple, const ArgList &Args) { return WantsPthread; } -static bool WantsComponentModelThreadContext(const llvm::Triple &Triple, +static bool WantsComponentModelThreading(const llvm::Triple &Triple, const ArgList &Args) { // If the target is WASIP3, then enable the - // component-model-thread-context feature by default, unless explicitly + // component-model-threading feature by default, unless explicitly // disabled. return Triple.getOS() == llvm::Triple::WASIp3 && - Args.hasFlag(options::OPT_mcomponent_model_thread_context, - options::OPT_mno_component_model_thread_context, true); + Args.hasFlag(options::OPT_mcomponent_model_threading, + options::OPT_mno_component_model_threading, true); } static bool WantsSharedMemory(const llvm::Triple &Triple, const ArgList &Args) { return WantsPthread(Triple, Args) && - !WantsComponentModelThreadContext(Triple, Args); + !WantsComponentModelThreading(Triple, Args); } void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -336,9 +336,9 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, options::OPT_fno_use_init_array, true)) CC1Args.push_back("-fno-use-init-array"); - if (WantsComponentModelThreadContext(getTriple(), DriverArgs)) { + if (WantsComponentModelThreading(getTriple(), DriverArgs)) { CC1Args.push_back("-target-feature"); - CC1Args.push_back("+component-model-thread-context"); + CC1Args.push_back("+component-model-threading"); } // '-pthread' implies bulk-memory, and, if shared memory is also used, diff --git a/clang/test/Driver/wasm-features.c b/clang/test/Driver/wasm-features.c index c75f66aa1e1b3..634eff9a1511c 100644 --- a/clang/test/Driver/wasm-features.c +++ b/clang/test/Driver/wasm-features.c @@ -119,9 +119,9 @@ // COMPACT-IMPORTS: "-target-feature" "+compact-imports" // NO-COMPACT-IMPORTS: "-target-feature" "-compact-imports" -// RUN: %clang --target=wasm32-unknown-unknown -### %s -mcomponent-model-thread-context 2>&1 | FileCheck %s -check-prefix=COMPONENT-MODEL-THREAD-CONTEXT -// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-component-model-thread-context 2>&1 | FileCheck %s -check-prefix=NO-COMPONENT-MODEL-THREAD-CONTEXT +// RUN: %clang --target=wasm32-unknown-unknown -### %s -mcomponent-model-threading 2>&1 | FileCheck %s -check-prefix=COMPONENT-MODEL-THREAD-CONTEXT +// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-component-model-threading 2>&1 | FileCheck %s -check-prefix=NO-COMPONENT-MODEL-THREAD-CONTEXT -// COMPONENT-MODEL-THREAD-CONTEXT: "-target-feature" "+component-model-thread-context" -// NO-COMPONENT-MODEL-THREAD-CONTEXT: "-target-feature" "-component-model-thread-context" +// COMPONENT-MODEL-THREAD-CONTEXT: "-target-feature" "+component-model-threading" +// NO-COMPONENT-MODEL-THREAD-CONTEXT: "-target-feature" "-component-model-threading" diff --git a/clang/test/Driver/wasm-toolchain.c b/clang/test/Driver/wasm-toolchain.c index 7dbf1d6ce6aa5..2c36e488b27fb 100644 --- a/clang/test/Driver/wasm-toolchain.c +++ b/clang/test/Driver/wasm-toolchain.c @@ -304,14 +304,14 @@ // LINK_WALI_BASIC: "-cc1" {{.*}} "-o" "[[temp:[^"]*]]" // LINK_WALI_BASIC: wasm-ld{{.*}}" "-L/foo/lib/wasm32-linux-muslwali" "crt1.o" "[[temp]]" "-lc" "{{.*[/\\]}}libclang_rt.builtins.a" "-o" "a.out" -// `wasm32-wasip3` passes `+component-model-thread-context` by default. +// `wasm32-wasip3` passes `+component-model-threading` by default. // RUN: %clang -### --target=wasm32-wasip3 --sysroot=/foo %s 2>&1 \ // RUN: | FileCheck -check-prefix=LINK_WASIP3_THREAD_CONTEXT %s -// LINK_WASIP3_THREAD_CONTEXT: "-cc1" {{.*}} "-target-feature" "+component-model-thread-context" +// LINK_WASIP3_THREAD_CONTEXT: "-cc1" {{.*}} "-target-feature" "+component-model-threading" -// `wasm32-wasip3` does not pass `+component-model-thread-context` when `-mno-component-model-thread-context` is used. +// `wasm32-wasip3` does not pass `+component-model-threading` when `-mno-component-model-threading` is used. -// RUN: %clang -### --target=wasm32-wasip3 --sysroot=/foo -mno-component-model-thread-context %s 2>&1 \ +// RUN: %clang -### --target=wasm32-wasip3 --sysroot=/foo -mno-component-model-threading %s 2>&1 \ // RUN: | FileCheck -check-prefix=LINK_WASIP3_NO_THREAD_CONTEXT %s -// LINK_WASIP3_NO_THREAD_CONTEXT: "-cc1" {{.*}} "-target-feature" "-component-model-thread-context" +// LINK_WASIP3_NO_THREAD_CONTEXT: "-cc1" {{.*}} "-target-feature" "-component-model-threading" diff --git a/clang/test/Preprocessor/wasm-target-features.c b/clang/test/Preprocessor/wasm-target-features.c index 72b314d2382a8..b81e03bb5d513 100644 --- a/clang/test/Preprocessor/wasm-target-features.c +++ b/clang/test/Preprocessor/wasm-target-features.c @@ -253,10 +253,10 @@ // BLEEDING-EDGE-NO-SIMD128-NOT: #define __wasm_simd128__ 1{{$}} // RUN: %clang -E -dM %s -o - 2>&1 \ -// RUN: -target wasm32-unknown-unknown -mcomponent-model-thread-context \ +// RUN: -target wasm32-unknown-unknown -mcomponent-model-threading \ // RUN: | FileCheck %s -check-prefix=COMPONENT-MODEL-THREAD-CONTEXT // RUN: %clang -E -dM %s -o - 2>&1 \ -// RUN: -target wasm64-unknown-unknown -mcomponent-model-thread-context \ +// RUN: -target wasm64-unknown-unknown -mcomponent-model-threading \ // RUN: | FileCheck %s -check-prefix=COMPONENT-MODEL-THREAD-CONTEXT -// COMPONENT-MODEL-THREAD-CONTEXT: #define __wasm_component_model_thread_context__ 1{{$}} +// COMPONENT-MODEL-THREAD-CONTEXT: #define __wasm_component_model_threading__ 1{{$}} diff --git a/compiler-rt/lib/builtins/wasm/thread_context.c b/compiler-rt/lib/builtins/wasm/thread_context.c index de64bb3035777..d5326f0ea8ae9 100644 --- a/compiler-rt/lib/builtins/wasm/thread_context.c +++ b/compiler-rt/lib/builtins/wasm/thread_context.c @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#ifdef __wasm_component_model_thread_context__ +#ifdef __wasm_component_model_threading__ // We define these function as naked functions with inline assembly because: // 1. Defining them as regular C functions would cause infinite recursion in diff --git a/lld/test/wasm/stack-pointer-abi.s b/lld/test/wasm/stack-pointer-abi.s index e03e9867c403b..492c7e5c08078 100644 --- a/lld/test/wasm/stack-pointer-abi.s +++ b/lld/test/wasm/stack-pointer-abi.s @@ -2,7 +2,7 @@ # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/use.o %t/use.s # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/disallow.o %t/disallow.s # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/start.o %t/start.s -# RUN: wasm-ld --component-model-thread-context -o %t/component-model.wasm %t/use.o %t/start.o +# RUN: wasm-ld -o %t/component-model.wasm %t/use.o %t/start.o # RUN: obj2yaml %t/component-model.wasm | FileCheck %s --check-prefix=COMPONENT-MODEL # RUN: wasm-ld -o %t/global.wasm %t/disallow.o %t/start.o # RUN: obj2yaml %t/global.wasm | FileCheck %s --check-prefix=GLOBAL @@ -18,7 +18,7 @@ _start: .int8 1 .int8 45 .int8 30 - .ascii "component-model-thread-context" + .ascii "component-model-threading" #--- use.s @@ -26,7 +26,7 @@ _start: .int8 1 .int8 43 .int8 30 - .ascii "component-model-thread-context" + .ascii "component-model-threading" # COMPONENT-MODEL: Name: __init_stack_pointer # GLOBAL: Name: __stack_pointer diff --git a/lld/test/wasm/thread-context-abi-mismatch.s b/lld/test/wasm/thread-context-abi-mismatch.s index b067b7c580caf..817c703ada7dc 100644 --- a/lld/test/wasm/thread-context-abi-mismatch.s +++ b/lld/test/wasm/thread-context-abi-mismatch.s @@ -4,19 +4,19 @@ # Test that the presence of an import of __stack_pointer from the env module is treated # as an indication that the global thread context ABI is being used, even if the -# component-model-thread-context feature is not disallowed. +# component-model-threading feature is not disallowed. # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/start.o %t/start.s # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/stack-pointer.o %t/stack-pointer.s # RUN: not wasm-ld %t/start.o %t/stack-pointer.o -o %t/fail.wasm 2>&1 | FileCheck %s -# Test that explicitly disallowing the component-model-thread-context feature causes linking to fail +# Test that explicitly disallowing the component-model-threading feature causes linking to fail # with an error when other files use the feature. # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/disallow.o %t/disallow.s # RUN: not wasm-ld %t/start.o %t/disallow.o -o %t/fail.wasm 2>&1 | FileCheck %s -# CHECK: error: thread context ABI mismatch: {{.*}} disallows component-model-thread-context but other files use it +# CHECK: error: thread context ABI mismatch: {{.*}} disallows component-model-threading but other files use it #--- start.s .globl _start @@ -29,7 +29,7 @@ _start: .int8 1 .int8 43 .int8 30 - .ascii "component-model-thread-context" + .ascii "component-model-threading" #--- stack-pointer.s .globaltype __stack_pointer, i32 @@ -49,4 +49,4 @@ _start: .int8 1 .int8 45 .int8 30 - .ascii "component-model-thread-context" + .ascii "component-model-threading" diff --git a/lld/test/wasm/tls-component-model.s b/lld/test/wasm/tls-component-model.s index 49b66263f57a5..1e1292f91b0d7 100644 --- a/lld/test/wasm/tls-component-model.s +++ b/lld/test/wasm/tls-component-model.s @@ -35,7 +35,7 @@ tls2: .int8 2 .int8 43 .int8 30 - .ascii "component-model-thread-context" + .ascii "component-model-threading" .int8 43 .int8 11 .ascii "bulk-memory" diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h index 002ac6e882804..760877acd9913 100644 --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -135,6 +135,13 @@ struct Config { llvm::SmallVector buildIdVector; }; +enum class ThreadModel { + Single, + SharedMemory, + // Used by WASIp3 targets + Cooperative, +}; + // The Ctx object hold all other (non-configuration) global state. struct Ctx { Config arg; @@ -280,17 +287,18 @@ struct Ctx { 0> whyExtractRecords; - // Whether to use component model thread context intrinsics for the stack - // pointer and TLS base. - bool componentModelThreadContext = false; + // Whether to use compiler-rt functions for the stack pointer and TLS base + // instead of globals. This is currently used for WASIp3 cooperative threads support. + bool externThreadBuiltins = false; + + // The thread model to use for tuning linker-generated code, segment passivity, etc. + ThreadModel threadModel = ThreadModel::Single; Ctx(); void reset(); - // This will be true for both shared-memory multi-threading and green threads - // support via externally-controlled stack pointer/TLS base. bool isMultithreaded() const { - return componentModelThreadContext || arg.sharedMemory; + return threadModel != ThreadModel::Single; } }; diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 5ef7465e069a1..71b1412548c4e 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -966,7 +966,7 @@ static void createPostLTOSymbols() { bool is64 = ctx.arg.is64.value_or(false); - auto stack_pointer_name = ctx.componentModelThreadContext + auto stack_pointer_name = ctx.externThreadBuiltins ? "__init_stack_pointer" : "__stack_pointer"; if (ctx.isPic) { @@ -987,16 +987,16 @@ static void createPostLTOSymbols() { } else { // For non-PIC code ctx.sym.stackPointer = createGlobalVariable( - stack_pointer_name, !ctx.componentModelThreadContext); + stack_pointer_name, !ctx.externThreadBuiltins); ctx.sym.stackPointer->markLive(); } if (ctx.isMultithreaded()) { // TLS symbols are all hidden/dso-local auto tls_base_name = - ctx.componentModelThreadContext ? "__init_tls_base" : "__tls_base"; + ctx.externThreadBuiltins ? "__init_tls_base" : "__tls_base"; ctx.sym.tlsBase = - createGlobalVariable(tls_base_name, !ctx.componentModelThreadContext, + createGlobalVariable(tls_base_name, !ctx.externThreadBuiltins, WASM_SYMBOL_VISIBILITY_HIDDEN); ctx.sym.tlsSize = createGlobalVariable("__tls_size", false, WASM_SYMBOL_VISIBILITY_HIDDEN); @@ -1006,7 +1006,7 @@ static void createPostLTOSymbols() { "__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN, make(is64 ? i64ArgSignature : i32ArgSignature, "__wasm_init_tls")); - if (ctx.componentModelThreadContext) { + if (ctx.externThreadBuiltins) { ctx.sym.tlsBase->markLive(); ctx.sym.tlsSize->markLive(); ctx.sym.tlsAlign->markLive(); @@ -1057,7 +1057,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 && !ctx.componentModelThreadContext) + if (!ctx.sym.tlsBase) ctx.sym.tlsBase = createOptionalGlobal("__tls_base", false); } @@ -1317,7 +1317,7 @@ static void checkZOptions(opt::InputArgList &args) { static void determineThreadContextABI(ArrayRef files) { // A complication is that a user may attempt to link together object files // compiled with different versions of LLVM, where one does not specifiy - // -component-model-thread-context when using the global thread context ABI. + // -component-model-threading when using the global thread context ABI. // They may also attempt to link object files with the global ABI compiled // with older LLVM versions, but link them with a newer wasm-ld. To ensure the // correct behavior in both of these cases, we treat the import of a @@ -1332,10 +1332,10 @@ static void determineThreadContextABI(ArrayRef files) { auto targetFeatures = obj->getWasmObj()->getTargetFeatures(); auto threadContextFeature = llvm::find_if(targetFeatures, [](const auto &f) { - return f.Name == "component-model-thread-context"; + return f.Name == "component-model-threading"; }); - bool usesComponentModelThreadContext = + bool usesComponentModelThreading = threadContextFeature != targetFeatures.end() && threadContextFeature->Prefix == WASM_FEATURE_PREFIX_USED; @@ -1356,16 +1356,16 @@ static void determineThreadContextABI(ArrayRef files) { continue; } // Treat this as using the globals ABI - usesComponentModelThreadContext = false; + usesComponentModelThreading = false; } - if (usesComponentModelThreadContext) { + if (usesComponentModelThreading) { if (threadContextABI == ThreadContextABI::Undetermined) { threadContextABI = ThreadContextABI::ComponentModelBuiltins; } else if (threadContextABI != ThreadContextABI::ComponentModelBuiltins) { error( "thread context ABI mismatch: " + obj->getName() + - " uses component-model-thread-context but other files disallow it"); + " uses component-model-threading but other files disallow it"); } } else { if (threadContextABI == ThreadContextABI::Undetermined) { @@ -1373,18 +1373,19 @@ static void determineThreadContextABI(ArrayRef files) { } else if (threadContextABI != ThreadContextABI::Globals) { error( "thread context ABI mismatch: " + obj->getName() + - " disallows component-model-thread-context but other files use it"); + " disallows component-model-threading but other files use it"); } } } // If the ABI is undetermined at this point, default to the globals ABI - ctx.componentModelThreadContext = - (threadContextABI == ThreadContextABI::ComponentModelBuiltins); - - if (ctx.arg.sharedMemory && ctx.componentModelThreadContext) { - error("--shared-memory is currently incompatible with component model " - "thread context intrinsics"); + if (threadContextABI == ThreadContextABI::ComponentModelBuiltins) { + if (ctx.arg.sharedMemory) { + error("--shared-memory is currently incompatible with component model " + "thread context intrinsics"); + } + ctx.externThreadBuiltins = true; + ctx.threadModel = ThreadModel::Cooperative; } } diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index 456fc2d8f7078..aaba30ece3b1e 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -53,7 +53,7 @@ class SubSection { }; void writeGetTLSBase(const Ctx &ctx, raw_ostream &os) { - if (ctx.componentModelThreadContext) { + if (ctx.externThreadBuiltins) { writeU8(os, WASM_OPCODE_CALL, "call"); writeUleb128(os, ctx.sym.getTLSBase->getFunctionIndex(), "function index"); } else { diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 6c04b4eaf5bd8..d196e4987f617 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -124,7 +124,7 @@ class Writer { }; void writeSetTLSBase(const Ctx &ctx, raw_ostream &os) { - if (ctx.componentModelThreadContext) { + if (ctx.externThreadBuiltins) { writeU8(os, WASM_OPCODE_CALL, "call"); writeUleb128(os, ctx.sym.setTLSBase->getFunctionIndex(), "function index"); } else { @@ -663,7 +663,7 @@ void Writer::populateTargetFeatures() { error("bulk-memory feature must be used in order to use thread-local " "storage"); } - if (!ctx.componentModelThreadContext && !allowed.contains("atomics")) { + if (ctx.threadModel == ThreadModel::SharedMemory && !allowed.contains("atomics")) { error( "atomics feature must be used in order to use thread-local storage"); } @@ -1049,9 +1049,10 @@ OutputSegment *Writer::createOutputSegment(StringRef name) { // threads. In the non-shared memory case, we use passive segments only for // TLS segments, so that they can be reused, and for .bss segments, which // don't need to be included in the binary at all. - bool passiveForCMTC = ctx.componentModelThreadContext && - (s->isTLS() || s->name.starts_with(".bss")); - if (ctx.arg.sharedMemory || passiveForCMTC) + bool needsPassiveInit = ctx.threadModel == ThreadModel::SharedMemory || + (ctx.threadModel == ThreadModel::Cooperative && + (s->isTLS() || s->name.starts_with(".bss"))); + if (needsPassiveInit) s->initFlags = WASM_DATA_SEGMENT_IS_PASSIVE; if (!ctx.arg.relocatable && name.starts_with(".bss")) s->isBss = true; @@ -1652,11 +1653,10 @@ void Writer::createInitTLSFunction() { writeUleb128(os, 0, "num locals"); if (tlsSeg) { - // When using component model thread context intrinsics, we don't set the - // TLS base + // When using WASIp3 cooperative threading, we don't set the TLS base // inside __init_tls; this should be done as part of the thread startup // stub. - if (!ctx.componentModelThreadContext) { + if (ctx.threadModel != ThreadModel::Cooperative) { writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); writeUleb128(os, 0, "local index"); diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.td b/llvm/lib/Target/WebAssembly/WebAssembly.td index 402764fa0de2f..54ecf92a51b94 100644 --- a/llvm/lib/Target/WebAssembly/WebAssembly.td +++ b/llvm/lib/Target/WebAssembly/WebAssembly.td @@ -37,8 +37,8 @@ def FeatureCallIndirectOverlong : SubtargetFeature<"call-indirect-overlong", "HasCallIndirectOverlong", "true", "Enable overlong encoding for call_indirect immediates">; -def FeatureComponentModelThreadContext : - SubtargetFeature<"component-model-thread-context", "HasComponentModelThreadContext", "true", +def FeatureComponentModelThreading : + SubtargetFeature<"component-model-threading", "HasComponentModelThreading", "true", "Enable component model thread context intrinsics">; def FeatureExceptionHandling : diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index 8a5c961115c52..4f129fae7bddd 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -139,7 +139,7 @@ bool WebAssemblyFrameLowering::needsSPForLocalFrame( // info is present so we can allocate a local for DWARF to reference. bool NeedsSPForDebug = MF.getFunction().getSubprogram() && - MF.getSubtarget().hasComponentModelThreadContext(); + MF.getSubtarget().hasComponentModelThreading(); return MFI.getStackSize() || MFI.adjustsStack() || hasFP(MF) || HasExplicitSPUse || NeedsSPForDebug; @@ -240,7 +240,7 @@ void WebAssemblyFrameLowering::writeBackSP( const auto *TII = MF.getSubtarget().getInstrInfo(); if (MF.getSubtarget() - .hasComponentModelThreadContext()) { + .hasComponentModelThreading()) { const char *ES = "__wasm_set_stack_pointer"; auto *SPSymbol = MF.createExternalSymbolName(ES); BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::CALL)) @@ -299,7 +299,7 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, if (StackSize) SPReg = MRI.createVirtualRegister(PtrRC); - if (ST.hasComponentModelThreadContext()) { + if (ST.hasComponentModelThreading()) { const char *ES = "__wasm_get_stack_pointer"; auto *SPSymbol = MF.createExternalSymbolName(ES); BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CALL), SPReg) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td index 52874915c6f24..fe6b0a6a0fb31 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -38,10 +38,10 @@ def HasCallIndirectOverlong : Predicate<"Subtarget->hasCallIndirectOverlong()">, AssemblerPredicate<(all_of FeatureCallIndirectOverlong), "call-indirect-overlong">; -def HasComponentModelThreadContext : - Predicate<"Subtarget->hasComponentModelThreadContext()">, - AssemblerPredicate<(all_of FeatureComponentModelThreadContext), - "component-model-thread-context">; +def HasComponentModelThreading : + Predicate<"Subtarget->hasComponentModelThreading()">, + AssemblerPredicate<(all_of FeatureComponentModelThreading), + "component-model-threading">; def HasExceptionHandling : Predicate<"Subtarget->hasExceptionHandling()">, diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp index 662e01022cc87..89478b20f035a 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp @@ -42,11 +42,11 @@ WebAssemblySubtarget::initializeSubtargetDependencies(StringRef CPU, // WASIP3 implies using the component model thread context intrinsics by // default, unless explicitly disabled. - if (!FS.contains("component-model-thread-context") && - !HasComponentModelThreadContext && + if (!FS.contains("component-model-threading") && + !HasComponentModelThreading && TargetTriple.getOS() == Triple::WASIp3) { - ToggleFeature(WebAssembly::FeatureComponentModelThreadContext); - HasComponentModelThreadContext = true; + ToggleFeature(WebAssembly::FeatureComponentModelThreading); + HasComponentModelThreading = true; } FeatureBitset Bits = getFeatureBits(); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h index fa0188807e9ca..4d711383a1b35 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h @@ -48,7 +48,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo { bool HasBulkMemoryOpt = false; bool HasCallIndirectOverlong = false; bool HasCompactImports = false; - bool HasComponentModelThreadContext = false; + bool HasComponentModelThreading = false; bool HasExceptionHandling = false; bool HasExtendedConst = false; bool HasFP16 = false; @@ -113,8 +113,8 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo { bool hasBulkMemoryOpt() const { return HasBulkMemoryOpt; } bool hasCallIndirectOverlong() const { return HasCallIndirectOverlong; } bool hasCompactImports() const { return HasCompactImports; } - bool hasComponentModelThreadContext() const { - return HasComponentModelThreadContext; + bool hasComponentModelThreading() const { + return HasComponentModelThreading; } bool hasExceptionHandling() const { return HasExceptionHandling; } bool hasExtendedConst() const { return HasExtendedConst; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index cb6e1ad45a4ab..6418d0d26f00f 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -282,7 +282,7 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { bool StrippedAtomics = false; bool StrippedTLS = false; - if (Features[WebAssembly::FeatureComponentModelThreadContext]) { + if (Features[WebAssembly::FeatureComponentModelThreading]) { // Using component model threading intrinsics allows TLS without // atomics, so don't strip TLS even if atomics are disabled. if (!Features[WebAssembly::FeatureAtomics]) { @@ -429,13 +429,13 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { wasm::WASM_FEATURE_PREFIX_DISALLOWED); } - // Mark component-model-thread-context as disallowed when not in use to + // Mark component-model-threading as disallowed when not in use to // prevent linking object files with incompatible threading ABIs. // This is implicit for MVP since the feature is not supported at all. if (CPU != "mvp" && - !Features[WebAssembly::FeatureComponentModelThreadContext]) { + !Features[WebAssembly::FeatureComponentModelThreading]) { M.addModuleFlag(Module::ModFlagBehavior::Error, - "wasm-feature-component-model-thread-context", + "wasm-feature-component-model-threading", wasm::WASM_FEATURE_PREFIX_DISALLOWED); } } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index 433e5ce987e4c..d01821269e667 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -202,7 +202,7 @@ MachineSDNode *WebAssembly::getTLSBase(SelectionDAG &DAG, const SDLoc &DL, unsigned Opcode; const char *SymName; - if (Subtarget->hasComponentModelThreadContext()) { + if (Subtarget->hasComponentModelThreading()) { Opcode = WebAssembly::CALL; SymName = "__wasm_get_tls_base"; } else { diff --git a/llvm/test/CodeGen/WebAssembly/stack-abi.ll b/llvm/test/CodeGen/WebAssembly/stack-abi.ll index 6b69cec44f022..bbdcb7c15f09f 100644 --- a/llvm/test/CodeGen/WebAssembly/stack-abi.ll +++ b/llvm/test/CodeGen/WebAssembly/stack-abi.ll @@ -1,5 +1,5 @@ -; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+component-model-thread-context | FileCheck --check-prefix=CMTC %s -; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=-component-model-thread-context | FileCheck --check-prefix=GLOBAL %s +; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+component-model-threading | FileCheck --check-prefix=CMTC %s +; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=-component-model-threading | FileCheck --check-prefix=GLOBAL %s declare void @force_sp_save() define void @use_stack() #0 { diff --git a/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll b/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll index 8e70c0607adb1..d6afbe613452e 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll @@ -53,7 +53,7 @@ attributes #2 = { "target-features"="+reference-types" } ; CHECK: i32.store ; Features in function attributes: -; +atomics, +nontrapping-fptoint, +reference-types, -component-model-thread-context +; +atomics, +nontrapping-fptoint, +reference-types, -component-model-threading ; CHECK-LABEL: .custom_section.target_features,"",@ ; CHECK-NEXT: .int8 4 ; CHECK-NEXT: .int8 43 @@ -70,7 +70,7 @@ attributes #2 = { "target-features"="+reference-types" } ; CHECK-NEXT: .ascii "reference-types" ; Features in function attributes + features specified by -mattr= option: -; +atomics, +nontrapping-fptoint, +reference-types, +simd128, -component-model-thread-context +; +atomics, +nontrapping-fptoint, +reference-types, +simd128, -component-model-threading ; SIMD128-LABEL: .custom_section.target_features,"",@ ; SIMD128-NEXT: .int8 5 ; SIMD128-NEXT: .int8 43 diff --git a/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll b/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll index 0081a1d661f4e..21bc5212beb39 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll @@ -12,7 +12,7 @@ target triple = "wasm32-unknown-unknown" ; mvp: should not contain the target features section ; MVP-NOT: .custom_section.target_features,"",@ -; generic: +call-indirect-overlong, +multivalue, +mutable-globals, +reference-types, +sign-ext, -component-model-thread-context +; generic: +call-indirect-overlong, +multivalue, +mutable-globals, +reference-types, +sign-ext, -component-model-threading ; GENERIC-LABEL: .custom_section.target_features,"",@ ; GENERIC-NEXT: .int8 9 ; GENERIC-NEXT: .int8 43 @@ -26,7 +26,7 @@ target triple = "wasm32-unknown-unknown" ; GENERIC-NEXT: .ascii "call-indirect-overlong" ; GENERIC-NEXT: .int8 45 ; GENERIC-NEXT: .int8 30 -; GENERIC-NEXT: .ascii "component-model-thread-context" +; GENERIC-NEXT: .ascii "component-model-threading" ; GENERIC-NEXT: .int8 43 ; GENERIC-NEXT: .int8 10 ; GENERIC-NEXT: .ascii "multivalue" @@ -44,7 +44,7 @@ target triple = "wasm32-unknown-unknown" ; GENERIC-NEXT: .ascii "sign-ext" ; lime1: +bulk-memory-opt, +call-indirect-overlong, +extended-const, +multivalue, -; +mutable-globals, +nontrapping-fptoint, +sign-ext, -component-model-thread-context +; +mutable-globals, +nontrapping-fptoint, +sign-ext, -component-model-threading ; LIME1-LABEL: .custom_section.target_features,"",@ ; LIME1-NEXT: .int8 8 ; LIME1-NEXT: .int8 43 @@ -55,7 +55,7 @@ target triple = "wasm32-unknown-unknown" ; LIME1-NEXT: .ascii "call-indirect-overlong" ; LIME1-NEXT: .int8 45 ; LIME1-NEXT: .int8 30 -; LIME1-NEXT: .ascii "component-model-thread-context" +; LIME1-NEXT: .ascii "component-model-threading" ; LIME1-NEXT: .int8 43 ; LIME1-NEXT: .int8 14 ; LIME1-NEXT: .ascii "extended-const" @@ -77,7 +77,7 @@ target triple = "wasm32-unknown-unknown" ; +extended-const, +fp16, +gc, +multimemory, +multivalue, ; +mutable-globals, +nontrapping-fptoint, +relaxed-simd, ; +reference-types, +simd128, +sign-ext, +tail-call -; -component-model-thread-context +; -component-model-threading ; BLEEDING-EDGE-LABEL: .section .custom_section.target_features,"",@ ; BLEEDING-EDGE-NEXT: .int8 18 ; BLEEDING-EDGE-NEXT: .int8 43 @@ -94,7 +94,7 @@ target triple = "wasm32-unknown-unknown" ; BLEEDING-EDGE-NEXT: .ascii "call-indirect-overlong" ; BLEEDING-EDGE-NEXT: .int8 45 ; BLEEDING-EDGE-NEXT: .int8 30 -; BLEEDING-EDGE-NEXT: .ascii "component-model-thread-context" +; BLEEDING-EDGE-NEXT: .ascii "component-model-threading" ; BLEEDING-EDGE-NEXT: .int8 43 ; BLEEDING-EDGE-NEXT: .int8 18 ; BLEEDING-EDGE-NEXT: .ascii "exception-handling" diff --git a/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll b/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll index db383e74b8283..1927430af72ea 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll @@ -1,9 +1,9 @@ ; RUN: llc < %s -mtriple=wasm32-wasip3 | FileCheck %s --check-prefix=WASIP3 -; RUN: llc < %s -mtriple=wasm32-wasip3 -mattr=-component-model-thread-context | FileCheck %s --check-prefix=EXPLICIT-DISABLE +; RUN: llc < %s -mtriple=wasm32-wasip3 -mattr=-component-model-threading | FileCheck %s --check-prefix=EXPLICIT-DISABLE ; RUN: llc < %s -mtriple=wasm32-wasip1 | FileCheck %s --check-prefix=WASIP1 ; RUN: llc < %s -mtriple=wasm32-wasip2 | FileCheck %s --check-prefix=WASIP2 -; Test that wasip3 target automatically enables component-model-thread-context +; Test that wasip3 target automatically enables component-model-threading ; WASIP3: .section .custom_section.target_features,"",@ ; WASIP3-NEXT: .int8 9 @@ -18,7 +18,7 @@ ; WASIP3-NEXT: .ascii "call-indirect-overlong" ; WASIP3-NEXT: .int8 43 ; WASIP3-NEXT: .int8 30 -; WASIP3-NEXT: .ascii "component-model-thread-context" +; WASIP3-NEXT: .ascii "component-model-threading" ; EXPLICIT-DISABLE: .section .custom_section.target_features,"",@ ; EXPLICIT-DISABLE-NEXT: .int8 9 @@ -33,7 +33,7 @@ ; EXPLICIT-DISABLE-NEXT: .ascii "call-indirect-overlong" ; EXPLICIT-DISABLE-NEXT: .int8 45 ; EXPLICIT-DISABLE-NEXT: .int8 30 -; EXPLICIT-DISABLE-NEXT: .ascii "component-model-thread-context" +; EXPLICIT-DISABLE-NEXT: .ascii "component-model-threading" ; WASIP1: .section .custom_section.target_features,"",@ ; WASIP1-NEXT: .int8 9 @@ -48,7 +48,7 @@ ; WASIP1-NEXT: .ascii "call-indirect-overlong" ; WASIP1-NEXT: .int8 45 ; WASIP1-NEXT: .int8 30 -; WASIP1-NEXT: .ascii "component-model-thread-context" +; WASIP1-NEXT: .ascii "component-model-threading" ; WASIP2: .section .custom_section.target_features,"",@ ; WASIP2-NEXT: .int8 9 @@ -63,7 +63,7 @@ ; WASIP2-NEXT: .ascii "call-indirect-overlong" ; WASIP2-NEXT: .int8 45 ; WASIP2-NEXT: .int8 30 -; WASIP2-NEXT: .ascii "component-model-thread-context" +; WASIP2-NEXT: .ascii "component-model-threading" define void @test() { ret void diff --git a/llvm/test/CodeGen/WebAssembly/target-features-tls.ll b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll index 946d5cb5691b4..f91398800822b 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-tls.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll @@ -1,7 +1,7 @@ ; RUN: llc < %s -mcpu=mvp -mattr=-bulk-memory,atomics | FileCheck %s --check-prefixes NO-BULK-MEM ; RUN: llc < %s -mcpu=mvp -mattr=+bulk-memory,atomics | FileCheck %s --check-prefixes BULK-MEM -; RUN: llc < %s -mcpu=mvp -mattr=+component-model-thread-context,-bulk-memory,atomics | FileCheck %s --check-prefixes NO-BULK-MEM-CMTC -; RUN: llc < %s -mcpu=mvp -mattr=+component-model-thread-context,bulk-memory,atomics | FileCheck %s --check-prefixes BULK-MEM-CMTC +; RUN: llc < %s -mcpu=mvp -mattr=+component-model-threading,-bulk-memory,atomics | FileCheck %s --check-prefixes NO-BULK-MEM-CMTC +; RUN: llc < %s -mcpu=mvp -mattr=+component-model-threading,bulk-memory,atomics | FileCheck %s --check-prefixes BULK-MEM-CMTC ; Test that the target features section contains -atomics or +atomics ; for modules that have thread local storage in their source. @@ -35,7 +35,7 @@ target triple = "wasm32-unknown-unknown" ; BULK-MEM-NEXT: .ascii "bulk-memory-opt" ; BULK-MEM-NEXT: .tbss.foo,"T",@ -; -bulk-memory,+component-model-thread-context +; -bulk-memory,+component-model-threading ; NO-BULK-MEM-CMTC-LABEL: .custom_section.target_features,"",@ ; NO-BULK-MEM-CMTC-NEXT: .int8 3 ; NO-BULK-MEM-CMTC-NEXT: .int8 43 @@ -43,13 +43,13 @@ target triple = "wasm32-unknown-unknown" ; NO-BULK-MEM-CMTC-NEXT: .ascii "atomics" ; NO-BULK-MEM-CMTC-NEXT: .int8 43 ; NO-BULK-MEM-CMTC-NEXT: .int8 30 -; NO-BULK-MEM-CMTC-NEXT: .ascii "component-model-thread-context" +; NO-BULK-MEM-CMTC-NEXT: .ascii "component-model-threading" ; NO-BULK-MEM-CMTC-NEXT: .int8 45 ; NO-BULK-MEM-CMTC-NEXT: .int8 10 ; NO-BULK-MEM-CMTC-NEXT: .ascii "shared-mem" ; NO-BULK-MEM-CMTC-NEXT: .bss.foo,"",@ -; +bulk-memory,+component-model-thread-context +; +bulk-memory,+component-model-threading ; BULK-MEM-CMTC-LABEL: .custom_section.target_features,"",@ ; BULK-MEM-CMTC-NEXT: .int8 4 ; BULK-MEM-CMTC-NEXT: .int8 43 @@ -63,5 +63,5 @@ target triple = "wasm32-unknown-unknown" ; BULK-MEM-CMTC-NEXT: .ascii "bulk-memory-opt" ; BULK-MEM-CMTC-NEXT: .int8 43 ; BULK-MEM-CMTC-NEXT: .int8 30 -; BULK-MEM-CMTC-NEXT: .ascii "component-model-thread-context" +; BULK-MEM-CMTC-NEXT: .ascii "component-model-threading" ; BULK-MEM-CMTC-NEXT: .tbss.foo,"T",@ diff --git a/llvm/test/CodeGen/WebAssembly/thread_pointer.ll b/llvm/test/CodeGen/WebAssembly/thread_pointer.ll index 38f9ec2543c89..9c75ebce187dd 100644 --- a/llvm/test/CodeGen/WebAssembly/thread_pointer.ll +++ b/llvm/test/CodeGen/WebAssembly/thread_pointer.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=wasm32-unknown-unknown | FileCheck %s --check-prefix=WASM32 ; RUN: llc < %s -mtriple=wasm64-unknown-unknown | FileCheck %s --check-prefix=WASM64 -; RUN: llc < %s -mtriple=wasm32-unknown-unknown -mattr=+component-model-thread-context | FileCheck %s --check-prefix=WASM32-CMTC +; RUN: llc < %s -mtriple=wasm32-unknown-unknown -mattr=+component-model-threading | FileCheck %s --check-prefix=WASM32-CMTC declare ptr @llvm.thread.pointer() diff --git a/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll b/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll index abe0afe806651..eb1120d4832ad 100644 --- a/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll +++ b/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll @@ -1,16 +1,16 @@ ; Run the tests with the `localexec` TLS mode specified. ; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,TLS %s ; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS %s -; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+component-model-thread-context,bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS-CMTC %s +; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+component-model-threading,bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS-CMTC %s ; Also, run the same tests without a specified TLS mode--this should still emit `localexec` code on non-Emscripten targtes which don't currently support dynamic linking. ; RUN: sed -e 's/\[\[TLS_MODE\]\]//' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,TLS %s ; RUN: sed -e 's/\[\[TLS_MODE\]\]//' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS %s -; RUN: sed -e 's/\[\[TLS_MODE\]\]//' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+component-model-thread-context,bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS-CMTC %s +; RUN: sed -e 's/\[\[TLS_MODE\]\]//' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+component-model-threading,bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS-CMTC %s ; Finally, when bulk memory is disabled, no TLS code should be generated. ; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=-bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,NO-TLS %s -; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+component-model-thread-context,-bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,NO-TLS %s +; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+component-model-threading,-bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,NO-TLS %s target triple = "wasm32-unknown-unknown" ; CHECK-LABEL: address_of_tls: From e841994d93b52859072042e62627a8cac109801c Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 1 Apr 2026 14:15:34 +0100 Subject: [PATCH 099/134] Refactor --- clang/include/clang/Options/Options.td | 4 +- clang/lib/Basic/Targets/WebAssembly.cpp | 22 +++--- clang/lib/Basic/Targets/WebAssembly.h | 2 +- clang/lib/Driver/ToolChains/WebAssembly.cpp | 67 ++++++++----------- .../WebAssembly/wasm-thread-context-abi.c | 11 +++ clang/test/Driver/wasm-features.c | 8 +-- clang/test/Driver/wasm-toolchain.c | 20 +++--- .../test/Preprocessor/wasm-target-features.c | 10 +-- compiler-rt/lib/builtins/CMakeLists.txt | 1 - .../lib/builtins/wasm/thread_context.c | 61 ----------------- lld/test/wasm/stack-pointer-abi.s | 14 ++-- lld/test/wasm/thread-context-abi-mismatch.s | 14 ++-- .../{tls-component-model.s => tls-libcall.s} | 4 +- lld/wasm/Config.h | 22 ++---- lld/wasm/Driver.cpp | 53 ++++++++------- lld/wasm/Relocations.cpp | 2 +- lld/wasm/SyntheticSections.cpp | 13 ++-- lld/wasm/Writer.cpp | 61 +++++++---------- .../MCTargetDesc/WebAssemblyMCTargetDesc.h | 4 +- llvm/lib/Target/WebAssembly/WebAssembly.td | 6 +- .../WebAssembly/WebAssemblyFrameLowering.cpp | 10 +-- .../WebAssembly/WebAssemblyFrameLowering.h | 4 +- .../WebAssembly/WebAssemblyISelLowering.cpp | 2 +- .../WebAssembly/WebAssemblyInstrInfo.td | 10 +-- .../WebAssembly/WebAssemblyLateEHPrepare.cpp | 4 +- .../WebAssembly/WebAssemblySubtarget.cpp | 10 +-- .../Target/WebAssembly/WebAssemblySubtarget.h | 6 +- .../WebAssembly/WebAssemblyTargetMachine.cpp | 44 +++++------- .../WebAssembly/WebAssemblyUtilities.cpp | 2 +- .../Target/WebAssembly/WebAssemblyUtilities.h | 4 +- llvm/test/CodeGen/WebAssembly/stack-abi.ll | 14 ++-- .../WebAssembly/target-features-attrs.ll | 4 +- .../WebAssembly/target-features-cpus.ll | 18 ++--- .../target-features-thread-context.ll | 20 +++--- .../WebAssembly/target-features-tls.ll | 12 ++-- .../CodeGen/WebAssembly/thread_pointer.ll | 12 ++-- .../CodeGen/WebAssembly/tls-local-exec.ll | 52 +++++++------- 37 files changed, 261 insertions(+), 366 deletions(-) create mode 100644 clang/test/CodeGen/WebAssembly/wasm-thread-context-abi.c delete mode 100644 compiler-rt/lib/builtins/wasm/thread_context.c rename lld/test/wasm/{tls-component-model.s => tls-libcall.s} (97%) diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 6d918d957b3ac..403e4a4c31820 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -5709,8 +5709,6 @@ def mcall_indirect_overlong : Flag<["-"], "mcall-indirect-overlong">, Group, Group; def mcompact_imports : Flag<["-"], "mcompact-imports">, Group; def mno_compact_imports : Flag<["-"], "mno-compact-imports">, Group; -def mcomponent_model_threading : Flag<["-"], "mcomponent-model-threading">, Group; -def mno_component_model_threading : Flag<["-"], "mno-component-model-threading">, Group; def mexception_handing : Flag<["-"], "mexception-handling">, Group; def mno_exception_handing : Flag<["-"], "mno-exception-handling">, Group; def mextended_const : Flag<["-"], "mextended-const">, Group; @@ -5719,6 +5717,8 @@ def mfp16 : Flag<["-"], "mfp16">, Group; def mno_fp16 : Flag<["-"], "mno-fp16">, Group; def mgc : Flag<["-"], "mgc">, Group; def mno_gc : Flag<["-"], "mno-gc">, Group; +def mlibcall_thread_context : Joined<["-"], "mlibcall-thread-context">, Group; +def mno_libcall_thread_context : Joined<["-"], "mno-libcall-thread-context">, Group; def mmultimemory : Flag<["-"], "mmultimemory">, Group; def mno_multimemory : Flag<["-"], "mno-multimemory">, Group; def mmultivalue : Flag<["-"], "mmultivalue">, Group; diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp index 2c5f42e66bb67..ea5b06e4a6fde 100644 --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -56,7 +56,6 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const { .Case("bulk-memory", HasBulkMemory) .Case("bulk-memory-opt", HasBulkMemoryOpt) .Case("call-indirect-overlong", HasCallIndirectOverlong) - .Case("component-model-threading", HasComponentModelThreading) .Case("compact-imports", HasCompactImports) .Case("exception-handling", HasExceptionHandling) .Case("extended-const", HasExtendedConst) @@ -124,8 +123,8 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__wasm_tail_call__"); if (HasWideArithmetic) Builder.defineMacro("__wasm_wide_arithmetic__"); - if (HasComponentModelThreading) - Builder.defineMacro("__wasm_component_model_threading__"); + if (HasLibcallThreadContext) + Builder.defineMacro("__wasm_libcall_thread_context__"); // Note that not all wasm features appear here. For example, // HasCompatctImports @@ -389,12 +388,12 @@ bool WebAssemblyTargetInfo::handleTargetFeatures( HasWideArithmetic = false; continue; } - if (Feature == "+component-model-threading") { - HasComponentModelThreading = true; + if (Feature == "+libcall-thread-context") { + HasLibcallThreadContext = true; continue; } - if (Feature == "-component-model-threading") { - HasComponentModelThreading = false; + if (Feature == "-libcall-thread-context") { + HasLibcallThreadContext = false; continue; } @@ -430,11 +429,10 @@ WebAssemblyTargetInfo::getTargetBuiltins() const { void WebAssemblyTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts, const TargetInfo *Aux) { TargetInfo::adjust(Diags, Opts, Aux); - // If not using component model threading intrinsics, turn off POSIXThreads - // and ThreadModel so that we don't predefine _REENTRANT or __STDCPP_THREADS__ - // if we will eventually end up stripping atomics because they are - // unsupported. - if (!HasComponentModelThreading && (!HasAtomics || !HasBulkMemory)) { + // Turn off POSIXThreads and ThreadModel so that we don't predefine _REENTRANT + // or __STDCPP_THREADS__ if we will eventually end up stripping atomics + // because they are unsupported. + if (!HasAtomics || !HasBulkMemory) { Opts.POSIXThreads = false; Opts.setThreadModel(LangOptions::ThreadModelKind::Single); Opts.ThreadsafeStatics = false; diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h index 2479f6ac3a090..6585ca4c88a37 100644 --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -63,11 +63,11 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo { bool HasBulkMemoryOpt = false; bool HasCallIndirectOverlong = false; bool HasCompactImports = false; - bool HasComponentModelThreading = false; bool HasExceptionHandling = false; bool HasExtendedConst = false; bool HasFP16 = false; bool HasGC = false; + bool HasLibcallThreadContext = false; bool HasMultiMemory = false; bool HasMultivalue = false; bool HasMutableGlobals = false; diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index df970aab06418..ab781b8575aa7 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -88,19 +88,14 @@ static bool WantsPthread(const llvm::Triple &Triple, const ArgList &Args) { return WantsPthread; } -static bool WantsComponentModelThreading(const llvm::Triple &Triple, +static bool WantsLibcallThreadContext(const llvm::Triple &Triple, const ArgList &Args) { // If the target is WASIP3, then enable the - // component-model-threading feature by default, unless explicitly + // libcall-thread-context feature by default, unless explicitly // disabled. return Triple.getOS() == llvm::Triple::WASIp3 && - Args.hasFlag(options::OPT_mcomponent_model_threading, - options::OPT_mno_component_model_threading, true); -} - -static bool WantsSharedMemory(const llvm::Triple &Triple, const ArgList &Args) { - return WantsPthread(Triple, Args) && - !WantsComponentModelThreading(Triple, Args); + Args.hasFlag(options::OPT_mlibcall_thread_context, + options::OPT_mno_libcall_thread_context, true); } void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -184,7 +179,7 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - if (WantsSharedMemory(ToolChain.getTriple(), Args)) + if (WantsPthread(ToolChain.getTriple(), Args)) CmdArgs.push_back("--shared-memory"); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { @@ -336,45 +331,41 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, options::OPT_fno_use_init_array, true)) CC1Args.push_back("-fno-use-init-array"); - if (WantsComponentModelThreading(getTriple(), DriverArgs)) { + if (WantsLibcallThreadContext(getTriple(), DriverArgs)) { CC1Args.push_back("-target-feature"); - CC1Args.push_back("+component-model-threading"); + CC1Args.push_back("+libcall-thread-context"); } - // '-pthread' implies bulk-memory, and, if shared memory is also used, - // also implies atomics, mutable-globals, and sign-ext. + // '-pthread' implies atomics, bulk-memory, mutable-globals, and sign-ext if (WantsPthread(getTriple(), DriverArgs)) { + if (DriverArgs.hasFlag(options::OPT_mno_atomics, options::OPT_matomics, + false)) + getDriver().Diag(diag::err_drv_argument_not_allowed_with) + << "-pthread" + << "-mno-atomics"; if (DriverArgs.hasFlag(options::OPT_mno_bulk_memory, options::OPT_mbulk_memory, false)) getDriver().Diag(diag::err_drv_argument_not_allowed_with) << "-pthread" << "-mno-bulk-memory"; + if (DriverArgs.hasFlag(options::OPT_mno_mutable_globals, + options::OPT_mmutable_globals, false)) + getDriver().Diag(diag::err_drv_argument_not_allowed_with) + << "-pthread" + << "-mno-mutable-globals"; + if (DriverArgs.hasFlag(options::OPT_mno_sign_ext, options::OPT_msign_ext, + false)) + getDriver().Diag(diag::err_drv_argument_not_allowed_with) + << "-pthread" + << "-mno-sign-ext"; + CC1Args.push_back("-target-feature"); + CC1Args.push_back("+atomics"); CC1Args.push_back("-target-feature"); CC1Args.push_back("+bulk-memory"); - - if (WantsSharedMemory(getTriple(), DriverArgs)) { - if (DriverArgs.hasFlag(options::OPT_mno_atomics, options::OPT_matomics, - false)) - getDriver().Diag(diag::err_drv_argument_not_allowed_with) - << "-pthread" - << "-mno-atomics"; - if (DriverArgs.hasFlag(options::OPT_mno_mutable_globals, - options::OPT_mmutable_globals, false)) - getDriver().Diag(diag::err_drv_argument_not_allowed_with) - << "-pthread" - << "-mno-mutable-globals"; - if (DriverArgs.hasFlag(options::OPT_mno_sign_ext, options::OPT_msign_ext, - false)) - getDriver().Diag(diag::err_drv_argument_not_allowed_with) - << "-pthread" - << "-mno-sign-ext"; - CC1Args.push_back("-target-feature"); - CC1Args.push_back("+atomics"); - CC1Args.push_back("-target-feature"); - CC1Args.push_back("+mutable-globals"); - CC1Args.push_back("-target-feature"); - CC1Args.push_back("+sign-ext"); - } + CC1Args.push_back("-target-feature"); + CC1Args.push_back("+mutable-globals"); + CC1Args.push_back("-target-feature"); + CC1Args.push_back("+sign-ext"); } if (!DriverArgs.hasFlag(options::OPT_mmutable_globals, diff --git a/clang/test/CodeGen/WebAssembly/wasm-thread-context-abi.c b/clang/test/CodeGen/WebAssembly/wasm-thread-context-abi.c new file mode 100644 index 0000000000000..48ba06a38b32e --- /dev/null +++ b/clang/test/CodeGen/WebAssembly/wasm-thread-context-abi.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -triple wasm32-unknown-unknown-wasm -emit-llvm -o - %s | FileCheck %s + +void use_stack() { + int x; + volatile int* ptr = &x; +} + +void use_tls() { + static __thread int x; + volatile int* ptr = &x; +} \ No newline at end of file diff --git a/clang/test/Driver/wasm-features.c b/clang/test/Driver/wasm-features.c index 634eff9a1511c..df4b3652de353 100644 --- a/clang/test/Driver/wasm-features.c +++ b/clang/test/Driver/wasm-features.c @@ -119,9 +119,9 @@ // COMPACT-IMPORTS: "-target-feature" "+compact-imports" // NO-COMPACT-IMPORTS: "-target-feature" "-compact-imports" -// RUN: %clang --target=wasm32-unknown-unknown -### %s -mcomponent-model-threading 2>&1 | FileCheck %s -check-prefix=COMPONENT-MODEL-THREAD-CONTEXT -// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-component-model-threading 2>&1 | FileCheck %s -check-prefix=NO-COMPONENT-MODEL-THREAD-CONTEXT +// RUN: %clang --target=wasm32-unknown-unknown -### %s -mlibcall-thread-context 2>&1 | FileCheck %s -check-prefix=LIBCALL-THREAD-CONTEXT +// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-libcall-thread-context 2>&1 | FileCheck %s -check-prefix=NO-LIBCALL-THREAD-CONTEXT -// COMPONENT-MODEL-THREAD-CONTEXT: "-target-feature" "+component-model-threading" -// NO-COMPONENT-MODEL-THREAD-CONTEXT: "-target-feature" "-component-model-threading" +// LIBCALL-THREAD-CONTEXT: "-target-feature" "+libcall-thread-context" +// NO-LIBCALL-THREAD-CONTEXT: "-target-feature" "-libcall-thread-context" diff --git a/clang/test/Driver/wasm-toolchain.c b/clang/test/Driver/wasm-toolchain.c index 2c36e488b27fb..bfe13e2922a41 100644 --- a/clang/test/Driver/wasm-toolchain.c +++ b/clang/test/Driver/wasm-toolchain.c @@ -77,13 +77,13 @@ // '-pthread' sets +atomics, +bulk-memory, +mutable-globals, +sign-ext, and --shared-memory // RUN: %clang -### --target=wasm32-unknown-unknown --sysroot=/foo %s -pthread 2>&1 \ // RUN: | FileCheck -check-prefix=PTHREAD %s -// PTHREAD: "-cc1" {{.*}} "-target-feature" "+bulk-memory" "-target-feature" "+atomics" "-target-feature" "+mutable-globals" "-target-feature" "+sign-ext" +// PTHREAD: "-cc1" {{.*}} "-target-feature" "+atomics" "-target-feature" "+bulk-memory" "-target-feature" "+mutable-globals" "-target-feature" "+sign-ext" // PTHREAD: wasm-ld{{.*}}" "--shared-memory" "-lpthread" // // '-pthread' with '-nostdlib' should still set '--shared-memory' but not include '-lpthread' // RUN: %clang -### --target=wasm32-unknown-unknown --sysroot=/foo %s -pthread -nostdlib 2>&1 \ // RUN: | FileCheck -check-prefix=PTHREAD-NOSTDLIB %s -// PTHREAD-NOSTDLIB: "-cc1" {{.*}} "-target-feature" "+bulk-memory" "-target-feature" "+atomics" "-target-feature" "+mutable-globals" "-target-feature" "+sign-ext" +// PTHREAD-NOSTDLIB: "-cc1" {{.*}} "-target-feature" "+atomics" "-target-feature" "+bulk-memory" "-target-feature" "+mutable-globals" "-target-feature" "+sign-ext" // PTHREAD-NOSTDLIB: wasm-ld{{.*}}" "--shared-memory" "-o" "a.out" // '-pthread' not allowed with '-mno-atomics' @@ -113,7 +113,7 @@ // 'wasm32-wasi-threads' does the same thing as '-pthread' // RUN: %clang -### --target=wasm32-wasi-threads --sysroot=/foo %s 2>&1 \ // RUN: | FileCheck -check-prefix=WASI_THREADS %s -// WASI_THREADS: "-cc1" {{.*}} "-target-feature" "+bulk-memory" "-target-feature" "+atomics" "-target-feature" "+mutable-globals" "-target-feature" "+sign-ext" +// WASI_THREADS: "-cc1" {{.*}} "-target-feature" "+atomics" "-target-feature" "+bulk-memory" "-target-feature" "+mutable-globals" "-target-feature" "+sign-ext" // WASI_THREADS: wasm-ld{{.*}}" "--shared-memory" "-lpthread" // '-mllvm -emscripten-cxx-exceptions-allowed=foo,bar' sets @@ -304,14 +304,14 @@ // LINK_WALI_BASIC: "-cc1" {{.*}} "-o" "[[temp:[^"]*]]" // LINK_WALI_BASIC: wasm-ld{{.*}}" "-L/foo/lib/wasm32-linux-muslwali" "crt1.o" "[[temp]]" "-lc" "{{.*[/\\]}}libclang_rt.builtins.a" "-o" "a.out" -// `wasm32-wasip3` passes `+component-model-threading` by default. +// `wasm32-wasip3` passes `+libcall-thread-context` by default. // RUN: %clang -### --target=wasm32-wasip3 --sysroot=/foo %s 2>&1 \ -// RUN: | FileCheck -check-prefix=LINK_WASIP3_THREAD_CONTEXT %s -// LINK_WASIP3_THREAD_CONTEXT: "-cc1" {{.*}} "-target-feature" "+component-model-threading" +// RUN: | FileCheck -check-prefix=LINK_WASIP3_LIBCALL_THREAD_CONTEXT %s +// LINK_WASIP3_LIBCALL_THREAD_CONTEXT: "-cc1" {{.*}} "-target-feature" "+libcall-thread-context" -// `wasm32-wasip3` does not pass `+component-model-threading` when `-mno-component-model-threading` is used. +// `wasm32-wasip3` does not pass `+libcall-thread-context` when `-mno-libcall-thread-context` is used. -// RUN: %clang -### --target=wasm32-wasip3 --sysroot=/foo -mno-component-model-threading %s 2>&1 \ -// RUN: | FileCheck -check-prefix=LINK_WASIP3_NO_THREAD_CONTEXT %s -// LINK_WASIP3_NO_THREAD_CONTEXT: "-cc1" {{.*}} "-target-feature" "-component-model-threading" +// RUN: %clang -### --target=wasm32-wasip3 --sysroot=/foo -mno-libcall-thread-context %s 2>&1 \ +// RUN: | FileCheck -check-prefix=LINK_WASIP3_NO_LIBCALL_THREAD_CONTEXT %s +// LINK_WASIP3_NO_LIBCALL_THREAD_CONTEXT: "-cc1" {{.*}} "-target-feature" "-libcall-thread-context" \ No newline at end of file diff --git a/clang/test/Preprocessor/wasm-target-features.c b/clang/test/Preprocessor/wasm-target-features.c index b81e03bb5d513..7bb9429be507b 100644 --- a/clang/test/Preprocessor/wasm-target-features.c +++ b/clang/test/Preprocessor/wasm-target-features.c @@ -253,10 +253,10 @@ // BLEEDING-EDGE-NO-SIMD128-NOT: #define __wasm_simd128__ 1{{$}} // RUN: %clang -E -dM %s -o - 2>&1 \ -// RUN: -target wasm32-unknown-unknown -mcomponent-model-threading \ -// RUN: | FileCheck %s -check-prefix=COMPONENT-MODEL-THREAD-CONTEXT +// RUN: -target wasm32-unknown-unknown -mlibcall-thread-context \ +// RUN: | FileCheck %s -check-prefix=LIBCALL-THREAD-CONTEXT // RUN: %clang -E -dM %s -o - 2>&1 \ -// RUN: -target wasm64-unknown-unknown -mcomponent-model-threading \ -// RUN: | FileCheck %s -check-prefix=COMPONENT-MODEL-THREAD-CONTEXT +// RUN: -target wasm64-unknown-unknown -mlibcall-thread-context \ +// RUN: | FileCheck %s -check-prefix=LIBCALL-THREAD-CONTEXT -// COMPONENT-MODEL-THREAD-CONTEXT: #define __wasm_component_model_threading__ 1{{$}} +// LIBCALL-THREAD-CONTEXT: #define __wasm_libcall_thread_context__ 1{{$}} diff --git a/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt index 2007899ffb3df..e64e6b70366e4 100644 --- a/compiler-rt/lib/builtins/CMakeLists.txt +++ b/compiler-rt/lib/builtins/CMakeLists.txt @@ -903,7 +903,6 @@ set(s390x_SOURCES set(wasm_SOURCES - wasm/thread_context.c ${GENERIC_TF_SOURCES} ${GENERIC_SOURCES} ) diff --git a/compiler-rt/lib/builtins/wasm/thread_context.c b/compiler-rt/lib/builtins/wasm/thread_context.c deleted file mode 100644 index d5326f0ea8ae9..0000000000000 --- a/compiler-rt/lib/builtins/wasm/thread_context.c +++ /dev/null @@ -1,61 +0,0 @@ -//===-- thread_context.c - Provide access to stack pointer and TLS base ---===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements __wasm_get_{stack_pointer,tls_base} and -// __wasm_set_{stack_pointer,tls_base}, which are used for accessing the -// component model thread context. -// -//===----------------------------------------------------------------------===// - -#ifdef __wasm_component_model_threading__ - -// We define these function as naked functions with inline assembly because: -// 1. Defining them as regular C functions would cause infinite recursion in -// the prologue/epilogue code that accesses the stack pointer. -// 2. The compiler-rt build system doesn't pass the target triple when compiling -// assembly files, and making it do so would require a non-trivial amount of -// build system changes. - -__attribute__((naked)) void *__wasm_get_stack_pointer(void) { - __asm__ volatile( - ".functype __wasm_component_model_builtin_context_get_0 () -> (i32)\n" - ".import_module __wasm_component_model_builtin_context_get_0, \"$root\"\n" - ".import_name __wasm_component_model_builtin_context_get_0, " - "\"[context-get-0]\"\n" - "call __wasm_component_model_builtin_context_get_0"); -} - -__attribute__((naked)) void __wasm_set_stack_pointer(void *ptr) { - __asm__ volatile( - ".functype __wasm_component_model_builtin_context_set_0 (i32) -> ()\n" - ".import_module __wasm_component_model_builtin_context_set_0, \"$root\"\n" - ".import_name __wasm_component_model_builtin_context_set_0, " - "\"[context-set-0]\"\n" - "local.get 0\n" - "call __wasm_component_model_builtin_context_set_0"); -} - -__attribute__((naked)) void *__wasm_get_tls_base(void) { - __asm__ volatile( - ".functype __wasm_component_model_builtin_context_get_1 () -> (i32)\n" - ".import_module __wasm_component_model_builtin_context_get_1, \"$root\"\n" - ".import_name __wasm_component_model_builtin_context_get_1, " - "\"[context-get-1]\"\n" - "call __wasm_component_model_builtin_context_get_1"); -} -__attribute__((naked)) void __wasm_set_tls_base(void *ptr) { - __asm__ volatile( - ".functype __wasm_component_model_builtin_context_set_1 (i32) -> ()\n" - ".import_module __wasm_component_model_builtin_context_set_1, \"$root\"\n" - ".import_name __wasm_component_model_builtin_context_set_1, " - "\"[context-set-1]\"\n" - "local.get 0\n" - "call __wasm_component_model_builtin_context_set_1"); -} - -#endif diff --git a/lld/test/wasm/stack-pointer-abi.s b/lld/test/wasm/stack-pointer-abi.s index 492c7e5c08078..c77d9fe55c523 100644 --- a/lld/test/wasm/stack-pointer-abi.s +++ b/lld/test/wasm/stack-pointer-abi.s @@ -2,8 +2,8 @@ # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/use.o %t/use.s # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/disallow.o %t/disallow.s # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/start.o %t/start.s -# RUN: wasm-ld -o %t/component-model.wasm %t/use.o %t/start.o -# RUN: obj2yaml %t/component-model.wasm | FileCheck %s --check-prefix=COMPONENT-MODEL +# RUN: wasm-ld -o %t/libcall.wasm %t/use.o %t/start.o +# RUN: obj2yaml %t/libcall.wasm | FileCheck %s --check-prefix=LIBCALL # RUN: wasm-ld -o %t/global.wasm %t/disallow.o %t/start.o # RUN: obj2yaml %t/global.wasm | FileCheck %s --check-prefix=GLOBAL @@ -17,16 +17,16 @@ _start: .section .custom_section.target_features,"",@ .int8 1 .int8 45 - .int8 30 - .ascii "component-model-threading" + .int8 22 + .ascii "libcall-thread-context" #--- use.s .section .custom_section.target_features,"",@ .int8 1 .int8 43 - .int8 30 - .ascii "component-model-threading" + .int8 2 + .ascii "libcall-thread-context" -# COMPONENT-MODEL: Name: __init_stack_pointer +# LIBCALL: Name: __init_stack_pointer # GLOBAL: Name: __stack_pointer diff --git a/lld/test/wasm/thread-context-abi-mismatch.s b/lld/test/wasm/thread-context-abi-mismatch.s index 817c703ada7dc..efc1230b5768e 100644 --- a/lld/test/wasm/thread-context-abi-mismatch.s +++ b/lld/test/wasm/thread-context-abi-mismatch.s @@ -4,19 +4,19 @@ # Test that the presence of an import of __stack_pointer from the env module is treated # as an indication that the global thread context ABI is being used, even if the -# component-model-threading feature is not disallowed. +# libcall-thread-context feature is not disallowed. # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/start.o %t/start.s # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/stack-pointer.o %t/stack-pointer.s # RUN: not wasm-ld %t/start.o %t/stack-pointer.o -o %t/fail.wasm 2>&1 | FileCheck %s -# Test that explicitly disallowing the component-model-threading feature causes linking to fail +# Test that explicitly disallowing the libcall-thread-context feature causes linking to fail # with an error when other files use the feature. # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/disallow.o %t/disallow.s # RUN: not wasm-ld %t/start.o %t/disallow.o -o %t/fail.wasm 2>&1 | FileCheck %s -# CHECK: error: thread context ABI mismatch: {{.*}} disallows component-model-threading but other files use it +# CHECK: error: thread context ABI mismatch: {{.*}} disallows libcall-thread-context but other files use it #--- start.s .globl _start @@ -28,8 +28,8 @@ _start: .section .custom_section.target_features,"",@ .int8 1 .int8 43 - .int8 30 - .ascii "component-model-threading" + .int8 22 + .ascii "libcall-thread-context" #--- stack-pointer.s .globaltype __stack_pointer, i32 @@ -48,5 +48,5 @@ _start: .section .custom_section.target_features,"",@ .int8 1 .int8 45 - .int8 30 - .ascii "component-model-threading" + .int8 22 + .ascii "libcall-thread-context" diff --git a/lld/test/wasm/tls-component-model.s b/lld/test/wasm/tls-libcall.s similarity index 97% rename from lld/test/wasm/tls-component-model.s rename to lld/test/wasm/tls-libcall.s index 1e1292f91b0d7..67addd5649b2c 100644 --- a/lld/test/wasm/tls-component-model.s +++ b/lld/test/wasm/tls-libcall.s @@ -34,8 +34,8 @@ tls2: .section .custom_section.target_features,"",@ .int8 2 .int8 43 - .int8 30 - .ascii "component-model-threading" + .int8 22 + .ascii "libcall-thread-context" .int8 43 .int8 11 .ascii "bulk-memory" diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h index 760877acd9913..845c40d36146f 100644 --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -135,13 +135,6 @@ struct Config { llvm::SmallVector buildIdVector; }; -enum class ThreadModel { - Single, - SharedMemory, - // Used by WASIp3 targets - Cooperative, -}; - // The Ctx object hold all other (non-configuration) global state. struct Ctx { Config arg; @@ -262,11 +255,11 @@ struct Ctx { TableSymbol *indirectFunctionTable; // __wasm_set_tls_base - // Function used to set TLS base in component model modules. + // Function used to set TLS base in libcall thread context modules. UndefinedFunction *setTLSBase; // __wasm_get_tls_base - // Function used to get TLS base in component model modules. + // Function used to get TLS base in libcall thread context modules. UndefinedFunction *getTLSBase; }; WasmSym sym; @@ -287,19 +280,12 @@ struct Ctx { 0> whyExtractRecords; - // Whether to use compiler-rt functions for the stack pointer and TLS base + // Whether to use library functions for the stack pointer and TLS base // instead of globals. This is currently used for WASIp3 cooperative threads support. - bool externThreadBuiltins = false; - - // The thread model to use for tuning linker-generated code, segment passivity, etc. - ThreadModel threadModel = ThreadModel::Single; + bool libcallThreadContext = false; Ctx(); void reset(); - - bool isMultithreaded() const { - return threadModel != ThreadModel::Single; - } }; extern Ctx ctx; diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 71b1412548c4e..e7b443c01765e 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -966,14 +966,20 @@ static void createPostLTOSymbols() { bool is64 = ctx.arg.is64.value_or(false); - auto stack_pointer_name = ctx.externThreadBuiltins + auto stack_pointer_name = ctx.libcallThreadContext ? "__init_stack_pointer" : "__stack_pointer"; if (ctx.isPic) { - ctx.sym.stackPointer = + if (ctx.libcallThreadContext) { + ctx.sym.stackPointer = createUndefinedGlobal(stack_pointer_name, ctx.arg.is64.value_or(false) - ? &mutableGlobalTypeI64 - : &mutableGlobalTypeI32); + ? &globalTypeI64 + : &globalTypeI32); + } + else { + ctx.sym.stackPointer = 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. @@ -987,16 +993,16 @@ static void createPostLTOSymbols() { } else { // For non-PIC code ctx.sym.stackPointer = createGlobalVariable( - stack_pointer_name, !ctx.externThreadBuiltins); + stack_pointer_name, !ctx.libcallThreadContext); ctx.sym.stackPointer->markLive(); } - if (ctx.isMultithreaded()) { + if (ctx.arg.sharedMemory) { // TLS symbols are all hidden/dso-local auto tls_base_name = - ctx.externThreadBuiltins ? "__init_tls_base" : "__tls_base"; + ctx.libcallThreadContext ? "__init_tls_base" : "__tls_base"; ctx.sym.tlsBase = - createGlobalVariable(tls_base_name, !ctx.externThreadBuiltins, + createGlobalVariable(tls_base_name, !ctx.libcallThreadContext, WASM_SYMBOL_VISIBILITY_HIDDEN); ctx.sym.tlsSize = createGlobalVariable("__tls_size", false, WASM_SYMBOL_VISIBILITY_HIDDEN); @@ -1006,7 +1012,7 @@ static void createPostLTOSymbols() { "__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN, make(is64 ? i64ArgSignature : i32ArgSignature, "__wasm_init_tls")); - if (ctx.externThreadBuiltins) { + if (ctx.libcallThreadContext) { ctx.sym.tlsBase->markLive(); ctx.sym.tlsSize->markLive(); ctx.sym.tlsAlign->markLive(); @@ -1317,14 +1323,14 @@ static void checkZOptions(opt::InputArgList &args) { static void determineThreadContextABI(ArrayRef files) { // A complication is that a user may attempt to link together object files // compiled with different versions of LLVM, where one does not specifiy - // -component-model-threading when using the global thread context ABI. + // -libcall-thread-context when using the global thread context ABI. // They may also attempt to link object files with the global ABI compiled // with older LLVM versions, but link them with a newer wasm-ld. To ensure the // correct behavior in both of these cases, we treat the import of a // __stack_pointer global from the env module as an indication that the global // thread context ABI is being used. - enum class ThreadContextABI { Undetermined, ComponentModelBuiltins, Globals }; + enum class ThreadContextABI { Undetermined, Libcall, Globals }; ThreadContextABI threadContextABI = ThreadContextABI::Undetermined; @@ -1332,10 +1338,10 @@ static void determineThreadContextABI(ArrayRef files) { auto targetFeatures = obj->getWasmObj()->getTargetFeatures(); auto threadContextFeature = llvm::find_if(targetFeatures, [](const auto &f) { - return f.Name == "component-model-threading"; + return f.Name == "libcall-thread-context"; }); - bool usesComponentModelThreading = + bool usesLibcallThreadContext = threadContextFeature != targetFeatures.end() && threadContextFeature->Prefix == WASM_FEATURE_PREFIX_USED; @@ -1356,16 +1362,16 @@ static void determineThreadContextABI(ArrayRef files) { continue; } // Treat this as using the globals ABI - usesComponentModelThreading = false; + usesLibcallThreadContext = false; } - if (usesComponentModelThreading) { + if (usesLibcallThreadContext) { if (threadContextABI == ThreadContextABI::Undetermined) { - threadContextABI = ThreadContextABI::ComponentModelBuiltins; - } else if (threadContextABI != ThreadContextABI::ComponentModelBuiltins) { + threadContextABI = ThreadContextABI::Libcall; + } else if (threadContextABI != ThreadContextABI::Libcall) { error( "thread context ABI mismatch: " + obj->getName() + - " uses component-model-threading but other files disallow it"); + " uses libcall-thread-context but other files disallow it"); } } else { if (threadContextABI == ThreadContextABI::Undetermined) { @@ -1373,19 +1379,14 @@ static void determineThreadContextABI(ArrayRef files) { } else if (threadContextABI != ThreadContextABI::Globals) { error( "thread context ABI mismatch: " + obj->getName() + - " disallows component-model-threading but other files use it"); + " disallows libcall-thread-context but other files use it"); } } } // If the ABI is undetermined at this point, default to the globals ABI - if (threadContextABI == ThreadContextABI::ComponentModelBuiltins) { - if (ctx.arg.sharedMemory) { - error("--shared-memory is currently incompatible with component model " - "thread context intrinsics"); - } - ctx.externThreadBuiltins = true; - ctx.threadModel = ThreadModel::Cooperative; + if (threadContextABI == ThreadContextABI::Libcall) { + ctx.libcallThreadContext = true; } } diff --git a/lld/wasm/Relocations.cpp b/lld/wasm/Relocations.cpp index d10132fa22bac..a1840abe88b3a 100644 --- a/lld/wasm/Relocations.cpp +++ b/lld/wasm/Relocations.cpp @@ -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.isMultithreaded()) { + if (ctx.arg.sharedMemory) { if (!sym->isTLS()) { error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) + diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index aaba30ece3b1e..4c30fc26d54fb 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -53,7 +53,7 @@ class SubSection { }; void writeGetTLSBase(const Ctx &ctx, raw_ostream &os) { - if (ctx.externThreadBuiltins) { + if (ctx.libcallThreadContext) { writeU8(os, WASM_OPCODE_CALL, "call"); writeUleb128(os, ctx.sym.getTLSBase->getFunctionIndex(), "function index"); } else { @@ -531,7 +531,7 @@ void GlobalSection::writeBody() { mutable_ = true; // With multi-threading any TLS globals must be mutable since they get // set during `__wasm_apply_global_tls_relocs` - if (ctx.isMultithreaded() && sym->isTLS()) + if (ctx.arg.sharedMemory && sym->isTLS()) mutable_ = true; } WasmGlobalType type{itype, mutable_}; @@ -568,11 +568,10 @@ void GlobalSection::writeBody() { } else { WasmInitExpr initExpr; if (auto *d = dyn_cast(sym)) - // In the multi-threaded case, TLS globals are set during - // `__wasm_apply_global_tls_relocs`, but in the non-multi-threaded case + // In the sharedMemory case TLS globals are set during + // `__wasm_apply_global_tls_relocs`, but in the non-shared case // we know the absolute value at link time. - initExpr = - intConst(d->getVA(/*absolute=*/!ctx.isMultithreaded()), is64); + initExpr = intConst(d->getVA(/*absolute=*/!ctx.arg.sharedMemory), is64); else if (auto *f = dyn_cast(sym)) initExpr = intConst(f->isStub ? 0 : f->getTableIndex(), is64); else { @@ -680,7 +679,7 @@ bool DataCountSection::isNeeded() const { // instructions are not yet supported in input files. However, in the case // of shared memory, lld itself will generate these instructions as part of // `__wasm_init_memory`. See Writer::createInitMemoryFunction. - return numSegments && ctx.isMultithreaded(); + return numSegments && ctx.arg.sharedMemory; } void LinkingSection::writeBody() { diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index d196e4987f617..e3b510e78e5df 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -124,7 +124,7 @@ class Writer { }; void writeSetTLSBase(const Ctx &ctx, raw_ostream &os) { - if (ctx.externThreadBuiltins) { + if (ctx.libcallThreadContext) { writeU8(os, WASM_OPCODE_CALL, "call"); writeUleb128(os, ctx.sym.setTLSBase->getFunctionIndex(), "function index"); } else { @@ -659,14 +659,10 @@ void Writer::populateTargetFeatures() { } if (tlsUsed) { - if (!allowed.contains("bulk-memory")) { - error("bulk-memory feature must be used in order to use thread-local " - "storage"); - } - if (ctx.threadModel == ThreadModel::SharedMemory && !allowed.contains("atomics")) { - error( - "atomics feature must be used in order to use thread-local storage"); - } + for (auto feature : {"atomics", "bulk-memory"}) + if (!allowed.contains(feature)) + error(StringRef("'") + feature + + "' feature must be used in order to use thread-local storage"); } // Validate that used features are allowed in output @@ -1044,15 +1040,7 @@ static StringRef getOutputDataSegmentName(const InputChunk &seg) { OutputSegment *Writer::createOutputSegment(StringRef name) { LLVM_DEBUG(dbgs() << "new segment: " << name << "\n"); OutputSegment *s = make(name); - // In the shared memory case, all data segments must be passive since they - // will be initialized once by the main thread and then shared with other - // threads. In the non-shared memory case, we use passive segments only for - // TLS segments, so that they can be reused, and for .bss segments, which - // don't need to be included in the binary at all. - bool needsPassiveInit = ctx.threadModel == ThreadModel::SharedMemory || - (ctx.threadModel == ThreadModel::Cooperative && - (s->isTLS() || s->name.starts_with(".bss"))); - if (needsPassiveInit) + if (ctx.arg.sharedMemory) s->initFlags = WASM_DATA_SEGMENT_IS_PASSIVE; if (!ctx.arg.relocatable && name.starts_with(".bss")) s->isBss = true; @@ -1177,10 +1165,10 @@ void Writer::createSyntheticInitFunctions() { createApplyDataRelocationsFunction(); // Passive segments are used to avoid memory being reinitialized on each - // thread's instantiation for wasi-threads, and for TLS when using cooperative - // threads. These passive segments are initialized and dropped in - // __wasm_init_memory, which is registered as the start function. We also - // initialize bss segments (using memory.fill) as part of this function. + // thread's instantiation. These passive segments are initialized and + // dropped in __wasm_init_memory, which is registered as the start function + // We also initialize bss segments (using memory.fill) as part of this + // function. if (hasPassiveInitializedSegments()) { ctx.sym.initMemory = symtab->addSyntheticFunction( "__wasm_init_memory", WASM_SYMBOL_VISIBILITY_HIDDEN, @@ -1193,17 +1181,15 @@ void Writer::createSyntheticInitFunctions() { } } - if (ctx.isMultithreaded()) { + if (ctx.arg.sharedMemory) { if (out.globalSec->needsTLSRelocations()) { ctx.sym.applyGlobalTLSRelocs = symtab->addSyntheticFunction( "__wasm_apply_global_tls_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN, make(nullSignature, "__wasm_apply_global_tls_relocs")); ctx.sym.applyGlobalTLSRelocs->markLive(); - // Shared memory TLS relocations depend on the __tls_base symbols - if (ctx.arg.sharedMemory) { - ctx.sym.tlsBase->markLive(); - } + // TLS relocations depend on the __tls_base symbols + ctx.sym.tlsBase->markLive(); } auto hasTLSRelocs = [](const OutputSegment *segment) { @@ -1372,10 +1358,10 @@ void Writer::createInitMemoryFunction() { "i32.add"); } - // When we initialize the TLS segment we also set the `__tls_base` - // global/context.get(1). This allows the runtime to use this + // When we initialize the TLS segment we also set the TLS base. + // This allows the runtime to use this // static copy of the TLS data for the first/main thread. - if (ctx.isMultithreaded() && s->isTLS()) { + if (ctx.arg.sharedMemory && s->isTLS()) { if (ctx.isPic) { // Cache the result of the addionion in local 0 writeU8(os, WASM_OPCODE_LOCAL_TEE, "local.tee"); @@ -1446,7 +1432,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.isMultithreaded() && s->isTLS()) + if (ctx.arg.sharedMemory && s->isTLS()) continue; // data.drop instruction writeU8(os, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix"); @@ -1653,13 +1639,14 @@ void Writer::createInitTLSFunction() { writeUleb128(os, 0, "num locals"); if (tlsSeg) { - // When using WASIp3 cooperative threading, we don't set the TLS base - // inside __init_tls; this should be done as part of the thread startup - // stub. - if (ctx.threadModel != ThreadModel::Cooperative) { - writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); - writeUleb128(os, 0, "local index"); + writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); + writeUleb128(os, 0, "local index"); + if (ctx.libcallThreadContext) { + writeU8(os, WASM_OPCODE_CALL, "call"); + writeUleb128(os, ctx.sym.setTLSBase->getFunctionIndex(), "function index"); + } + else { writeU8(os, WASM_OPCODE_GLOBAL_SET, "global.set"); writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "global index"); } diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h index d85de9cc8b339..be42618eea5a4 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -108,8 +108,8 @@ enum TOF { MO_MEMORY_BASE_REL, // On a symbol operand this indicates that the immediate is the symbol - // address relative to the TLS base. This is stored in context.get(1) - // when using the component model thread context, and the __tls_base global + // address relative to the TLS base. This is retrieved through __wasm_get_tls_base() + // when using libcall thread context, and the __tls_base global // otherwise. Only applicable to data symbols. MO_TLS_BASE_REL, diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.td b/llvm/lib/Target/WebAssembly/WebAssembly.td index 54ecf92a51b94..187f99e9df07d 100644 --- a/llvm/lib/Target/WebAssembly/WebAssembly.td +++ b/llvm/lib/Target/WebAssembly/WebAssembly.td @@ -37,9 +37,9 @@ def FeatureCallIndirectOverlong : SubtargetFeature<"call-indirect-overlong", "HasCallIndirectOverlong", "true", "Enable overlong encoding for call_indirect immediates">; -def FeatureComponentModelThreading : - SubtargetFeature<"component-model-threading", "HasComponentModelThreading", "true", - "Enable component model thread context intrinsics">; +def FeatureLibcallThreadContext : + SubtargetFeature<"libcall-thread-context", "HasLibcallThreadContext", "true", + "Enable using library calls for managing thread context">; def FeatureExceptionHandling : SubtargetFeature<"exception-handling", "HasExceptionHandling", "true", diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index 4f129fae7bddd..e3b6c2e29555e 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -135,11 +135,11 @@ bool WebAssemblyFrameLowering::needsSPForLocalFrame( any_of(MRI.use_operands(getSPReg(MF)), [](MachineOperand &MO) { return !MO.isImplicit(); }); - // With component model thread context, we need SP in the prolog when debug + // With libcall thread context, we need SP in the prolog when debug // info is present so we can allocate a local for DWARF to reference. bool NeedsSPForDebug = MF.getFunction().getSubprogram() && - MF.getSubtarget().hasComponentModelThreading(); + MF.getSubtarget().hasLibcallThreadContext(); return MFI.getStackSize() || MFI.adjustsStack() || hasFP(MF) || HasExplicitSPUse || NeedsSPForDebug; @@ -157,7 +157,7 @@ bool WebAssemblyFrameLowering::needsPrologForEH( /// Returns true if this function needs a local user-space stack pointer. /// Unlike a machine stack pointer, the wasm user stack pointer is a global -/// variable or stored in the component model thread context, so it is loaded +/// variable or managed by library calls, so it is loaded /// into a register in the prolog. bool WebAssemblyFrameLowering::needsSP(const MachineFunction &MF) const { return needsSPForLocalFrame(MF) || needsPrologForEH(MF); @@ -240,7 +240,7 @@ void WebAssemblyFrameLowering::writeBackSP( const auto *TII = MF.getSubtarget().getInstrInfo(); if (MF.getSubtarget() - .hasComponentModelThreading()) { + .hasLibcallThreadContext()) { const char *ES = "__wasm_set_stack_pointer"; auto *SPSymbol = MF.createExternalSymbolName(ES); BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::CALL)) @@ -299,7 +299,7 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, if (StackSize) SPReg = MRI.createVirtualRegister(PtrRC); - if (ST.hasComponentModelThreading()) { + if (ST.hasLibcallThreadContext()) { const char *ES = "__wasm_get_stack_pointer"; auto *SPSymbol = MF.createExternalSymbolName(ES); BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CALL), SPReg) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h index 98133d48a9eaa..f836f4e95a93b 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/context.set). + /// global/__wasm_set_stack_pointer). // TODO: (ABI) Revisit and decide how large it should be. static const size_t RedZoneSize = 128; @@ -47,7 +47,7 @@ class WebAssemblyFrameLowering final : public TargetFrameLowering { bool needsPrologForEH(const MachineFunction &MF) const; - /// Write SP back to __stack_pointer global or context.set. + /// Write SP back to __stack_pointer global, or call __wasm_set_stack_pointer. void writeBackSP(unsigned SrcReg, MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator &InsertStore, const DebugLoc &DL) const; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index c56877c5bfaa0..89c5761b2f64b 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -2054,7 +2054,7 @@ WebAssemblyTargetLowering::LowerGlobalTLSAddress(SDValue Op, (model == GlobalValue::GeneralDynamicTLSModel && getTargetMachine().shouldAssumeDSOLocal(GV))) { // For DSO-local TLS variables we use offset from __tls_base, or - // context.get(1) if using component model threading intrinsics. + // __wasm_get_tls_base() if using libcall thread context. MVT PtrVT = getPointerTy(DAG.getDataLayout()); SDValue BaseAddr(WebAssembly::getTLSBase(DAG, DL, Subtarget), 0); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td index fe6b0a6a0fb31..9f9e39aa17d3c 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -38,11 +38,6 @@ def HasCallIndirectOverlong : Predicate<"Subtarget->hasCallIndirectOverlong()">, AssemblerPredicate<(all_of FeatureCallIndirectOverlong), "call-indirect-overlong">; -def HasComponentModelThreading : - Predicate<"Subtarget->hasComponentModelThreading()">, - AssemblerPredicate<(all_of FeatureComponentModelThreading), - "component-model-threading">; - def HasExceptionHandling : Predicate<"Subtarget->hasExceptionHandling()">, AssemblerPredicate<(all_of FeatureExceptionHandling), "exception-handling">; @@ -58,6 +53,11 @@ def HasFP16 : def HasGC : Predicate<"Subtarget->hasGC()">, AssemblerPredicate<(all_of FeatureGC), "gc">; +def HasLibcallThreadContext : + Predicate<"Subtarget->hasLibcallThreadContext()">, + AssemblerPredicate<(all_of FeatureLibcallThreadContext), + "libcall-thread-context">; + def HasMultiMemory : Predicate<"Subtarget->hasMultiMemory()">, AssemblerPredicate<(all_of FeatureMultiMemory), "multimemory">; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp index 74a8d5a775d2c..771aa5187d0d2 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp @@ -377,8 +377,8 @@ bool WebAssemblyLateEHPrepare::removeUnnecessaryUnreachables( } // After the stack is unwound due to a thrown exception, the __stack_pointer -// global/context.get(0) can point to an invalid address. This inserts -// instructions that restore the stack pointer state.. +// global/__wasm_get_stack_pointer() can point to an invalid address. This inserts +// instructions that restore the stack pointer state. bool WebAssemblyLateEHPrepare::restoreStackPointer(MachineFunction &MF) { const auto *FrameLowering = static_cast( MF.getSubtarget().getFrameLowering()); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp index 89478b20f035a..179d5dc89603a 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp @@ -40,13 +40,13 @@ WebAssemblySubtarget::initializeSubtargetDependencies(StringRef CPU, ParseSubtargetFeatures(CPU, /*TuneCPU*/ CPU, FS); - // WASIP3 implies using the component model thread context intrinsics by + // WASIP3 implies using the libcall thread context by // default, unless explicitly disabled. - if (!FS.contains("component-model-threading") && - !HasComponentModelThreading && + if (!FS.contains("libcall-thread-context") && + !HasLibcallThreadContext && TargetTriple.getOS() == Triple::WASIp3) { - ToggleFeature(WebAssembly::FeatureComponentModelThreading); - HasComponentModelThreading = true; + ToggleFeature(WebAssembly::FeatureLibcallThreadContext); + HasLibcallThreadContext = true; } FeatureBitset Bits = getFeatureBits(); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h index 4d711383a1b35..5c6f4cb5b36ff 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h @@ -48,11 +48,11 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo { bool HasBulkMemoryOpt = false; bool HasCallIndirectOverlong = false; bool HasCompactImports = false; - bool HasComponentModelThreading = false; bool HasExceptionHandling = false; bool HasExtendedConst = false; bool HasFP16 = false; bool HasGC = false; + bool HasLibcallThreadContext = false; bool HasMultiMemory = false; bool HasMultivalue = false; bool HasMutableGlobals = false; @@ -113,13 +113,11 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo { bool hasBulkMemoryOpt() const { return HasBulkMemoryOpt; } bool hasCallIndirectOverlong() const { return HasCallIndirectOverlong; } bool hasCompactImports() const { return HasCompactImports; } - bool hasComponentModelThreading() const { - return HasComponentModelThreading; - } bool hasExceptionHandling() const { return HasExceptionHandling; } bool hasExtendedConst() const { return HasExtendedConst; } bool hasFP16() const { return HasFP16; } bool hasGC() const { return HasGC; } + bool hasLibcallThreadContext() const { return HasLibcallThreadContext; } bool hasMultiMemory() const { return HasMultiMemory; } bool hasMultivalue() const { return HasMultivalue; } bool hasMutableGlobals() const { return HasMutableGlobals; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index 6418d0d26f00f..b30738bb77047 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -261,9 +261,7 @@ 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, unless the target - // is using component model threading intrinsics which allow thread local - // storage without atomics, in which case only strip atomics. + // also strip atomic operations and thread local storage. static char ID; WebAssemblyTargetMachine *WasmTM; @@ -282,31 +280,19 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { bool StrippedAtomics = false; bool StrippedTLS = false; - if (Features[WebAssembly::FeatureComponentModelThreading]) { - // Using component model threading intrinsics allows TLS without - // atomics, so don't strip TLS even if atomics are disabled. - if (!Features[WebAssembly::FeatureAtomics]) { - StrippedAtomics = stripAtomics(M); - } - if (!Features[WebAssembly::FeatureBulkMemory]) { - StrippedTLS = stripThreadLocals(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 (!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); - recordFeatures(M, WasmTM->getTargetCPU(), Features, - StrippedAtomics || StrippedTLS); + recordFeatures(M, WasmTM->getTargetCPU(), Features, StrippedAtomics || StrippedTLS); // Conservatively assume we have made some change return true; @@ -429,13 +415,13 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { wasm::WASM_FEATURE_PREFIX_DISALLOWED); } - // Mark component-model-threading as disallowed when not in use to + // Mark libcall-thread-context as disallowed when not in use to // prevent linking object files with incompatible threading ABIs. // This is implicit for MVP since the feature is not supported at all. if (CPU != "mvp" && - !Features[WebAssembly::FeatureComponentModelThreading]) { + !Features[WebAssembly::FeatureLibcallThreadContext]) { M.addModuleFlag(Module::ModFlagBehavior::Error, - "wasm-feature-component-model-threading", + "wasm-feature-libcall-thread-context", wasm::WASM_FEATURE_PREFIX_DISALLOWED); } } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index d01821269e667..ac8df67fe7557 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -202,7 +202,7 @@ MachineSDNode *WebAssembly::getTLSBase(SelectionDAG &DAG, const SDLoc &DL, unsigned Opcode; const char *SymName; - if (Subtarget->hasComponentModelThreading()) { + if (Subtarget->hasLibcallThreadContext()) { Opcode = WebAssembly::CALL; SymName = "__wasm_get_tls_base"; } else { diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h index 9bb0fb4cc35d3..0827791d93657 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h @@ -78,8 +78,8 @@ bool canLowerMultivalueReturn(const WebAssemblySubtarget *Subtarget); bool canLowerReturn(size_t ResultSize, const WebAssemblySubtarget *Subtarget); // Get the TLS base value for the current target -// If using component model threading intrinsics: calls -// __wasm_get_tls_base, otherwise: global.get __tls_base +// If using libcall thread context, calls +// __wasm_get_tls_base, otherwise, global.get __tls_base MachineSDNode *getTLSBase(SelectionDAG &DAG, const SDLoc &DL, const WebAssemblySubtarget *Subtarget, const SDValue Chain = SDValue()); diff --git a/llvm/test/CodeGen/WebAssembly/stack-abi.ll b/llvm/test/CodeGen/WebAssembly/stack-abi.ll index bbdcb7c15f09f..2cd6089dd5d65 100644 --- a/llvm/test/CodeGen/WebAssembly/stack-abi.ll +++ b/llvm/test/CodeGen/WebAssembly/stack-abi.ll @@ -1,5 +1,5 @@ -; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+component-model-threading | FileCheck --check-prefix=CMTC %s -; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=-component-model-threading | FileCheck --check-prefix=GLOBAL %s +; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+libcall-thread-context | FileCheck --check-prefix=LIBCALL %s +; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=-libcall-thread-context | FileCheck --check-prefix=GLOBAL %s declare void @force_sp_save() define void @use_stack() #0 { @@ -10,11 +10,11 @@ define void @use_stack() #0 { ret void } -; CMTC-LABEL: use_stack: -; CMTC: call __wasm_get_stack_pointer -; CMTC: call __wasm_set_stack_pointer -; CMTC-NOT: global.get __stack_pointer -; CMTC-NOT: global.set __stack_pointer +; LIBCALL-LABEL: use_stack: +; LIBCALL: call __wasm_get_stack_pointer +; LIBCALL: call __wasm_set_stack_pointer +; LIBCALL-NOT: global.get __stack_pointer +; LIBCALL-NOT: global.set __stack_pointer ; GLOBAL-LABEL: use_stack: ; GLOBAL: global.get __stack_pointer diff --git a/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll b/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll index d6afbe613452e..cf3b3fc5a2f4a 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll @@ -53,7 +53,7 @@ attributes #2 = { "target-features"="+reference-types" } ; CHECK: i32.store ; Features in function attributes: -; +atomics, +nontrapping-fptoint, +reference-types, -component-model-threading +; +atomics, +nontrapping-fptoint, +reference-types, -libcall-thread-context ; CHECK-LABEL: .custom_section.target_features,"",@ ; CHECK-NEXT: .int8 4 ; CHECK-NEXT: .int8 43 @@ -70,7 +70,7 @@ attributes #2 = { "target-features"="+reference-types" } ; CHECK-NEXT: .ascii "reference-types" ; Features in function attributes + features specified by -mattr= option: -; +atomics, +nontrapping-fptoint, +reference-types, +simd128, -component-model-threading +; +atomics, +nontrapping-fptoint, +reference-types, +simd128, -libcall-thread-context ; SIMD128-LABEL: .custom_section.target_features,"",@ ; SIMD128-NEXT: .int8 5 ; SIMD128-NEXT: .int8 43 diff --git a/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll b/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll index 21bc5212beb39..3123cd9ce71e6 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll @@ -12,7 +12,7 @@ target triple = "wasm32-unknown-unknown" ; mvp: should not contain the target features section ; MVP-NOT: .custom_section.target_features,"",@ -; generic: +call-indirect-overlong, +multivalue, +mutable-globals, +reference-types, +sign-ext, -component-model-threading +; generic: +call-indirect-overlong, +multivalue, +mutable-globals, +reference-types, +sign-ext, -libcall-thread-context ; GENERIC-LABEL: .custom_section.target_features,"",@ ; GENERIC-NEXT: .int8 9 ; GENERIC-NEXT: .int8 43 @@ -25,8 +25,8 @@ target triple = "wasm32-unknown-unknown" ; GENERIC-NEXT: .int8 22 ; GENERIC-NEXT: .ascii "call-indirect-overlong" ; GENERIC-NEXT: .int8 45 -; GENERIC-NEXT: .int8 30 -; GENERIC-NEXT: .ascii "component-model-threading" +; GENERIC-NEXT: .int8 22 +; GENERIC-NEXT: .ascii "libcall-thread-context" ; GENERIC-NEXT: .int8 43 ; GENERIC-NEXT: .int8 10 ; GENERIC-NEXT: .ascii "multivalue" @@ -44,7 +44,7 @@ target triple = "wasm32-unknown-unknown" ; GENERIC-NEXT: .ascii "sign-ext" ; lime1: +bulk-memory-opt, +call-indirect-overlong, +extended-const, +multivalue, -; +mutable-globals, +nontrapping-fptoint, +sign-ext, -component-model-threading +; +mutable-globals, +nontrapping-fptoint, +sign-ext, -libcall-thread-context ; LIME1-LABEL: .custom_section.target_features,"",@ ; LIME1-NEXT: .int8 8 ; LIME1-NEXT: .int8 43 @@ -54,8 +54,8 @@ target triple = "wasm32-unknown-unknown" ; LIME1-NEXT: .int8 22 ; LIME1-NEXT: .ascii "call-indirect-overlong" ; LIME1-NEXT: .int8 45 -; LIME1-NEXT: .int8 30 -; LIME1-NEXT: .ascii "component-model-threading" +; LIME1-NEXT: .int8 22 +; LIME1-NEXT: .ascii "libcall-thread-context" ; LIME1-NEXT: .int8 43 ; LIME1-NEXT: .int8 14 ; LIME1-NEXT: .ascii "extended-const" @@ -77,7 +77,7 @@ target triple = "wasm32-unknown-unknown" ; +extended-const, +fp16, +gc, +multimemory, +multivalue, ; +mutable-globals, +nontrapping-fptoint, +relaxed-simd, ; +reference-types, +simd128, +sign-ext, +tail-call -; -component-model-threading +; -libcall-thread-context ; BLEEDING-EDGE-LABEL: .section .custom_section.target_features,"",@ ; BLEEDING-EDGE-NEXT: .int8 18 ; BLEEDING-EDGE-NEXT: .int8 43 @@ -93,8 +93,8 @@ target triple = "wasm32-unknown-unknown" ; BLEEDING-EDGE-NEXT: .int8 22 ; BLEEDING-EDGE-NEXT: .ascii "call-indirect-overlong" ; BLEEDING-EDGE-NEXT: .int8 45 -; BLEEDING-EDGE-NEXT: .int8 30 -; BLEEDING-EDGE-NEXT: .ascii "component-model-threading" +; BLEEDING-EDGE-NEXT: .int8 22 +; BLEEDING-EDGE-NEXT: .ascii "libcall-thread-context" ; BLEEDING-EDGE-NEXT: .int8 43 ; BLEEDING-EDGE-NEXT: .int8 18 ; BLEEDING-EDGE-NEXT: .ascii "exception-handling" diff --git a/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll b/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll index 1927430af72ea..703486e1971a2 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll @@ -1,9 +1,9 @@ ; RUN: llc < %s -mtriple=wasm32-wasip3 | FileCheck %s --check-prefix=WASIP3 -; RUN: llc < %s -mtriple=wasm32-wasip3 -mattr=-component-model-threading | FileCheck %s --check-prefix=EXPLICIT-DISABLE +; RUN: llc < %s -mtriple=wasm32-wasip3 -mattr=-libcall-thread-context | FileCheck %s --check-prefix=EXPLICIT-DISABLE ; RUN: llc < %s -mtriple=wasm32-wasip1 | FileCheck %s --check-prefix=WASIP1 ; RUN: llc < %s -mtriple=wasm32-wasip2 | FileCheck %s --check-prefix=WASIP2 -; Test that wasip3 target automatically enables component-model-threading +; Test that wasip3 target automatically enables libcall-thread-context ; WASIP3: .section .custom_section.target_features,"",@ ; WASIP3-NEXT: .int8 9 @@ -17,8 +17,8 @@ ; WASIP3-NEXT: .int8 22 ; WASIP3-NEXT: .ascii "call-indirect-overlong" ; WASIP3-NEXT: .int8 43 -; WASIP3-NEXT: .int8 30 -; WASIP3-NEXT: .ascii "component-model-threading" +; WASIP3-NEXT: .int8 22 +; WASIP3-NEXT: .ascii "libcall-thread-context" ; EXPLICIT-DISABLE: .section .custom_section.target_features,"",@ ; EXPLICIT-DISABLE-NEXT: .int8 9 @@ -32,8 +32,8 @@ ; EXPLICIT-DISABLE-NEXT: .int8 22 ; EXPLICIT-DISABLE-NEXT: .ascii "call-indirect-overlong" ; EXPLICIT-DISABLE-NEXT: .int8 45 -; EXPLICIT-DISABLE-NEXT: .int8 30 -; EXPLICIT-DISABLE-NEXT: .ascii "component-model-threading" +; EXPLICIT-DISABLE-NEXT: .int8 22 +; EXPLICIT-DISABLE-NEXT: .ascii "libcall-thread-context" ; WASIP1: .section .custom_section.target_features,"",@ ; WASIP1-NEXT: .int8 9 @@ -47,8 +47,8 @@ ; WASIP1-NEXT: .int8 22 ; WASIP1-NEXT: .ascii "call-indirect-overlong" ; WASIP1-NEXT: .int8 45 -; WASIP1-NEXT: .int8 30 -; WASIP1-NEXT: .ascii "component-model-threading" +; WASIP1-NEXT: .int8 22 +; WASIP1-NEXT: .ascii "libcall-thread-context" ; WASIP2: .section .custom_section.target_features,"",@ ; WASIP2-NEXT: .int8 9 @@ -62,8 +62,8 @@ ; WASIP2-NEXT: .int8 22 ; WASIP2-NEXT: .ascii "call-indirect-overlong" ; WASIP2-NEXT: .int8 45 -; WASIP2-NEXT: .int8 30 -; WASIP2-NEXT: .ascii "component-model-threading" +; WASIP2-NEXT: .int8 22 +; WASIP2-NEXT: .ascii "libcall-thread-context" define void @test() { ret void diff --git a/llvm/test/CodeGen/WebAssembly/target-features-tls.ll b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll index f91398800822b..9be61ade178d0 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-tls.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll @@ -35,21 +35,21 @@ target triple = "wasm32-unknown-unknown" ; BULK-MEM-NEXT: .ascii "bulk-memory-opt" ; BULK-MEM-NEXT: .tbss.foo,"T",@ -; -bulk-memory,+component-model-threading +; -bulk-memory,+libcall-thread-context ; NO-BULK-MEM-CMTC-LABEL: .custom_section.target_features,"",@ ; NO-BULK-MEM-CMTC-NEXT: .int8 3 ; NO-BULK-MEM-CMTC-NEXT: .int8 43 ; NO-BULK-MEM-CMTC-NEXT: .int8 7 ; NO-BULK-MEM-CMTC-NEXT: .ascii "atomics" ; NO-BULK-MEM-CMTC-NEXT: .int8 43 -; NO-BULK-MEM-CMTC-NEXT: .int8 30 -; NO-BULK-MEM-CMTC-NEXT: .ascii "component-model-threading" +; NO-BULK-MEM-CMTC-NEXT: .int8 22 +; NO-BULK-MEM-CMTC-NEXT: .ascii "libcall-thread-context" ; NO-BULK-MEM-CMTC-NEXT: .int8 45 ; NO-BULK-MEM-CMTC-NEXT: .int8 10 ; NO-BULK-MEM-CMTC-NEXT: .ascii "shared-mem" ; NO-BULK-MEM-CMTC-NEXT: .bss.foo,"",@ -; +bulk-memory,+component-model-threading +; +bulk-memory,+libcall-thread-context ; BULK-MEM-CMTC-LABEL: .custom_section.target_features,"",@ ; BULK-MEM-CMTC-NEXT: .int8 4 ; BULK-MEM-CMTC-NEXT: .int8 43 @@ -62,6 +62,6 @@ target triple = "wasm32-unknown-unknown" ; BULK-MEM-CMTC-NEXT: .int8 15 ; BULK-MEM-CMTC-NEXT: .ascii "bulk-memory-opt" ; BULK-MEM-CMTC-NEXT: .int8 43 -; BULK-MEM-CMTC-NEXT: .int8 30 -; BULK-MEM-CMTC-NEXT: .ascii "component-model-threading" +; BULK-MEM-CMTC-NEXT: .int8 22 +; BULK-MEM-CMTC-NEXT: .ascii "libcall-thread-context" ; BULK-MEM-CMTC-NEXT: .tbss.foo,"T",@ diff --git a/llvm/test/CodeGen/WebAssembly/thread_pointer.ll b/llvm/test/CodeGen/WebAssembly/thread_pointer.ll index 9c75ebce187dd..1be5e7833e05c 100644 --- a/llvm/test/CodeGen/WebAssembly/thread_pointer.ll +++ b/llvm/test/CodeGen/WebAssembly/thread_pointer.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=wasm32-unknown-unknown | FileCheck %s --check-prefix=WASM32 ; RUN: llc < %s -mtriple=wasm64-unknown-unknown | FileCheck %s --check-prefix=WASM64 -; RUN: llc < %s -mtriple=wasm32-unknown-unknown -mattr=+component-model-threading | FileCheck %s --check-prefix=WASM32-CMTC +; RUN: llc < %s -mtriple=wasm32-unknown-unknown -mattr=+libcall-thread-context | FileCheck %s --check-prefix=WASM32-LIBCALL declare ptr @llvm.thread.pointer() @@ -18,11 +18,11 @@ define ptr @thread_pointer() nounwind { ; WASM64-NEXT: global.get __tls_base ; WASM64-NEXT: # fallthrough-return ; -; WASM32-CMTC-LABEL: thread_pointer: -; WASM32-CMTC: .functype thread_pointer () -> (i32) -; WASM32-CMTC-NEXT: # %bb.0: -; WASM32-CMTC-NEXT: call __wasm_get_tls_base -; WASM32-CMTC-NEXT: # fallthrough-return +; WASM32-LIBCALL-LABEL: thread_pointer: +; WASM32-LIBCALL: .functype thread_pointer () -> (i32) +; WASM32-LIBCALL-NEXT: # %bb.0: +; WASM32-LIBCALL-NEXT: call __wasm_get_tls_base +; WASM32-LIBCALL-NEXT: # fallthrough-return ; %1 = tail call ptr @llvm.thread.pointer() ret ptr %1 diff --git a/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll b/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll index eb1120d4832ad..586f5234d9bc4 100644 --- a/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll +++ b/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll @@ -1,16 +1,16 @@ ; Run the tests with the `localexec` TLS mode specified. ; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,TLS %s ; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS %s -; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+component-model-threading,bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS-CMTC %s +; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+libcall-thread-context,bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS-LIBCALL %s ; Also, run the same tests without a specified TLS mode--this should still emit `localexec` code on non-Emscripten targtes which don't currently support dynamic linking. ; RUN: sed -e 's/\[\[TLS_MODE\]\]//' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,TLS %s ; RUN: sed -e 's/\[\[TLS_MODE\]\]//' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS %s -; RUN: sed -e 's/\[\[TLS_MODE\]\]//' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+component-model-threading,bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS-CMTC %s +; RUN: sed -e 's/\[\[TLS_MODE\]\]//' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+libcall-thread-context,bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS-LIBCALL %s ; Finally, when bulk memory is disabled, no TLS code should be generated. ; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=-bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,NO-TLS %s -; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+component-model-threading,-bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,NO-TLS %s +; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+libcall-thread-context,-bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,NO-TLS %s target triple = "wasm32-unknown-unknown" ; CHECK-LABEL: address_of_tls: @@ -21,10 +21,10 @@ define i32 @address_of_tls() { ; TLS-NEXT: i32.add ; TLS-NEXT: return - ; TLS-CMTC-DAG: call __wasm_get_tls_base - ; TLS-CMTC-DAG: i32.const tls@TLSREL - ; TLS-CMTC-NEXT: i32.add - ; TLS-CMTC-NEXT: return + ; TLS-LIBCALL-DAG: call __wasm_get_tls_base + ; TLS-LIBCALL-DAG: i32.const tls@TLSREL + ; TLS-LIBCALL-NEXT: i32.add + ; TLS-LIBCALL-NEXT: return ; NO-TLS-NEXT: i32.const tls ; NO-TLS-NEXT: return @@ -41,10 +41,10 @@ define i32 @address_of_tls_external() { ; TLS-NEXT: i32.add ; TLS-NEXT: return - ; TLS-CMTC-DAG: call __wasm_get_tls_base - ; TLS-CMTC-DAG: i32.const tls_external@TLSREL - ; TLS-CMTC-NEXT: i32.add - ; TLS-CMTC-NEXT: return + ; TLS-LIBCALL-DAG: call __wasm_get_tls_base + ; TLS-LIBCALL-DAG: i32.const tls_external@TLSREL + ; TLS-LIBCALL-NEXT: i32.add + ; TLS-LIBCALL-NEXT: return ; NO-TLS-NEXT: i32.const tls_external ; NO-TLS-NEXT: return @@ -61,10 +61,10 @@ define ptr @ptr_to_tls() { ; TLS-NEXT: i32.add ; TLS-NEXT: return - ; TLS-CMTC-DAG: call __wasm_get_tls_base - ; TLS-CMTC-DAG: i32.const tls@TLSREL - ; TLS-CMTC-NEXT: i32.add - ; TLS-CMTC-NEXT: return + ; TLS-LIBCALL-DAG: call __wasm_get_tls_base + ; TLS-LIBCALL-DAG: i32.const tls@TLSREL + ; TLS-LIBCALL-NEXT: i32.add + ; TLS-LIBCALL-NEXT: return ; NO-TLS-NEXT: i32.const tls ; NO-TLS-NEXT: return @@ -81,11 +81,11 @@ define i32 @tls_load() { ; TLS-NEXT: i32.load 0 ; TLS-NEXT: return - ; TLS-CMTC-DAG: call __wasm_get_tls_base - ; TLS-CMTC-DAG: i32.const tls@TLSREL - ; TLS-CMTC-NEXT: i32.add - ; TLS-CMTC-NEXT: i32.load 0 - ; TLS-CMTC-NEXT: return + ; TLS-LIBCALL-DAG: call __wasm_get_tls_base + ; TLS-LIBCALL-DAG: i32.const tls@TLSREL + ; TLS-LIBCALL-NEXT: i32.add + ; TLS-LIBCALL-NEXT: i32.load 0 + ; TLS-LIBCALL-NEXT: return ; NO-TLS-NEXT: i32.const 0 ; NO-TLS-NEXT: i32.load tls @@ -104,11 +104,11 @@ define void @tls_store(i32 %x) { ; TLS-NEXT: i32.store 0 ; TLS-NEXT: return - ; TLS-CMTC-DAG: call __wasm_get_tls_base - ; TLS-CMTC-DAG: i32.const tls@TLSREL - ; TLS-CMTC-NEXT: i32.add - ; TLS-CMTC-NEXT: i32.store 0 - ; TLS-CMTC-NEXT: return + ; TLS-LIBCALL-DAG: call __wasm_get_tls_base + ; TLS-LIBCALL-DAG: i32.const tls@TLSREL + ; TLS-LIBCALL-NEXT: i32.add + ; TLS-LIBCALL-NEXT: i32.store 0 + ; TLS-LIBCALL-NEXT: return ; NO-TLS-NEXT: i32.const 0 ; NO-TLS-NEXT: i32.store tls @@ -129,7 +129,7 @@ define i32 @tls_size() { ; CHECK: .type tls,@object ; TLS-NEXT: .section .tbss.tls,"T",@ -; TLS-CMTC-NEXT: .section .tbss.tls,"T",@ +; TLS-LIBCALL-NEXT: .section .tbss.tls,"T",@ ; NO-TLS-NEXT: .section .bss.tls,"",@ ; CHECK-NEXT: .p2align 2 ; CHECK-NEXT: tls: From 8dfc97c5bdaa0264ef4563343d08dffcd1c63daa Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 1 Apr 2026 14:23:19 +0100 Subject: [PATCH 100/134] Cleanup --- .../CodeGen/WebAssembly/wasm-thread-context-abi.c | 11 ----------- clang/test/Driver/wasm-toolchain.c | 2 +- lld/wasm/Driver.cpp | 2 +- 3 files changed, 2 insertions(+), 13 deletions(-) delete mode 100644 clang/test/CodeGen/WebAssembly/wasm-thread-context-abi.c diff --git a/clang/test/CodeGen/WebAssembly/wasm-thread-context-abi.c b/clang/test/CodeGen/WebAssembly/wasm-thread-context-abi.c deleted file mode 100644 index 48ba06a38b32e..0000000000000 --- a/clang/test/CodeGen/WebAssembly/wasm-thread-context-abi.c +++ /dev/null @@ -1,11 +0,0 @@ -// RUN: %clang_cc1 -triple wasm32-unknown-unknown-wasm -emit-llvm -o - %s | FileCheck %s - -void use_stack() { - int x; - volatile int* ptr = &x; -} - -void use_tls() { - static __thread int x; - volatile int* ptr = &x; -} \ No newline at end of file diff --git a/clang/test/Driver/wasm-toolchain.c b/clang/test/Driver/wasm-toolchain.c index bfe13e2922a41..d7b2e2d5a279d 100644 --- a/clang/test/Driver/wasm-toolchain.c +++ b/clang/test/Driver/wasm-toolchain.c @@ -314,4 +314,4 @@ // RUN: %clang -### --target=wasm32-wasip3 --sysroot=/foo -mno-libcall-thread-context %s 2>&1 \ // RUN: | FileCheck -check-prefix=LINK_WASIP3_NO_LIBCALL_THREAD_CONTEXT %s -// LINK_WASIP3_NO_LIBCALL_THREAD_CONTEXT: "-cc1" {{.*}} "-target-feature" "-libcall-thread-context" \ No newline at end of file +// LINK_WASIP3_NO_LIBCALL_THREAD_CONTEXT: "-cc1" {{.*}} "-target-feature" "-libcall-thread-context" diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index e7b443c01765e..93d2c238c990e 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -1063,7 +1063,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.sym.tlsBase) + if (!ctx.arg.sharedMemory) ctx.sym.tlsBase = createOptionalGlobal("__tls_base", false); } From cdca5aac2313774d1045782d2230826a82f060ab Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 1 Apr 2026 14:24:43 +0100 Subject: [PATCH 101/134] fmt --- clang/lib/Driver/ToolChains/WebAssembly.cpp | 2 +- lld/wasm/Config.h | 5 +-- lld/wasm/Driver.cpp | 33 +++++++++---------- lld/wasm/Writer.cpp | 8 ++--- .../MCTargetDesc/WebAssemblyMCTargetDesc.h | 6 ++-- .../WebAssembly/WebAssemblyFrameLowering.cpp | 3 +- .../WebAssembly/WebAssemblyLateEHPrepare.cpp | 4 +-- .../WebAssembly/WebAssemblySubtarget.cpp | 3 +- .../WebAssembly/WebAssemblyTargetMachine.cpp | 8 ++--- 9 files changed, 34 insertions(+), 38 deletions(-) diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index ab781b8575aa7..c4acd6635047c 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -89,7 +89,7 @@ static bool WantsPthread(const llvm::Triple &Triple, const ArgList &Args) { } static bool WantsLibcallThreadContext(const llvm::Triple &Triple, - const ArgList &Args) { + const ArgList &Args) { // If the target is WASIP3, then enable the // libcall-thread-context feature by default, unless explicitly // disabled. diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h index 845c40d36146f..9cee25b9d6461 100644 --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -280,8 +280,9 @@ struct Ctx { 0> whyExtractRecords; - // Whether to use library functions for the stack pointer and TLS base - // instead of globals. This is currently used for WASIp3 cooperative threads support. + // Whether to use library functions for the stack pointer and TLS base + // instead of globals. This is currently used for WASIp3 cooperative threads + // support. bool libcallThreadContext = false; Ctx(); diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 93d2c238c990e..b87be2d8bd6af 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -966,19 +966,18 @@ static void createPostLTOSymbols() { bool is64 = ctx.arg.is64.value_or(false); - auto stack_pointer_name = ctx.libcallThreadContext - ? "__init_stack_pointer" - : "__stack_pointer"; + auto stack_pointer_name = + ctx.libcallThreadContext ? "__init_stack_pointer" : "__stack_pointer"; if (ctx.isPic) { if (ctx.libcallThreadContext) { - ctx.sym.stackPointer = - createUndefinedGlobal(stack_pointer_name, ctx.arg.is64.value_or(false) - ? &globalTypeI64 - : &globalTypeI32); - } - else { + ctx.sym.stackPointer = createUndefinedGlobal( + stack_pointer_name, + ctx.arg.is64.value_or(false) ? &globalTypeI64 : &globalTypeI32); + } else { ctx.sym.stackPointer = createUndefinedGlobal(stack_pointer_name, - ctx.arg.is64.value_or(false) ? &mutableGlobalTypeI64 : &mutableGlobalTypeI32); + 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 @@ -992,8 +991,8 @@ static void createPostLTOSymbols() { ctx.sym.tableBase->markLive(); } else { // For non-PIC code - ctx.sym.stackPointer = createGlobalVariable( - stack_pointer_name, !ctx.libcallThreadContext); + ctx.sym.stackPointer = + createGlobalVariable(stack_pointer_name, !ctx.libcallThreadContext); ctx.sym.stackPointer->markLive(); } @@ -1369,17 +1368,15 @@ static void determineThreadContextABI(ArrayRef files) { if (threadContextABI == ThreadContextABI::Undetermined) { threadContextABI = ThreadContextABI::Libcall; } else if (threadContextABI != ThreadContextABI::Libcall) { - error( - "thread context ABI mismatch: " + obj->getName() + - " uses libcall-thread-context but other files disallow it"); + error("thread context ABI mismatch: " + obj->getName() + + " uses libcall-thread-context but other files disallow it"); } } else { if (threadContextABI == ThreadContextABI::Undetermined) { threadContextABI = ThreadContextABI::Globals; } else if (threadContextABI != ThreadContextABI::Globals) { - error( - "thread context ABI mismatch: " + obj->getName() + - " disallows libcall-thread-context but other files use it"); + error("thread context ABI mismatch: " + obj->getName() + + " disallows libcall-thread-context but other files use it"); } } } diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index e3b510e78e5df..a0d6fc2dd5b2e 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1358,7 +1358,7 @@ void Writer::createInitMemoryFunction() { "i32.add"); } - // When we initialize the TLS segment we also set the TLS base. + // When we initialize the TLS segment we also set the TLS base. // This allows the runtime to use this // static copy of the TLS data for the first/main thread. if (ctx.arg.sharedMemory && s->isTLS()) { @@ -1644,9 +1644,9 @@ void Writer::createInitTLSFunction() { if (ctx.libcallThreadContext) { writeU8(os, WASM_OPCODE_CALL, "call"); - writeUleb128(os, ctx.sym.setTLSBase->getFunctionIndex(), "function index"); - } - else { + writeUleb128(os, ctx.sym.setTLSBase->getFunctionIndex(), + "function index"); + } else { writeU8(os, WASM_OPCODE_GLOBAL_SET, "global.set"); writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "global index"); } diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h index be42618eea5a4..f68e10704c71b 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -108,9 +108,9 @@ enum TOF { MO_MEMORY_BASE_REL, // On a symbol operand this indicates that the immediate is the symbol - // address relative to the TLS base. This is retrieved through __wasm_get_tls_base() - // when using libcall thread context, and the __tls_base global - // otherwise. Only applicable to data symbols. + // address relative to the TLS base. This is retrieved through + // __wasm_get_tls_base() when using libcall thread context, and the __tls_base + // global otherwise. Only applicable to data symbols. MO_TLS_BASE_REL, // On a symbol operand this indicates that the immediate is the symbol diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index e3b6c2e29555e..180c8446f1a39 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -239,8 +239,7 @@ void WebAssemblyFrameLowering::writeBackSP( MachineBasicBlock::iterator &InsertStore, const DebugLoc &DL) const { const auto *TII = MF.getSubtarget().getInstrInfo(); - if (MF.getSubtarget() - .hasLibcallThreadContext()) { + if (MF.getSubtarget().hasLibcallThreadContext()) { const char *ES = "__wasm_set_stack_pointer"; auto *SPSymbol = MF.createExternalSymbolName(ES); BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::CALL)) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp index 771aa5187d0d2..5e370ca4ada31 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp @@ -377,8 +377,8 @@ bool WebAssemblyLateEHPrepare::removeUnnecessaryUnreachables( } // After the stack is unwound due to a thrown exception, the __stack_pointer -// global/__wasm_get_stack_pointer() can point to an invalid address. This inserts -// instructions that restore the stack pointer state. +// global/__wasm_get_stack_pointer() can point to an invalid address. This +// inserts instructions that restore the stack pointer state. bool WebAssemblyLateEHPrepare::restoreStackPointer(MachineFunction &MF) { const auto *FrameLowering = static_cast( MF.getSubtarget().getFrameLowering()); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp index 179d5dc89603a..50eef290bc5a7 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp @@ -42,8 +42,7 @@ WebAssemblySubtarget::initializeSubtargetDependencies(StringRef CPU, // WASIP3 implies using the libcall thread context by // default, unless explicitly disabled. - if (!FS.contains("libcall-thread-context") && - !HasLibcallThreadContext && + if (!FS.contains("libcall-thread-context") && !HasLibcallThreadContext && TargetTriple.getOS() == Triple::WASIp3) { ToggleFeature(WebAssembly::FeatureLibcallThreadContext); HasLibcallThreadContext = true; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index b30738bb77047..75485564fa210 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -286,13 +286,14 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { } else if (!Features[WebAssembly::FeatureBulkMemory]) { StrippedTLS |= stripThreadLocals(M); } - + if (StrippedAtomics && !StrippedTLS) stripThreadLocals(M); else if (StrippedTLS && !StrippedAtomics) stripAtomics(M); - recordFeatures(M, WasmTM->getTargetCPU(), Features, StrippedAtomics || StrippedTLS); + recordFeatures(M, WasmTM->getTargetCPU(), Features, + StrippedAtomics || StrippedTLS); // Conservatively assume we have made some change return true; @@ -418,8 +419,7 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { // Mark libcall-thread-context as disallowed when not in use to // prevent linking object files with incompatible threading ABIs. // This is implicit for MVP since the feature is not supported at all. - if (CPU != "mvp" && - !Features[WebAssembly::FeatureLibcallThreadContext]) { + if (CPU != "mvp" && !Features[WebAssembly::FeatureLibcallThreadContext]) { M.addModuleFlag(Module::ModFlagBehavior::Error, "wasm-feature-libcall-thread-context", wasm::WASM_FEATURE_PREFIX_DISALLOWED); From 7559ec5323dbd192d7e5c1204804323828b2fe8a Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 1 Apr 2026 17:26:23 +0100 Subject: [PATCH 102/134] Flag for libcall thread context --- clang/lib/Driver/ToolChains/WebAssembly.cpp | 3 + lld/test/wasm/comdats.ll | 6 +- lld/test/wasm/mutable-global-exports.s | 12 +-- lld/test/wasm/pie.s | 4 - lld/test/wasm/shared-weak-symbols.s | 8 +- lld/test/wasm/stack-pointer-abi.s | 4 +- lld/test/wasm/thread-context-abi-mismatch.s | 16 ++- lld/test/wasm/tls-libcall.s | 25 +++-- lld/test/wasm/visibility-hidden.ll | 6 +- lld/test/wasm/weak-undefined-pic.s | 10 -- lld/wasm/Config.h | 6 +- lld/wasm/Driver.cpp | 110 +++----------------- lld/wasm/Options.td | 3 + lld/wasm/SyntheticSections.cpp | 2 +- lld/wasm/Writer.cpp | 27 ++++- 15 files changed, 82 insertions(+), 160 deletions(-) diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index c4acd6635047c..6a1e7b6653348 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -179,6 +179,9 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + if (WantsLibcallThreadContext(ToolChain.getTriple(), Args)) + CmdArgs.push_back("--libcall-thread-context"); + if (WantsPthread(ToolChain.getTriple(), Args)) CmdArgs.push_back("--shared-memory"); diff --git a/lld/test/wasm/comdats.ll b/lld/test/wasm/comdats.ll index 249ad279f8acc..1662a983698ac 100644 --- a/lld/test/wasm/comdats.ll +++ b/lld/test/wasm/comdats.ll @@ -35,6 +35,9 @@ entry: ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __stack_pointer +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: _start ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 @@ -50,9 +53,6 @@ entry: ; CHECK-NEXT: - Name: callComdatFn2 ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 5 -; CHECK-NEXT: - Name: __stack_pointer -; CHECK-NEXT: Kind: GLOBAL -; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Type: ELEM ; CHECK-NEXT: Segments: ; CHECK-NEXT: - Offset: diff --git a/lld/test/wasm/mutable-global-exports.s b/lld/test/wasm/mutable-global-exports.s index af2dd428d8d78..3cf1ae746b30a 100644 --- a/lld/test/wasm/mutable-global-exports.s +++ b/lld/test/wasm/mutable-global-exports.s @@ -57,12 +57,12 @@ _start: # CHECK-SP-NEXT: - Name: memory # CHECK-SP-NEXT: Kind: MEMORY # CHECK-SP-NEXT: Index: 0 -# CHECK-SP-NEXT: - Name: _start -# CHECK-SP-NEXT: Kind: FUNCTION -# CHECK-SP-NEXT: Index: 0 # CHECK-SP-NEXT: - Name: __stack_pointer # CHECK-SP-NEXT: Kind: GLOBAL # CHECK-SP-NEXT: Index: 0 +# CHECK-SP-NEXT: - Name: _start +# CHECK-SP-NEXT: Kind: FUNCTION +# CHECK-SP-NEXT: Index: 0 # CHECK-SP-NEXT: - Type: CODE # CHECK-ALL: - Type: EXPORT @@ -73,6 +73,9 @@ _start: # CHECK-ALL-NEXT: - Name: __wasm_call_ctors # CHECK-ALL-NEXT: Kind: FUNCTION # CHECK-ALL-NEXT: Index: 0 +# CHECK-ALL-NEXT: - Name: __stack_pointer +# CHECK-ALL-NEXT: Kind: GLOBAL +# CHECK-ALL-NEXT: Index: 0 # CHECK-ALL-NEXT: - Name: _start # CHECK-ALL-NEXT: Kind: FUNCTION # CHECK-ALL-NEXT: Index: 1 @@ -82,9 +85,6 @@ _start: # CHECK-ALL-NEXT: - Name: bar_global # CHECK-ALL-NEXT: Kind: GLOBAL # CHECK-ALL-NEXT: Index: 5 -# CHECK-ALL-NEXT: - Name: __stack_pointer -# CHECK-ALL-NEXT: Kind: GLOBAL -# CHECK-ALL-NEXT: Index: 0 # CHECK-ALL-NEXT: - Name: __dso_handle # CHECK-ALL-NEXT: Kind: GLOBAL # CHECK-ALL-NEXT: Index: 6 diff --git a/lld/test/wasm/pie.s b/lld/test/wasm/pie.s index 41f405062fba9..21eac79207318 100644 --- a/lld/test/wasm/pie.s +++ b/lld/test/wasm/pie.s @@ -98,10 +98,6 @@ _start: # CHECK-NEXT: GlobalType: I32 # CHECK-NEXT: GlobalMutable: true # CHECK-NEXT: - Module: env -# CHECK-NEXT: Field: external_func -# CHECK-NEXT: Kind: FUNCTION -# CHECK-NEXT: SigIndex: 1 -# CHECK-NEXT: - Module: env # CHECK-NEXT: Field: __memory_base # CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: GlobalType: I32 diff --git a/lld/test/wasm/shared-weak-symbols.s b/lld/test/wasm/shared-weak-symbols.s index 62c46d8b9285f..df049ce4600fe 100644 --- a/lld/test/wasm/shared-weak-symbols.s +++ b/lld/test/wasm/shared-weak-symbols.s @@ -42,10 +42,6 @@ call_weak: # CHECK-NEXT: Memory: # CHECK-NEXT: Minimum: 0x0 # CHECK-NEXT: - Module: env -# CHECK-NEXT: Field: weak_func -# CHECK-NEXT: Kind: FUNCTION -# CHECK-NEXT: SigIndex: 0 -# CHECK-NEXT: - Module: env # CHECK-NEXT: Field: __memory_base # CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: GlobalType: I32 @@ -55,6 +51,10 @@ call_weak: # CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: GlobalType: I32 # CHECK-NEXT: GlobalMutable: false +# CHECK-NEXT: - Module: env +# CHECK-NEXT: Field: weak_func +# CHECK-NEXT: Kind: FUNCTION +# CHECK-NEXT: SigIndex: 0 # CHECK-NEXT: - Type: FUNCTION # CHECK: - Type: EXPORT diff --git a/lld/test/wasm/stack-pointer-abi.s b/lld/test/wasm/stack-pointer-abi.s index c77d9fe55c523..63f3f5302966b 100644 --- a/lld/test/wasm/stack-pointer-abi.s +++ b/lld/test/wasm/stack-pointer-abi.s @@ -2,7 +2,7 @@ # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/use.o %t/use.s # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/disallow.o %t/disallow.s # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/start.o %t/start.s -# RUN: wasm-ld -o %t/libcall.wasm %t/use.o %t/start.o +# RUN: wasm-ld --libcall-thread-context -o %t/libcall.wasm %t/use.o %t/start.o # RUN: obj2yaml %t/libcall.wasm | FileCheck %s --check-prefix=LIBCALL # RUN: wasm-ld -o %t/global.wasm %t/disallow.o %t/start.o # RUN: obj2yaml %t/global.wasm | FileCheck %s --check-prefix=GLOBAL @@ -25,7 +25,7 @@ _start: .section .custom_section.target_features,"",@ .int8 1 .int8 43 - .int8 2 + .int8 22 .ascii "libcall-thread-context" # LIBCALL: Name: __init_stack_pointer diff --git a/lld/test/wasm/thread-context-abi-mismatch.s b/lld/test/wasm/thread-context-abi-mismatch.s index efc1230b5768e..a5bf661b11c40 100644 --- a/lld/test/wasm/thread-context-abi-mismatch.s +++ b/lld/test/wasm/thread-context-abi-mismatch.s @@ -8,15 +8,15 @@ # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/start.o %t/start.s # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/stack-pointer.o %t/stack-pointer.s -# RUN: not wasm-ld %t/start.o %t/stack-pointer.o -o %t/fail.wasm 2>&1 | FileCheck %s +# RUN: not wasm-ld --libcall-thread-context %t/start.o %t/stack-pointer.o -o %t/fail.wasm 2>&1 | FileCheck %s # Test that explicitly disallowing the libcall-thread-context feature causes linking to fail # with an error when other files use the feature. # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/disallow.o %t/disallow.s -# RUN: not wasm-ld %t/start.o %t/disallow.o -o %t/fail.wasm 2>&1 | FileCheck %s +# RUN: not wasm-ld --libcall-thread-context %t/start.o %t/disallow.o -o %t/fail.wasm 2>&1 | FileCheck %s -# CHECK: error: thread context ABI mismatch: {{.*}} disallows libcall-thread-context but other files use it +# CHECK: error: --libcall-thread-context is disallowed by {{.*}} because it uses globals for thread context rather than library function calls. #--- start.s .globl _start @@ -24,7 +24,6 @@ _start: .functype _start () -> () end_function -# Mark the feature as USED .section .custom_section.target_features,"",@ .int8 1 .int8 43 @@ -34,14 +33,11 @@ _start: #--- stack-pointer.s .globaltype __stack_pointer, i32 -.globl _start -_start: - .functype _start () -> (i32) +.globl use_stack_pointer +use_stack_pointer: + .functype use_stack_pointer () -> () global.get __stack_pointer - i32.const 16 - i32.sub drop - i32.const 0 end_function #--- disallow.s diff --git a/lld/test/wasm/tls-libcall.s b/lld/test/wasm/tls-libcall.s index 67addd5649b2c..4e9c547c11196 100644 --- a/lld/test/wasm/tls-libcall.s +++ b/lld/test/wasm/tls-libcall.s @@ -1,9 +1,13 @@ # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s -# RUN: wasm-ld -no-gc-sections -o %t.wasm %t.o +# RUN: wasm-ld --libcall-thread-context --shared-memory -no-gc-sections -o %t.wasm %t.o # RUN: obj2yaml %t.wasm | FileCheck %s # RUN: llvm-objdump -d --no-print-imm-hex --no-show-raw-insn %t.wasm | FileCheck %s --check-prefix=DIS -.functype __wasm_get_tls_base () -> (i32) +.globl __wasm_get_tls_base +__wasm_get_tls_base: + .functype __wasm_get_tls_base () -> (i32) + i32.const 0 + end_function .globl _start _start: @@ -32,13 +36,16 @@ tls2: .size tls2, 4 .section .custom_section.target_features,"",@ - .int8 2 + .int8 3 .int8 43 .int8 22 .ascii "libcall-thread-context" .int8 43 .int8 11 .ascii "bulk-memory" + .int8 43 + .int8 7 + .ascii "atomics" # CHECK: GlobalNames: @@ -52,22 +59,14 @@ tls2: # CHECK-NEXT: Name: __tls_align # DIS-LABEL: <__wasm_init_memory>: -# DIS-EMPTY: -# DIS-NEXT: i32.const 65536 -# DIS-NEXT: i32.const 65536 -# DIS-NEXT: call 1 -# DIS-NEXT: i32.const 0 -# DIS-NEXT: i32.const 8 -# DIS-NEXT: memory.init 0, 0 -# DIS-NEXT: end # DIS-LABEL: <_start>: # DIS-EMPTY: -# DIS-NEXT: call 0 +# DIS-NEXT: call 4 # DIS-NEXT: i32.const 0 # DIS-NEXT: i32.add # DIS-NEXT: i32.load 0 -# DIS-NEXT: call 0 +# DIS-NEXT: call 4 # DIS-NEXT: i32.const 4 # DIS-NEXT: i32.add # DIS-NEXT: i32.load 0 diff --git a/lld/test/wasm/visibility-hidden.ll b/lld/test/wasm/visibility-hidden.ll index 657748676849d..6ed7ba3afdc02 100644 --- a/lld/test/wasm/visibility-hidden.ll +++ b/lld/test/wasm/visibility-hidden.ll @@ -43,6 +43,9 @@ entry: ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __stack_pointer +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: objectDefault ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 @@ -52,9 +55,6 @@ entry: ; CHECK-NEXT: - Name: archiveDefault ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 4 -; CHECK-NEXT: - Name: __stack_pointer -; CHECK-NEXT: Kind: GLOBAL -; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Type: diff --git a/lld/test/wasm/weak-undefined-pic.s b/lld/test/wasm/weak-undefined-pic.s index 4be482c72728d..1a3a1715b4bb9 100644 --- a/lld/test/wasm/weak-undefined-pic.s +++ b/lld/test/wasm/weak-undefined-pic.s @@ -81,16 +81,6 @@ _start: # IMPORT: Field: foo # IMPORT-NEXT: Kind: FUNCTION # IMPORT-NEXT: SigIndex: 0 -# IMPORT-NEXT: - Module: env -# IMPORT-NEXT: Field: __memory_base -# IMPORT-NEXT: Kind: GLOBAL -# IMPORT-NEXT: GlobalType: I32 -# IMPORT-NEXT: GlobalMutable: false -# IMPORT-NEXT: - Module: env -# IMPORT-NEXT: Field: __table_base -# IMPORT-NEXT: Kind: GLOBAL -# IMPORT-NEXT: GlobalType: I32 -# IMPORT-NEXT: GlobalMutable: false # IMPORT-NEXT: - Module: GOT.func # IMPORT-NEXT: Field: foo # IMPORT-NEXT: Kind: GLOBAL diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h index 9cee25b9d6461..8408c1c6d2af3 100644 --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -66,6 +66,7 @@ struct Config { bool growableTable; bool gcSections; llvm::StringSet<> keepSections; + bool libcallThreadContext; std::optional> memoryImport; std::optional memoryExport; bool sharedMemory; @@ -280,11 +281,6 @@ struct Ctx { 0> whyExtractRecords; - // Whether to use library functions for the stack pointer and TLS base - // instead of globals. This is currently used for WASIp3 cooperative threads - // support. - bool libcallThreadContext = false; - Ctx(); void reset(); }; diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index b87be2d8bd6af..45ec3af5cea21 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -562,6 +562,7 @@ static void readConfigs(opt::InputArgList &args) { ctx.arg.soName = args.getLastArgValue(OPT_soname); ctx.arg.importTable = args.hasArg(OPT_import_table); ctx.arg.importUndefined = args.hasArg(OPT_import_undefined); + ctx.arg.libcallThreadContext = args.hasArg(OPT_libcall_thread_context); ctx.arg.ltoo = args::getInteger(args, OPT_lto_O, 2); if (ctx.arg.ltoo > 3) error("invalid optimization level for LTO: " + Twine(ctx.arg.ltoo)); @@ -938,23 +939,12 @@ static DefinedGlobal *createOptionalGlobal(StringRef name, bool isMutable) { return symtab->addOptionalGlobalSymbol(name, g); } -// Create ABI-defined synthetic symbols that are needed early, before LTO. -static void createEarlySyntheticSymbols() { +// Create ABI-defined synthetic symbols +static void createSyntheticSymbols() { if (ctx.arg.relocatable) return; static WasmSignature nullSignature = {{}, {}}; - ctx.sym.callCtors = symtab->addSyntheticFunction( - "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN, - make(nullSignature, "__wasm_call_ctors")); -} - -// Create synthetic symbols that rely on information that is only available -// after LTO, e.g. __stack_pointer, __tls_base. -static void createPostLTOSymbols() { - if (ctx.arg.relocatable) - return; - static WasmSignature i32ArgSignature = {{}, {ValType::I32}}; static WasmSignature i64ArgSignature = {{}, {ValType::I64}}; static llvm::wasm::WasmGlobalType globalTypeI32 = {WASM_TYPE_I32, false}; @@ -964,12 +954,16 @@ static void createPostLTOSymbols() { static llvm::wasm::WasmGlobalType mutableGlobalTypeI64 = {WASM_TYPE_I64, true}; + ctx.sym.callCtors = symtab->addSyntheticFunction( + "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN, + make(nullSignature, "__wasm_call_ctors")); + bool is64 = ctx.arg.is64.value_or(false); auto stack_pointer_name = - ctx.libcallThreadContext ? "__init_stack_pointer" : "__stack_pointer"; + ctx.arg.libcallThreadContext ? "__init_stack_pointer" : "__stack_pointer"; if (ctx.isPic) { - if (ctx.libcallThreadContext) { + if (ctx.arg.libcallThreadContext) { ctx.sym.stackPointer = createUndefinedGlobal( stack_pointer_name, ctx.arg.is64.value_or(false) ? &globalTypeI64 : &globalTypeI32); @@ -992,16 +986,16 @@ static void createPostLTOSymbols() { } else { // For non-PIC code ctx.sym.stackPointer = - createGlobalVariable(stack_pointer_name, !ctx.libcallThreadContext); + createGlobalVariable(stack_pointer_name, !ctx.arg.libcallThreadContext); ctx.sym.stackPointer->markLive(); } if (ctx.arg.sharedMemory) { // TLS symbols are all hidden/dso-local auto tls_base_name = - ctx.libcallThreadContext ? "__init_tls_base" : "__tls_base"; + ctx.arg.libcallThreadContext ? "__init_tls_base" : "__tls_base"; ctx.sym.tlsBase = - createGlobalVariable(tls_base_name, !ctx.libcallThreadContext, + createGlobalVariable(tls_base_name, !ctx.arg.libcallThreadContext, WASM_SYMBOL_VISIBILITY_HIDDEN); ctx.sym.tlsSize = createGlobalVariable("__tls_size", false, WASM_SYMBOL_VISIBILITY_HIDDEN); @@ -1011,7 +1005,7 @@ static void createPostLTOSymbols() { "__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN, make(is64 ? i64ArgSignature : i32ArgSignature, "__wasm_init_tls")); - if (ctx.libcallThreadContext) { + if (ctx.arg.libcallThreadContext) { ctx.sym.tlsBase->markLive(); ctx.sym.tlsSize->markLive(); ctx.sym.tlsAlign->markLive(); @@ -1317,76 +1311,6 @@ static void checkZOptions(opt::InputArgList &args) { warn("unknown -z value: " + StringRef(arg->getValue())); } -// Determine the thread context ABI based on object file features. -// This must be called after LTO, since LTO object files are needed. -static void determineThreadContextABI(ArrayRef files) { - // A complication is that a user may attempt to link together object files - // compiled with different versions of LLVM, where one does not specifiy - // -libcall-thread-context when using the global thread context ABI. - // They may also attempt to link object files with the global ABI compiled - // with older LLVM versions, but link them with a newer wasm-ld. To ensure the - // correct behavior in both of these cases, we treat the import of a - // __stack_pointer global from the env module as an indication that the global - // thread context ABI is being used. - - enum class ThreadContextABI { Undetermined, Libcall, Globals }; - - ThreadContextABI threadContextABI = ThreadContextABI::Undetermined; - - for (ObjFile *obj : files) { - auto targetFeatures = obj->getWasmObj()->getTargetFeatures(); - auto threadContextFeature = - llvm::find_if(targetFeatures, [](const auto &f) { - return f.Name == "libcall-thread-context"; - }); - - bool usesLibcallThreadContext = - threadContextFeature != targetFeatures.end() && - threadContextFeature->Prefix == WASM_FEATURE_PREFIX_USED; - - if (threadContextFeature == targetFeatures.end()) { - // If the feature is not explicitly used or disallowed, check for the - // presence of a __stack_pointer import in this specific file to determine - // if the global thread context ABI is being used. - bool hasStackPointerImport = - llvm::any_of(obj->getSymbols(), [](const auto &sym) { - return sym && sym->getName() == "__stack_pointer" && - sym->kind() == Symbol::UndefinedGlobalKind && - sym->importModule && sym->importModule == "env"; - }); - if (!hasStackPointerImport) { - // No __stack_pointer import, so this is probably an object file - // compiled from assembly or some other source that doesn't care about - // the thread context ABI. As such, we let it pass. - continue; - } - // Treat this as using the globals ABI - usesLibcallThreadContext = false; - } - - if (usesLibcallThreadContext) { - if (threadContextABI == ThreadContextABI::Undetermined) { - threadContextABI = ThreadContextABI::Libcall; - } else if (threadContextABI != ThreadContextABI::Libcall) { - error("thread context ABI mismatch: " + obj->getName() + - " uses libcall-thread-context but other files disallow it"); - } - } else { - if (threadContextABI == ThreadContextABI::Undetermined) { - threadContextABI = ThreadContextABI::Globals; - } else if (threadContextABI != ThreadContextABI::Globals) { - error("thread context ABI mismatch: " + obj->getName() + - " disallows libcall-thread-context but other files use it"); - } - } - } - - // If the ABI is undetermined at this point, default to the globals ABI - if (threadContextABI == ThreadContextABI::Libcall) { - ctx.libcallThreadContext = true; - } -} - LinkerDriver::LinkerDriver(Ctx &ctx) : ctx(ctx) {} void LinkerDriver::linkerMain(ArrayRef argsArr) { @@ -1476,7 +1400,7 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { ctx.arg.requiredExports.push_back(arg->getValue()); } - createEarlySyntheticSymbols(); + createSyntheticSymbols(); // Add all files to the symbol table. This will add almost all // symbols that we need to the symbol table. @@ -1561,12 +1485,6 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { if (errorCount()) return; - // Now that LTO is complete and all object files are available, determine the - // thread context ABI and create symbols (__stack_pointer, __tls_base, etc.) - // based on the determined ABI. - determineThreadContextABI(ctx.objectFiles); - createPostLTOSymbols(); - // The LTO process can generate new undefined symbols, specifically libcall // functions. Because those symbols might be declared in a stub library we // need the process the stub libraries once again after LTO to handle all diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td index 33ecf03176d36..cac21fa070d56 100644 --- a/lld/wasm/Options.td +++ b/lld/wasm/Options.td @@ -238,6 +238,9 @@ def page_size: JJ<"page-size=">, def initial_memory: JJ<"initial-memory=">, HelpText<"Initial size of the linear memory">; +def libcall_thread_context: FF<"libcall-thread-context">, + HelpText<"Use library calls for thread context access instead of globals.">; + def max_memory: JJ<"max-memory=">, HelpText<"Maximum size of the linear memory">; diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index 4c30fc26d54fb..74ac9aa944772 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -53,7 +53,7 @@ class SubSection { }; void writeGetTLSBase(const Ctx &ctx, raw_ostream &os) { - if (ctx.libcallThreadContext) { + if (ctx.arg.libcallThreadContext) { writeU8(os, WASM_OPCODE_CALL, "call"); writeUleb128(os, ctx.sym.getTLSBase->getFunctionIndex(), "function index"); } else { diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index a0d6fc2dd5b2e..80c6070cfa517 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -124,7 +124,7 @@ class Writer { }; void writeSetTLSBase(const Ctx &ctx, raw_ostream &os) { - if (ctx.libcallThreadContext) { + if (ctx.arg.libcallThreadContext) { writeU8(os, WASM_OPCODE_CALL, "call"); writeUleb128(os, ctx.sym.setTLSBase->getFunctionIndex(), "function index"); } else { @@ -637,6 +637,19 @@ void Writer::populateTargetFeatures() { return segment->live && segment->isTLS(); }; tlsUsed = tlsUsed || llvm::any_of(file->segments, isTLS); + + // Older versions of LLVM will not disallow the `libcall-thread-context` feature when + // emitting globals for thread context, so we use the presence of an imported `__stack_pointer` symbol + // as a heuristic to detect this case and disallow the feature. + if (!disallowed.contains("libcall-thread-context") && ctx.arg.libcallThreadContext) { + if (llvm::any_of(file->getSymbols(), [](const auto &sym) { + return sym && sym->getName() == "__stack_pointer" && + sym->kind() == Symbol::UndefinedGlobalKind && + sym->importModule && sym->importModule == "env"; + })) { + disallowed.insert({"libcall-thread-context", std::string(fileName)}); + } + } } if (inferFeatures) @@ -658,6 +671,13 @@ void Writer::populateTargetFeatures() { "' feature must be used in order to use shared memory"); } + // Special case for `libcall-thread-context` to give a more specific error message + if (ctx.arg.libcallThreadContext) + if (disallowed.contains("libcall-thread-context")) + error("--libcall-thread-context is disallowed by " + + disallowed["libcall-thread-context"] + + " because it uses globals for thread context rather than library function calls."); + if (tlsUsed) { for (auto feature : {"atomics", "bulk-memory"}) if (!allowed.contains(feature)) @@ -682,7 +702,8 @@ void Writer::populateTargetFeatures() { if (feature.Prefix == WASM_FEATURE_PREFIX_DISALLOWED) continue; objectFeatures.insert(feature.Name); - if (disallowed.contains(feature.Name)) + // libcall-thread-context is handled as a special case above + if (disallowed.contains(feature.Name) && feature.Name != "libcall-thread-context") error(Twine("Target feature '") + feature.Name + "' used in " + fileName + " is disallowed by " + disallowed[feature.Name] + ". Use --no-check-features to suppress."); @@ -1642,7 +1663,7 @@ void Writer::createInitTLSFunction() { writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); writeUleb128(os, 0, "local index"); - if (ctx.libcallThreadContext) { + if (ctx.arg.libcallThreadContext) { writeU8(os, WASM_OPCODE_CALL, "call"); writeUleb128(os, ctx.sym.setTLSBase->getFunctionIndex(), "function index"); From 4135d3de0a26d6d49865b9ab7b4064cf64e3aa89 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 1 Apr 2026 17:31:39 +0100 Subject: [PATCH 103/134] Test fixes --- .../WebAssembly/target-features-cpus.ll | 12 ++-- .../WebAssembly/target-features-tls.ll | 58 +++++++++---------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll b/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll index 3123cd9ce71e6..bca45ec85e0bf 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll @@ -53,12 +53,12 @@ target triple = "wasm32-unknown-unknown" ; LIME1-NEXT: .int8 43 ; LIME1-NEXT: .int8 22 ; LIME1-NEXT: .ascii "call-indirect-overlong" -; LIME1-NEXT: .int8 45 -; LIME1-NEXT: .int8 22 -; LIME1-NEXT: .ascii "libcall-thread-context" ; LIME1-NEXT: .int8 43 ; LIME1-NEXT: .int8 14 ; LIME1-NEXT: .ascii "extended-const" +; LIME1-NEXT: .int8 45 +; LIME1-NEXT: .int8 22 +; LIME1-NEXT: .ascii "libcall-thread-context" ; LIME1-NEXT: .int8 43 ; LIME1-NEXT: .int8 10 ; LIME1-NEXT: .ascii "multivalue" @@ -92,9 +92,6 @@ target triple = "wasm32-unknown-unknown" ; BLEEDING-EDGE-NEXT: .int8 43 ; BLEEDING-EDGE-NEXT: .int8 22 ; BLEEDING-EDGE-NEXT: .ascii "call-indirect-overlong" -; BLEEDING-EDGE-NEXT: .int8 45 -; BLEEDING-EDGE-NEXT: .int8 22 -; BLEEDING-EDGE-NEXT: .ascii "libcall-thread-context" ; BLEEDING-EDGE-NEXT: .int8 43 ; BLEEDING-EDGE-NEXT: .int8 18 ; BLEEDING-EDGE-NEXT: .ascii "exception-handling" @@ -107,6 +104,9 @@ target triple = "wasm32-unknown-unknown" ; BLEEDING-EDGE-NEXT: .int8 43 ; BLEEDING-EDGE-NEXT: .int8 2 ; BLEEDING-EDGE-NEXT: .ascii "gc" +; BLEEDING-EDGE-NEXT: .int8 45 +; BLEEDING-EDGE-NEXT: .int8 22 +; BLEEDING-EDGE-NEXT: .ascii "libcall-thread-context" ; BLEEDING-EDGE-NEXT: .int8 43 ; BLEEDING-EDGE-NEXT: .int8 11 ; BLEEDING-EDGE-NEXT: .ascii "multimemory" diff --git a/llvm/test/CodeGen/WebAssembly/target-features-tls.ll b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll index 9be61ade178d0..39d9be00a0eb0 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-tls.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll @@ -1,7 +1,7 @@ ; RUN: llc < %s -mcpu=mvp -mattr=-bulk-memory,atomics | FileCheck %s --check-prefixes NO-BULK-MEM ; RUN: llc < %s -mcpu=mvp -mattr=+bulk-memory,atomics | FileCheck %s --check-prefixes BULK-MEM -; RUN: llc < %s -mcpu=mvp -mattr=+component-model-threading,-bulk-memory,atomics | FileCheck %s --check-prefixes NO-BULK-MEM-CMTC -; RUN: llc < %s -mcpu=mvp -mattr=+component-model-threading,bulk-memory,atomics | FileCheck %s --check-prefixes BULK-MEM-CMTC +; RUN: llc < %s -mcpu=mvp -mattr=+libcall-thread-context,-bulk-memory,atomics | FileCheck %s --check-prefixes NO-BULK-MEM-LIBCALL +; RUN: llc < %s -mcpu=mvp -mattr=+libcall-thread-context,bulk-memory,atomics | FileCheck %s --check-prefixes BULK-MEM-LIBCALL ; Test that the target features section contains -atomics or +atomics ; for modules that have thread local storage in their source. @@ -36,32 +36,32 @@ target triple = "wasm32-unknown-unknown" ; BULK-MEM-NEXT: .tbss.foo,"T",@ ; -bulk-memory,+libcall-thread-context -; NO-BULK-MEM-CMTC-LABEL: .custom_section.target_features,"",@ -; NO-BULK-MEM-CMTC-NEXT: .int8 3 -; NO-BULK-MEM-CMTC-NEXT: .int8 43 -; NO-BULK-MEM-CMTC-NEXT: .int8 7 -; NO-BULK-MEM-CMTC-NEXT: .ascii "atomics" -; NO-BULK-MEM-CMTC-NEXT: .int8 43 -; NO-BULK-MEM-CMTC-NEXT: .int8 22 -; NO-BULK-MEM-CMTC-NEXT: .ascii "libcall-thread-context" -; NO-BULK-MEM-CMTC-NEXT: .int8 45 -; NO-BULK-MEM-CMTC-NEXT: .int8 10 -; NO-BULK-MEM-CMTC-NEXT: .ascii "shared-mem" -; NO-BULK-MEM-CMTC-NEXT: .bss.foo,"",@ +; NO-BULK-MEM-LIBCALL-LABEL: .custom_section.target_features,"",@ +; NO-BULK-MEM-LIBCALL-NEXT: .int8 3 +; NO-BULK-MEM-LIBCALL-NEXT: .int8 43 +; NO-BULK-MEM-LIBCALL-NEXT: .int8 7 +; NO-BULK-MEM-LIBCALL-NEXT: .ascii "atomics" +; NO-BULK-MEM-LIBCALL-NEXT: .int8 43 +; NO-BULK-MEM-LIBCALL-NEXT: .int8 22 +; NO-BULK-MEM-LIBCALL-NEXT: .ascii "libcall-thread-context" +; NO-BULK-MEM-LIBCALL-NEXT: .int8 45 +; NO-BULK-MEM-LIBCALL-NEXT: .int8 10 +; NO-BULK-MEM-LIBCALL-NEXT: .ascii "shared-mem" +; NO-BULK-MEM-LIBCALL-NEXT: .bss.foo,"",@ ; +bulk-memory,+libcall-thread-context -; BULK-MEM-CMTC-LABEL: .custom_section.target_features,"",@ -; BULK-MEM-CMTC-NEXT: .int8 4 -; BULK-MEM-CMTC-NEXT: .int8 43 -; BULK-MEM-CMTC-NEXT: .int8 7 -; BULK-MEM-CMTC-NEXT: .ascii "atomics" -; BULK-MEM-CMTC-NEXT: .int8 43 -; BULK-MEM-CMTC-NEXT: .int8 11 -; BULK-MEM-CMTC-NEXT: .ascii "bulk-memory" -; BULK-MEM-CMTC-NEXT: .int8 43 -; BULK-MEM-CMTC-NEXT: .int8 15 -; BULK-MEM-CMTC-NEXT: .ascii "bulk-memory-opt" -; BULK-MEM-CMTC-NEXT: .int8 43 -; BULK-MEM-CMTC-NEXT: .int8 22 -; BULK-MEM-CMTC-NEXT: .ascii "libcall-thread-context" -; BULK-MEM-CMTC-NEXT: .tbss.foo,"T",@ +; BULK-MEM-LIBCALL-LABEL: .custom_section.target_features,"",@ +; BULK-MEM-LIBCALL-NEXT: .int8 4 +; BULK-MEM-LIBCALL-NEXT: .int8 43 +; BULK-MEM-LIBCALL-NEXT: .int8 7 +; BULK-MEM-LIBCALL-NEXT: .ascii "atomics" +; BULK-MEM-LIBCALL-NEXT: .int8 43 +; BULK-MEM-LIBCALL-NEXT: .int8 11 +; BULK-MEM-LIBCALL-NEXT: .ascii "bulk-memory" +; BULK-MEM-LIBCALL-NEXT: .int8 43 +; BULK-MEM-LIBCALL-NEXT: .int8 15 +; BULK-MEM-LIBCALL-NEXT: .ascii "bulk-memory-opt" +; BULK-MEM-LIBCALL-NEXT: .int8 43 +; BULK-MEM-LIBCALL-NEXT: .int8 22 +; BULK-MEM-LIBCALL-NEXT: .ascii "libcall-thread-context" +; BULK-MEM-LIBCALL-NEXT: .tbss.foo,"T",@ From a1cacc9fee287f2e0ca83267458b5e60187afaae Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 1 Apr 2026 17:34:17 +0100 Subject: [PATCH 104/134] fmt --- lld/wasm/Writer.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 80c6070cfa517..c3eb03adf3921 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -638,17 +638,19 @@ void Writer::populateTargetFeatures() { }; tlsUsed = tlsUsed || llvm::any_of(file->segments, isTLS); - // Older versions of LLVM will not disallow the `libcall-thread-context` feature when - // emitting globals for thread context, so we use the presence of an imported `__stack_pointer` symbol - // as a heuristic to detect this case and disallow the feature. - if (!disallowed.contains("libcall-thread-context") && ctx.arg.libcallThreadContext) { - if (llvm::any_of(file->getSymbols(), [](const auto &sym) { + // Older versions of LLVM will not disallow the `libcall-thread-context` + // feature when emitting globals for thread context, so we use the presence + // of an imported `__stack_pointer` symbol as a heuristic to detect this + // case and disallow the feature. + if (!disallowed.contains("libcall-thread-context") && + ctx.arg.libcallThreadContext) { + if (llvm::any_of(file->getSymbols(), [](const auto &sym) { return sym && sym->getName() == "__stack_pointer" && sym->kind() == Symbol::UndefinedGlobalKind && sym->importModule && sym->importModule == "env"; })) { - disallowed.insert({"libcall-thread-context", std::string(fileName)}); - } + disallowed.insert({"libcall-thread-context", std::string(fileName)}); + } } } @@ -671,12 +673,14 @@ void Writer::populateTargetFeatures() { "' feature must be used in order to use shared memory"); } - // Special case for `libcall-thread-context` to give a more specific error message + // Special case for `libcall-thread-context` to give a more specific error + // message if (ctx.arg.libcallThreadContext) if (disallowed.contains("libcall-thread-context")) error("--libcall-thread-context is disallowed by " + disallowed["libcall-thread-context"] + - " because it uses globals for thread context rather than library function calls."); + " because it uses globals for thread context rather than library " + "function calls."); if (tlsUsed) { for (auto feature : {"atomics", "bulk-memory"}) @@ -703,7 +707,8 @@ void Writer::populateTargetFeatures() { continue; objectFeatures.insert(feature.Name); // libcall-thread-context is handled as a special case above - if (disallowed.contains(feature.Name) && feature.Name != "libcall-thread-context") + if (disallowed.contains(feature.Name) && + feature.Name != "libcall-thread-context") error(Twine("Target feature '") + feature.Name + "' used in " + fileName + " is disallowed by " + disallowed[feature.Name] + ". Use --no-check-features to suppress."); From dfbfcd979074abffbef86c8c06b7fbc022b52214 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Thu, 2 Apr 2026 19:33:03 +0100 Subject: [PATCH 105/134] Cleanup --- lld/wasm/SymbolTable.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp index e4ca7c56a7602..9bd93f317c3c5 100644 --- a/lld/wasm/SymbolTable.cpp +++ b/lld/wasm/SymbolTable.cpp @@ -222,7 +222,7 @@ DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name, uint32_t flags, InputFunction *function) { LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << name << "\n"); - assert(!find(name) || find(name)->isUndefined()); + assert(!find(name)); ctx.syntheticFunctions.emplace_back(function); return replaceSymbol(insertName(name).first, name, flags, nullptr, function); @@ -250,7 +250,7 @@ DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name, DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef name, uint32_t flags) { LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << name << "\n"); - assert(!find(name) || find(name)->isUndefined()); + assert(!find(name)); return replaceSymbol(insertName(name).first, name, flags | WASM_SYMBOL_ABSOLUTE); } @@ -259,7 +259,7 @@ DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef name, uint32_t flags, InputGlobal *global) { LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << name << " -> " << global << "\n"); - assert(!find(name) || find(name)->isUndefined()); + assert(!find(name)); ctx.syntheticGlobals.emplace_back(global); return replaceSymbol(insertName(name).first, name, flags, nullptr, global); From 5c04563a05849df6d634da7aee233e581a576a3d Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Thu, 2 Apr 2026 19:34:10 +0100 Subject: [PATCH 106/134] newline --- clang/test/Driver/wasm-features.c | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/test/Driver/wasm-features.c b/clang/test/Driver/wasm-features.c index df4b3652de353..5b6fa980854f3 100644 --- a/clang/test/Driver/wasm-features.c +++ b/clang/test/Driver/wasm-features.c @@ -124,4 +124,3 @@ // LIBCALL-THREAD-CONTEXT: "-target-feature" "+libcall-thread-context" // NO-LIBCALL-THREAD-CONTEXT: "-target-feature" "-libcall-thread-context" - From 08080df6823eb342414f2603071b7a5192944528 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 21 Apr 2026 11:49:53 +0100 Subject: [PATCH 107/134] Remove compiler flag and wasm feature --- clang/include/clang/Options/Options.td | 2 - clang/lib/Basic/Targets/WebAssembly.cpp | 8 --- clang/lib/Driver/ToolChains/WebAssembly.cpp | 12 +--- clang/test/Driver/wasm-features.c | 6 -- clang/test/Driver/wasm-toolchain.c | 11 --- .../test/Preprocessor/wasm-target-features.c | 4 +- lld/test/wasm/stack-pointer-abi.s | 25 +------ lld/test/wasm/thread-context-abi-mismatch.s | 19 ----- lld/test/wasm/tls-libcall.s | 5 +- .../WebAssembly/WebAssemblyRegStackify.cpp | 3 + .../WebAssembly/WebAssemblySubtarget.cpp | 7 +- .../WebAssembly/WebAssemblyTargetMachine.cpp | 13 +--- llvm/test/CodeGen/WebAssembly/stack-abi.ll | 4 +- .../WebAssembly/target-features-attrs.ll | 4 +- .../WebAssembly/target-features-cpus.ll | 20 ++---- .../target-features-thread-context.ll | 70 ------------------- .../WebAssembly/target-features-tls.ll | 33 --------- .../CodeGen/WebAssembly/thread_pointer.ll | 2 +- 18 files changed, 24 insertions(+), 224 deletions(-) delete mode 100644 llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index bab2b1835194e..412683fd968b0 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -5763,8 +5763,6 @@ def mfp16 : Flag<["-"], "mfp16">, Group; def mno_fp16 : Flag<["-"], "mno-fp16">, Group; def mgc : Flag<["-"], "mgc">, Group; def mno_gc : Flag<["-"], "mno-gc">, Group; -def mlibcall_thread_context : Joined<["-"], "mlibcall-thread-context">, Group; -def mno_libcall_thread_context : Joined<["-"], "mno-libcall-thread-context">, Group; def mmultimemory : Flag<["-"], "mmultimemory">, Group; def mno_multimemory : Flag<["-"], "mno-multimemory">, Group; def mmultivalue : Flag<["-"], "mmultivalue">, Group; diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp index ea5b06e4a6fde..46f9bd10f01ec 100644 --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -388,14 +388,6 @@ bool WebAssemblyTargetInfo::handleTargetFeatures( HasWideArithmetic = false; continue; } - if (Feature == "+libcall-thread-context") { - HasLibcallThreadContext = true; - continue; - } - if (Feature == "-libcall-thread-context") { - HasLibcallThreadContext = false; - continue; - } Diags.Report(diag::err_opt_not_valid_with_opt) << Feature << "-target-feature"; diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 6a1e7b6653348..ce0245773b75d 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -90,12 +90,7 @@ static bool WantsPthread(const llvm::Triple &Triple, const ArgList &Args) { static bool WantsLibcallThreadContext(const llvm::Triple &Triple, const ArgList &Args) { - // If the target is WASIP3, then enable the - // libcall-thread-context feature by default, unless explicitly - // disabled. - return Triple.getOS() == llvm::Triple::WASIp3 && - Args.hasFlag(options::OPT_mlibcall_thread_context, - options::OPT_mno_libcall_thread_context, true); + return Triple.getOS() == llvm::Triple::WASIp3; } void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -334,11 +329,6 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, options::OPT_fno_use_init_array, true)) CC1Args.push_back("-fno-use-init-array"); - if (WantsLibcallThreadContext(getTriple(), DriverArgs)) { - CC1Args.push_back("-target-feature"); - CC1Args.push_back("+libcall-thread-context"); - } - // '-pthread' implies atomics, bulk-memory, mutable-globals, and sign-ext if (WantsPthread(getTriple(), DriverArgs)) { if (DriverArgs.hasFlag(options::OPT_mno_atomics, options::OPT_matomics, diff --git a/clang/test/Driver/wasm-features.c b/clang/test/Driver/wasm-features.c index 5b6fa980854f3..9e523aa5b53b6 100644 --- a/clang/test/Driver/wasm-features.c +++ b/clang/test/Driver/wasm-features.c @@ -118,9 +118,3 @@ // COMPACT-IMPORTS: "-target-feature" "+compact-imports" // NO-COMPACT-IMPORTS: "-target-feature" "-compact-imports" - -// RUN: %clang --target=wasm32-unknown-unknown -### %s -mlibcall-thread-context 2>&1 | FileCheck %s -check-prefix=LIBCALL-THREAD-CONTEXT -// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-libcall-thread-context 2>&1 | FileCheck %s -check-prefix=NO-LIBCALL-THREAD-CONTEXT - -// LIBCALL-THREAD-CONTEXT: "-target-feature" "+libcall-thread-context" -// NO-LIBCALL-THREAD-CONTEXT: "-target-feature" "-libcall-thread-context" diff --git a/clang/test/Driver/wasm-toolchain.c b/clang/test/Driver/wasm-toolchain.c index d7b2e2d5a279d..492366516cdc6 100644 --- a/clang/test/Driver/wasm-toolchain.c +++ b/clang/test/Driver/wasm-toolchain.c @@ -304,14 +304,3 @@ // LINK_WALI_BASIC: "-cc1" {{.*}} "-o" "[[temp:[^"]*]]" // LINK_WALI_BASIC: wasm-ld{{.*}}" "-L/foo/lib/wasm32-linux-muslwali" "crt1.o" "[[temp]]" "-lc" "{{.*[/\\]}}libclang_rt.builtins.a" "-o" "a.out" -// `wasm32-wasip3` passes `+libcall-thread-context` by default. - -// RUN: %clang -### --target=wasm32-wasip3 --sysroot=/foo %s 2>&1 \ -// RUN: | FileCheck -check-prefix=LINK_WASIP3_LIBCALL_THREAD_CONTEXT %s -// LINK_WASIP3_LIBCALL_THREAD_CONTEXT: "-cc1" {{.*}} "-target-feature" "+libcall-thread-context" - -// `wasm32-wasip3` does not pass `+libcall-thread-context` when `-mno-libcall-thread-context` is used. - -// RUN: %clang -### --target=wasm32-wasip3 --sysroot=/foo -mno-libcall-thread-context %s 2>&1 \ -// RUN: | FileCheck -check-prefix=LINK_WASIP3_NO_LIBCALL_THREAD_CONTEXT %s -// LINK_WASIP3_NO_LIBCALL_THREAD_CONTEXT: "-cc1" {{.*}} "-target-feature" "-libcall-thread-context" diff --git a/clang/test/Preprocessor/wasm-target-features.c b/clang/test/Preprocessor/wasm-target-features.c index 7bb9429be507b..62dc330b6cad5 100644 --- a/clang/test/Preprocessor/wasm-target-features.c +++ b/clang/test/Preprocessor/wasm-target-features.c @@ -253,10 +253,10 @@ // BLEEDING-EDGE-NO-SIMD128-NOT: #define __wasm_simd128__ 1{{$}} // RUN: %clang -E -dM %s -o - 2>&1 \ -// RUN: -target wasm32-unknown-unknown -mlibcall-thread-context \ +// RUN: -target wasm32-wasip3 \ // RUN: | FileCheck %s -check-prefix=LIBCALL-THREAD-CONTEXT // RUN: %clang -E -dM %s -o - 2>&1 \ -// RUN: -target wasm64-unknown-unknown -mlibcall-thread-context \ +// RUN: -target wasm64-wasip3 \ // RUN: | FileCheck %s -check-prefix=LIBCALL-THREAD-CONTEXT // LIBCALL-THREAD-CONTEXT: #define __wasm_libcall_thread_context__ 1{{$}} diff --git a/lld/test/wasm/stack-pointer-abi.s b/lld/test/wasm/stack-pointer-abi.s index 63f3f5302966b..3bf5afc3c054d 100644 --- a/lld/test/wasm/stack-pointer-abi.s +++ b/lld/test/wasm/stack-pointer-abi.s @@ -1,32 +1,13 @@ -# RUN: split-file %s %t -# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/use.o %t/use.s -# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/disallow.o %t/disallow.s -# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/start.o %t/start.s -# RUN: wasm-ld --libcall-thread-context -o %t/libcall.wasm %t/use.o %t/start.o +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s +# RUN: wasm-ld --libcall-thread-context -o %t.wasm %t.o # RUN: obj2yaml %t/libcall.wasm | FileCheck %s --check-prefix=LIBCALL -# RUN: wasm-ld -o %t/global.wasm %t/disallow.o %t/start.o +# RUN: wasm-ld -o %t.wasm %t.o # RUN: obj2yaml %t/global.wasm | FileCheck %s --check-prefix=GLOBAL -#--- start.s .globl _start _start: .functype _start () -> () end_function -#--- disallow.s -.section .custom_section.target_features,"",@ - .int8 1 - .int8 45 - .int8 22 - .ascii "libcall-thread-context" - -#--- use.s - -.section .custom_section.target_features,"",@ - .int8 1 - .int8 43 - .int8 22 - .ascii "libcall-thread-context" - # LIBCALL: Name: __init_stack_pointer # GLOBAL: Name: __stack_pointer diff --git a/lld/test/wasm/thread-context-abi-mismatch.s b/lld/test/wasm/thread-context-abi-mismatch.s index a5bf661b11c40..69a707e4c86ab 100644 --- a/lld/test/wasm/thread-context-abi-mismatch.s +++ b/lld/test/wasm/thread-context-abi-mismatch.s @@ -10,12 +10,6 @@ # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/stack-pointer.o %t/stack-pointer.s # RUN: not wasm-ld --libcall-thread-context %t/start.o %t/stack-pointer.o -o %t/fail.wasm 2>&1 | FileCheck %s -# Test that explicitly disallowing the libcall-thread-context feature causes linking to fail -# with an error when other files use the feature. - -# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/disallow.o %t/disallow.s -# RUN: not wasm-ld --libcall-thread-context %t/start.o %t/disallow.o -o %t/fail.wasm 2>&1 | FileCheck %s - # CHECK: error: --libcall-thread-context is disallowed by {{.*}} because it uses globals for thread context rather than library function calls. #--- start.s @@ -24,12 +18,6 @@ _start: .functype _start () -> () end_function -.section .custom_section.target_features,"",@ - .int8 1 - .int8 43 - .int8 22 - .ascii "libcall-thread-context" - #--- stack-pointer.s .globaltype __stack_pointer, i32 @@ -39,10 +27,3 @@ use_stack_pointer: global.get __stack_pointer drop end_function - -#--- disallow.s -.section .custom_section.target_features,"",@ - .int8 1 - .int8 45 - .int8 22 - .ascii "libcall-thread-context" diff --git a/lld/test/wasm/tls-libcall.s b/lld/test/wasm/tls-libcall.s index 4e9c547c11196..df8b8f8be0207 100644 --- a/lld/test/wasm/tls-libcall.s +++ b/lld/test/wasm/tls-libcall.s @@ -36,10 +36,7 @@ tls2: .size tls2, 4 .section .custom_section.target_features,"",@ - .int8 3 - .int8 43 - .int8 22 - .ascii "libcall-thread-context" + .int8 2 .int8 43 .int8 11 .ascii "bulk-memory" diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp index 97f2ed0a828ba..025a0bee2717a 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -251,6 +251,9 @@ static void query(const MachineInstr &MI, bool &Read, bool &Write, !strcmp(MI.getOperand(0).getSymbolName(), "__stack_pointer")) StackPointer = true; + if (MI.isCall() && MI.getOperand(0).isSymbol() && !strcmp(MI.getOperand(0).getSymbolName(), "__wasm_get_stack_pointer")) + StackPointer = true; + // Analyze calls. if (MI.isCall()) { queryCallee(MI, Read, Write, Effects, StackPointer); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp index 50eef290bc5a7..96cb8ca538a67 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp @@ -40,11 +40,8 @@ WebAssemblySubtarget::initializeSubtargetDependencies(StringRef CPU, ParseSubtargetFeatures(CPU, /*TuneCPU*/ CPU, FS); - // WASIP3 implies using the libcall thread context by - // default, unless explicitly disabled. - if (!FS.contains("libcall-thread-context") && !HasLibcallThreadContext && - TargetTriple.getOS() == Triple::WASIp3) { - ToggleFeature(WebAssembly::FeatureLibcallThreadContext); + // WASIP3 implies using the libcall thread context. + if (!HasLibcallThreadContext && TargetTriple.getOS() == Triple::WASIp3) { HasLibcallThreadContext = true; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index 75485564fa210..a0c4166b96e82 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -292,7 +292,7 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { else if (StrippedTLS && !StrippedAtomics) stripAtomics(M); - recordFeatures(M, WasmTM->getTargetCPU(), Features, + recordFeatures(M, Features, StrippedAtomics || StrippedTLS); // Conservatively assume we have made some change @@ -396,7 +396,7 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { return Stripped; } - void recordFeatures(Module &M, StringRef CPU, const FeatureBitset &Features, + void recordFeatures(Module &M, const FeatureBitset &Features, bool Stripped) { for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) { if (Features[KV.Value]) { @@ -415,15 +415,6 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { M.addModuleFlag(Module::ModFlagBehavior::Error, "wasm-feature-shared-mem", wasm::WASM_FEATURE_PREFIX_DISALLOWED); } - - // Mark libcall-thread-context as disallowed when not in use to - // prevent linking object files with incompatible threading ABIs. - // This is implicit for MVP since the feature is not supported at all. - if (CPU != "mvp" && !Features[WebAssembly::FeatureLibcallThreadContext]) { - M.addModuleFlag(Module::ModFlagBehavior::Error, - "wasm-feature-libcall-thread-context", - wasm::WASM_FEATURE_PREFIX_DISALLOWED); - } } }; char CoalesceFeaturesAndStripAtomics::ID = 0; diff --git a/llvm/test/CodeGen/WebAssembly/stack-abi.ll b/llvm/test/CodeGen/WebAssembly/stack-abi.ll index 2cd6089dd5d65..684abb9d80028 100644 --- a/llvm/test/CodeGen/WebAssembly/stack-abi.ll +++ b/llvm/test/CodeGen/WebAssembly/stack-abi.ll @@ -1,5 +1,5 @@ -; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+libcall-thread-context | FileCheck --check-prefix=LIBCALL %s -; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=-libcall-thread-context | FileCheck --check-prefix=GLOBAL %s +; RUN: llc < %s --mtriple=wasm32-wasip3 -asm-verbose=false | FileCheck --check-prefix=LIBCALL %s +; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false | FileCheck --check-prefix=GLOBAL %s declare void @force_sp_save() define void @use_stack() #0 { diff --git a/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll b/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll index cf3b3fc5a2f4a..0e46b96591816 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-attrs.ll @@ -53,7 +53,7 @@ attributes #2 = { "target-features"="+reference-types" } ; CHECK: i32.store ; Features in function attributes: -; +atomics, +nontrapping-fptoint, +reference-types, -libcall-thread-context +; +atomics, +nontrapping-fptoint, +reference-types ; CHECK-LABEL: .custom_section.target_features,"",@ ; CHECK-NEXT: .int8 4 ; CHECK-NEXT: .int8 43 @@ -70,7 +70,7 @@ attributes #2 = { "target-features"="+reference-types" } ; CHECK-NEXT: .ascii "reference-types" ; Features in function attributes + features specified by -mattr= option: -; +atomics, +nontrapping-fptoint, +reference-types, +simd128, -libcall-thread-context +; +atomics, +nontrapping-fptoint, +reference-types, +simd128 ; SIMD128-LABEL: .custom_section.target_features,"",@ ; SIMD128-NEXT: .int8 5 ; SIMD128-NEXT: .int8 43 diff --git a/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll b/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll index bca45ec85e0bf..4a4973b034637 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll @@ -12,9 +12,9 @@ target triple = "wasm32-unknown-unknown" ; mvp: should not contain the target features section ; MVP-NOT: .custom_section.target_features,"",@ -; generic: +call-indirect-overlong, +multivalue, +mutable-globals, +reference-types, +sign-ext, -libcall-thread-context +; generic: +call-indirect-overlong, +multivalue, +mutable-globals, +reference-types, +sign-ext ; GENERIC-LABEL: .custom_section.target_features,"",@ -; GENERIC-NEXT: .int8 9 +; GENERIC-NEXT: .int8 8 ; GENERIC-NEXT: .int8 43 ; GENERIC-NEXT: .int8 11 ; GENERIC-NEXT: .ascii "bulk-memory" @@ -24,9 +24,6 @@ target triple = "wasm32-unknown-unknown" ; GENERIC-NEXT: .int8 43 ; GENERIC-NEXT: .int8 22 ; GENERIC-NEXT: .ascii "call-indirect-overlong" -; GENERIC-NEXT: .int8 45 -; GENERIC-NEXT: .int8 22 -; GENERIC-NEXT: .ascii "libcall-thread-context" ; GENERIC-NEXT: .int8 43 ; GENERIC-NEXT: .int8 10 ; GENERIC-NEXT: .ascii "multivalue" @@ -44,9 +41,9 @@ target triple = "wasm32-unknown-unknown" ; GENERIC-NEXT: .ascii "sign-ext" ; lime1: +bulk-memory-opt, +call-indirect-overlong, +extended-const, +multivalue, -; +mutable-globals, +nontrapping-fptoint, +sign-ext, -libcall-thread-context +; +mutable-globals, +nontrapping-fptoint, +sign-ext ; LIME1-LABEL: .custom_section.target_features,"",@ -; LIME1-NEXT: .int8 8 +; LIME1-NEXT: .int8 7 ; LIME1-NEXT: .int8 43 ; LIME1-NEXT: .int8 15 ; LIME1-NEXT: .ascii "bulk-memory-opt" @@ -56,9 +53,6 @@ target triple = "wasm32-unknown-unknown" ; LIME1-NEXT: .int8 43 ; LIME1-NEXT: .int8 14 ; LIME1-NEXT: .ascii "extended-const" -; LIME1-NEXT: .int8 45 -; LIME1-NEXT: .int8 22 -; LIME1-NEXT: .ascii "libcall-thread-context" ; LIME1-NEXT: .int8 43 ; LIME1-NEXT: .int8 10 ; LIME1-NEXT: .ascii "multivalue" @@ -77,9 +71,8 @@ target triple = "wasm32-unknown-unknown" ; +extended-const, +fp16, +gc, +multimemory, +multivalue, ; +mutable-globals, +nontrapping-fptoint, +relaxed-simd, ; +reference-types, +simd128, +sign-ext, +tail-call -; -libcall-thread-context ; BLEEDING-EDGE-LABEL: .section .custom_section.target_features,"",@ -; BLEEDING-EDGE-NEXT: .int8 18 +; BLEEDING-EDGE-NEXT: .int8 17 ; BLEEDING-EDGE-NEXT: .int8 43 ; BLEEDING-EDGE-NEXT: .int8 7 ; BLEEDING-EDGE-NEXT: .ascii "atomics" @@ -104,9 +97,6 @@ target triple = "wasm32-unknown-unknown" ; BLEEDING-EDGE-NEXT: .int8 43 ; BLEEDING-EDGE-NEXT: .int8 2 ; BLEEDING-EDGE-NEXT: .ascii "gc" -; BLEEDING-EDGE-NEXT: .int8 45 -; BLEEDING-EDGE-NEXT: .int8 22 -; BLEEDING-EDGE-NEXT: .ascii "libcall-thread-context" ; BLEEDING-EDGE-NEXT: .int8 43 ; BLEEDING-EDGE-NEXT: .int8 11 ; BLEEDING-EDGE-NEXT: .ascii "multimemory" diff --git a/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll b/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll deleted file mode 100644 index 703486e1971a2..0000000000000 --- a/llvm/test/CodeGen/WebAssembly/target-features-thread-context.ll +++ /dev/null @@ -1,70 +0,0 @@ -; RUN: llc < %s -mtriple=wasm32-wasip3 | FileCheck %s --check-prefix=WASIP3 -; RUN: llc < %s -mtriple=wasm32-wasip3 -mattr=-libcall-thread-context | FileCheck %s --check-prefix=EXPLICIT-DISABLE -; RUN: llc < %s -mtriple=wasm32-wasip1 | FileCheck %s --check-prefix=WASIP1 -; RUN: llc < %s -mtriple=wasm32-wasip2 | FileCheck %s --check-prefix=WASIP2 - -; Test that wasip3 target automatically enables libcall-thread-context - -; WASIP3: .section .custom_section.target_features,"",@ -; WASIP3-NEXT: .int8 9 -; WASIP3-NEXT: .int8 43 -; WASIP3-NEXT: .int8 11 -; WASIP3-NEXT: .ascii "bulk-memory" -; WASIP3-NEXT: .int8 43 -; WASIP3-NEXT: .int8 15 -; WASIP3-NEXT: .ascii "bulk-memory-opt" -; WASIP3-NEXT: .int8 43 -; WASIP3-NEXT: .int8 22 -; WASIP3-NEXT: .ascii "call-indirect-overlong" -; WASIP3-NEXT: .int8 43 -; WASIP3-NEXT: .int8 22 -; WASIP3-NEXT: .ascii "libcall-thread-context" - -; EXPLICIT-DISABLE: .section .custom_section.target_features,"",@ -; EXPLICIT-DISABLE-NEXT: .int8 9 -; EXPLICIT-DISABLE-NEXT: .int8 43 -; EXPLICIT-DISABLE-NEXT: .int8 11 -; EXPLICIT-DISABLE-NEXT: .ascii "bulk-memory" -; EXPLICIT-DISABLE-NEXT: .int8 43 -; EXPLICIT-DISABLE-NEXT: .int8 15 -; EXPLICIT-DISABLE-NEXT: .ascii "bulk-memory-opt" -; EXPLICIT-DISABLE-NEXT: .int8 43 -; EXPLICIT-DISABLE-NEXT: .int8 22 -; EXPLICIT-DISABLE-NEXT: .ascii "call-indirect-overlong" -; EXPLICIT-DISABLE-NEXT: .int8 45 -; EXPLICIT-DISABLE-NEXT: .int8 22 -; EXPLICIT-DISABLE-NEXT: .ascii "libcall-thread-context" - -; WASIP1: .section .custom_section.target_features,"",@ -; WASIP1-NEXT: .int8 9 -; WASIP1-NEXT: .int8 43 -; WASIP1-NEXT: .int8 11 -; WASIP1-NEXT: .ascii "bulk-memory" -; WASIP1-NEXT: .int8 43 -; WASIP1-NEXT: .int8 15 -; WASIP1-NEXT: .ascii "bulk-memory-opt" -; WASIP1-NEXT: .int8 43 -; WASIP1-NEXT: .int8 22 -; WASIP1-NEXT: .ascii "call-indirect-overlong" -; WASIP1-NEXT: .int8 45 -; WASIP1-NEXT: .int8 22 -; WASIP1-NEXT: .ascii "libcall-thread-context" - -; WASIP2: .section .custom_section.target_features,"",@ -; WASIP2-NEXT: .int8 9 -; WASIP2-NEXT: .int8 43 -; WASIP2-NEXT: .int8 11 -; WASIP2-NEXT: .ascii "bulk-memory" -; WASIP2-NEXT: .int8 43 -; WASIP2-NEXT: .int8 15 -; WASIP2-NEXT: .ascii "bulk-memory-opt" -; WASIP2-NEXT: .int8 43 -; WASIP2-NEXT: .int8 22 -; WASIP2-NEXT: .ascii "call-indirect-overlong" -; WASIP2-NEXT: .int8 45 -; WASIP2-NEXT: .int8 22 -; WASIP2-NEXT: .ascii "libcall-thread-context" - -define void @test() { - ret void -} diff --git a/llvm/test/CodeGen/WebAssembly/target-features-tls.ll b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll index 39d9be00a0eb0..4abe01a73aeee 100644 --- a/llvm/test/CodeGen/WebAssembly/target-features-tls.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll @@ -1,7 +1,5 @@ ; RUN: llc < %s -mcpu=mvp -mattr=-bulk-memory,atomics | FileCheck %s --check-prefixes NO-BULK-MEM ; RUN: llc < %s -mcpu=mvp -mattr=+bulk-memory,atomics | FileCheck %s --check-prefixes BULK-MEM -; RUN: llc < %s -mcpu=mvp -mattr=+libcall-thread-context,-bulk-memory,atomics | FileCheck %s --check-prefixes NO-BULK-MEM-LIBCALL -; RUN: llc < %s -mcpu=mvp -mattr=+libcall-thread-context,bulk-memory,atomics | FileCheck %s --check-prefixes BULK-MEM-LIBCALL ; Test that the target features section contains -atomics or +atomics ; for modules that have thread local storage in their source. @@ -34,34 +32,3 @@ target triple = "wasm32-unknown-unknown" ; BULK-MEM-NEXT: .int8 15 ; BULK-MEM-NEXT: .ascii "bulk-memory-opt" ; BULK-MEM-NEXT: .tbss.foo,"T",@ - -; -bulk-memory,+libcall-thread-context -; NO-BULK-MEM-LIBCALL-LABEL: .custom_section.target_features,"",@ -; NO-BULK-MEM-LIBCALL-NEXT: .int8 3 -; NO-BULK-MEM-LIBCALL-NEXT: .int8 43 -; NO-BULK-MEM-LIBCALL-NEXT: .int8 7 -; NO-BULK-MEM-LIBCALL-NEXT: .ascii "atomics" -; NO-BULK-MEM-LIBCALL-NEXT: .int8 43 -; NO-BULK-MEM-LIBCALL-NEXT: .int8 22 -; NO-BULK-MEM-LIBCALL-NEXT: .ascii "libcall-thread-context" -; NO-BULK-MEM-LIBCALL-NEXT: .int8 45 -; NO-BULK-MEM-LIBCALL-NEXT: .int8 10 -; NO-BULK-MEM-LIBCALL-NEXT: .ascii "shared-mem" -; NO-BULK-MEM-LIBCALL-NEXT: .bss.foo,"",@ - -; +bulk-memory,+libcall-thread-context -; BULK-MEM-LIBCALL-LABEL: .custom_section.target_features,"",@ -; BULK-MEM-LIBCALL-NEXT: .int8 4 -; BULK-MEM-LIBCALL-NEXT: .int8 43 -; BULK-MEM-LIBCALL-NEXT: .int8 7 -; BULK-MEM-LIBCALL-NEXT: .ascii "atomics" -; BULK-MEM-LIBCALL-NEXT: .int8 43 -; BULK-MEM-LIBCALL-NEXT: .int8 11 -; BULK-MEM-LIBCALL-NEXT: .ascii "bulk-memory" -; BULK-MEM-LIBCALL-NEXT: .int8 43 -; BULK-MEM-LIBCALL-NEXT: .int8 15 -; BULK-MEM-LIBCALL-NEXT: .ascii "bulk-memory-opt" -; BULK-MEM-LIBCALL-NEXT: .int8 43 -; BULK-MEM-LIBCALL-NEXT: .int8 22 -; BULK-MEM-LIBCALL-NEXT: .ascii "libcall-thread-context" -; BULK-MEM-LIBCALL-NEXT: .tbss.foo,"T",@ diff --git a/llvm/test/CodeGen/WebAssembly/thread_pointer.ll b/llvm/test/CodeGen/WebAssembly/thread_pointer.ll index 1be5e7833e05c..875f0f4c84c39 100644 --- a/llvm/test/CodeGen/WebAssembly/thread_pointer.ll +++ b/llvm/test/CodeGen/WebAssembly/thread_pointer.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=wasm32-unknown-unknown | FileCheck %s --check-prefix=WASM32 ; RUN: llc < %s -mtriple=wasm64-unknown-unknown | FileCheck %s --check-prefix=WASM64 -; RUN: llc < %s -mtriple=wasm32-unknown-unknown -mattr=+libcall-thread-context | FileCheck %s --check-prefix=WASM32-LIBCALL +; RUN: llc < %s -mtriple=wasm32-wasip3 | FileCheck %s --check-prefix=WASM32-LIBCALL declare ptr @llvm.thread.pointer() From 92880bdb769db9988848b1a2c9f92adc95c49576 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 21 Apr 2026 11:55:53 +0100 Subject: [PATCH 108/134] fmt --- llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp | 3 ++- llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp index 025a0bee2717a..9c827f294da7c 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -251,7 +251,8 @@ static void query(const MachineInstr &MI, bool &Read, bool &Write, !strcmp(MI.getOperand(0).getSymbolName(), "__stack_pointer")) StackPointer = true; - if (MI.isCall() && MI.getOperand(0).isSymbol() && !strcmp(MI.getOperand(0).getSymbolName(), "__wasm_get_stack_pointer")) + if (MI.isCall() && MI.getOperand(0).isSymbol() && + !strcmp(MI.getOperand(0).getSymbolName(), "__wasm_get_stack_pointer")) StackPointer = true; // Analyze calls. diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index a0c4166b96e82..f51b7ba9b7963 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -292,8 +292,7 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { else if (StrippedTLS && !StrippedAtomics) stripAtomics(M); - recordFeatures(M, Features, - StrippedAtomics || StrippedTLS); + recordFeatures(M, Features, StrippedAtomics || StrippedTLS); // Conservatively assume we have made some change return true; @@ -396,8 +395,7 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass { return Stripped; } - void recordFeatures(Module &M, const FeatureBitset &Features, - bool Stripped) { + void recordFeatures(Module &M, const FeatureBitset &Features, bool Stripped) { for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) { if (Features[KV.Value]) { // Mark features as used From 4f658aec562908f72ecdfde67385c80fe9cd0f7b Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 21 Apr 2026 13:22:04 +0100 Subject: [PATCH 109/134] Set HasLibcallThreadContext --- clang/lib/Basic/Targets/WebAssembly.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h index 9199dc9f79cd7..6085197498163 100644 --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -111,6 +111,8 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo { PtrDiffType = SignedLong; IntPtrType = SignedLong; } + if (T.getOS() == llvm::Triple::WASIp3) + HasLibcallThreadContext = true; } StringRef getABI() const override; From a3a46eb67fc4da6fb13e4a6370143c4cda038101 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 21 Apr 2026 13:37:50 +0100 Subject: [PATCH 110/134] Fix test --- lld/test/wasm/stack-pointer-abi.s | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lld/test/wasm/stack-pointer-abi.s b/lld/test/wasm/stack-pointer-abi.s index 3bf5afc3c054d..6bfe0d4a8daa8 100644 --- a/lld/test/wasm/stack-pointer-abi.s +++ b/lld/test/wasm/stack-pointer-abi.s @@ -1,8 +1,8 @@ # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s -# RUN: wasm-ld --libcall-thread-context -o %t.wasm %t.o -# RUN: obj2yaml %t/libcall.wasm | FileCheck %s --check-prefix=LIBCALL -# RUN: wasm-ld -o %t.wasm %t.o -# RUN: obj2yaml %t/global.wasm | FileCheck %s --check-prefix=GLOBAL +# RUN: wasm-ld --libcall-thread-context -o %t.libcall.wasm %t.o +# RUN: obj2yaml %t.libcall.wasm | FileCheck %s --check-prefix=LIBCALL +# RUN: wasm-ld -o %t.global.wasm %t.o +# RUN: obj2yaml %t.global.wasm | FileCheck %s --check-prefix=GLOBAL .globl _start _start: From ed65fda90afb06f2ad100e643b051822db3b35cc Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 22 Apr 2026 09:45:04 +0100 Subject: [PATCH 111/134] Debug info fixes --- .../WebAssembly/WebAssemblyExplicitLocals.cpp | 11 ++++++++- .../WebAssembly/WebAssemblyFrameLowering.cpp | 5 ++++ .../WebAssembly/WebAssemblyRegStackify.cpp | 24 ++++++++++++++----- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp index 5c3127e2d3dc6..84761e08be88e 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp @@ -366,7 +366,16 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) { const TargetRegisterClass *RC = MRI.getRegClass(OldReg); Register NewReg = MRI.createVirtualRegister(RC); auto InsertPt = std::next(MI.getIterator()); - if (UseEmpty[OldReg.virtRegIndex()]) { + // When libcalls are emitted for thread context, the frame base vreg has + // an implicit use in the DW_AT_frame_base debug info, so we should not + // remove it. + bool NeedsRegForDebug = + MFI.isFrameBaseVirtual() && + OldReg == MFI.getFrameBaseVreg() && + MF.getFunction().getSubprogram() && + MF.getSubtarget().hasLibcallThreadContext(); + if (UseEmpty[OldReg.virtRegIndex()] && + !NeedsRegForDebug) { unsigned Opc = getDropOpcode(RC); MachineInstr *Drop = BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc)) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index 180c8446f1a39..21014074aecb1 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -407,6 +407,11 @@ WebAssemblyFrameLowering::getDwarfFrameBase(const MachineFunction &MF) const { if (needsSP(MF) && MFI.isFrameBaseVirtual()) { unsigned LocalNum = MFI.getFrameBaseLocal(); Loc.Location.WasmLoc = {WebAssembly::TI_LOCAL, LocalNum}; + } else if (MF.getSubtarget().hasLibcallThreadContext()) { + // There is no __stack_pointer global in libcall thread context mode, so + // TI_GLOBAL_RELOC would produce a bogus relocation. Ideally, this case would never happen, + // but if it does, fall back to a CFA directive. + Loc.Kind = DwarfFrameBase::CFA; } else { // TODO: This should work on a breakpoint at a function with no frame, // but probably won't work for traversing up the stack. diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp index 9c827f294da7c..6657cf072053c 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -291,17 +291,28 @@ static MachineInstr *getVRegDef(unsigned Reg, const MachineInstr *Insert, // generalization of MachineRegisterInfo::hasOneNonDBGUse that uses // LiveIntervals to handle complex cases in optimized code. static bool hasSingleUse(unsigned Reg, MachineRegisterInfo &MRI, - WebAssemblyFunctionInfo &MFI, bool Optimize, + const MachineFunction &MF, bool Optimize, MachineInstr *Def, LiveIntervals *LIS) { + auto& MFI = *MF.getInfo(); + // The frame base always has an implicit DBG use as DW_AT_frame_base. + if (MFI.isFrameBaseVirtual() && MFI.getFrameBaseVreg() == Reg) { + // When using global thread context, the frame base can be encoded + // as an offset from __stack_pointer, so the vreg can be stackified. + // However, when using libcall thread context, we need to keep the frame + // base vreg around if debug info is enabled, because there is no + // global to refer to. + bool NeedsRegForDebug = + MF.getFunction().getSubprogram() && + MF.getSubtarget().hasLibcallThreadContext(); + if (!Optimize || NeedsRegForDebug) + return false; + } if (!Optimize) { // Using "hasOneUse" instead of "hasOneNonDBGUse" here because we don't // want to stackify DBG_VALUE operands - WASM stack locations are less // useful and less widely supported than WASM local locations. if (!MRI.hasOneUse(Reg)) return false; - // The frame base always has an implicit DBG use as DW_AT_frame_base. - if (MFI.isFrameBaseVirtual() && MFI.getFrameBaseVreg() == Reg) - return false; return true; } @@ -922,7 +933,8 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { bool CanMove = SameBlock && isSafeToMove(Def, &Use, Insert, MFI, MRI, Optimize) && !TreeWalker.isOnStack(Reg); - if (CanMove && hasSingleUse(Reg, MRI, MFI, Optimize, DefI, LIS)) { + + if (CanMove && hasSingleUse(Reg, MRI, MF, Optimize, DefI, LIS)) { Insert = moveForSingleUse(Reg, Use, DefI, MBB, Insert, LIS, MFI, MRI); // If we are removing the frame base reg completely, remove the debug @@ -964,7 +976,7 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { Register UseReg = SubsequentUse->getReg(); // TODO: This single-use restriction could be relaxed by using tees if (DefReg != UseReg || - !hasSingleUse(DefReg, MRI, MFI, Optimize, nullptr, nullptr)) + !hasSingleUse(DefReg, MRI, MF, Optimize, nullptr, nullptr)) break; MFI.stackifyVReg(MRI, DefReg); ++SubsequentDef; From f0651c3e53e5d0aeffc9c087fb84cd0e0fbcbb9c Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 22 Apr 2026 10:50:56 +0100 Subject: [PATCH 112/134] Remove __init_XXX from codeGen --- llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index fdfb33610d18e..2925d7a18e975 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -233,8 +233,8 @@ 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 == "__init_stack_pointer" || - Name == "__tls_base" || Name == "__init_tls_base" || + if (Name == "__stack_pointer" || + Name == "__tls_base" || Name == "__memory_base" || Name == "__table_base" || Name == "__tls_size" || Name == "__tls_align") { bool Mutable = Name == "__stack_pointer" || Name == "__tls_base"; From a69b43d8d6264ea4fc9182025f11b0ec97c382e7 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 22 Apr 2026 10:51:27 +0100 Subject: [PATCH 113/134] fmt --- llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp | 3 +-- llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp | 7 ++++--- llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 2925d7a18e975..c25972343c96a 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -233,8 +233,7 @@ 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 == "__tls_base" || Name == "__memory_base" || Name == "__table_base" || Name == "__tls_size" || Name == "__tls_align") { bool Mutable = Name == "__stack_pointer" || Name == "__tls_base"; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index 21014074aecb1..61665d2b51f36 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -407,10 +407,11 @@ WebAssemblyFrameLowering::getDwarfFrameBase(const MachineFunction &MF) const { if (needsSP(MF) && MFI.isFrameBaseVirtual()) { unsigned LocalNum = MFI.getFrameBaseLocal(); Loc.Location.WasmLoc = {WebAssembly::TI_LOCAL, LocalNum}; - } else if (MF.getSubtarget().hasLibcallThreadContext()) { + } else if (MF.getSubtarget() + .hasLibcallThreadContext()) { // There is no __stack_pointer global in libcall thread context mode, so - // TI_GLOBAL_RELOC would produce a bogus relocation. Ideally, this case would never happen, - // but if it does, fall back to a CFA directive. + // TI_GLOBAL_RELOC would produce a bogus relocation. Ideally, this case + // would never happen, but if it does, fall back to a CFA directive. Loc.Kind = DwarfFrameBase::CFA; } else { // TODO: This should work on a breakpoint at a function with no frame, diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp index 6657cf072053c..f211d9e120526 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -293,10 +293,10 @@ static MachineInstr *getVRegDef(unsigned Reg, const MachineInstr *Insert, static bool hasSingleUse(unsigned Reg, MachineRegisterInfo &MRI, const MachineFunction &MF, bool Optimize, MachineInstr *Def, LiveIntervals *LIS) { - auto& MFI = *MF.getInfo(); + auto &MFI = *MF.getInfo(); // The frame base always has an implicit DBG use as DW_AT_frame_base. if (MFI.isFrameBaseVirtual() && MFI.getFrameBaseVreg() == Reg) { - // When using global thread context, the frame base can be encoded + // When using global thread context, the frame base can be encoded // as an offset from __stack_pointer, so the vreg can be stackified. // However, when using libcall thread context, we need to keep the frame // base vreg around if debug info is enabled, because there is no From 7cf2aa7dc41ae9d14b300d0c189b4b38a2bcfed3 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 11 May 2026 09:50:40 +0100 Subject: [PATCH 114/134] fmt --- .../Target/WebAssembly/WebAssemblyExplicitLocals.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp index 84761e08be88e..e05b23d255894 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp @@ -366,16 +366,14 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) { const TargetRegisterClass *RC = MRI.getRegClass(OldReg); Register NewReg = MRI.createVirtualRegister(RC); auto InsertPt = std::next(MI.getIterator()); - // When libcalls are emitted for thread context, the frame base vreg has - // an implicit use in the DW_AT_frame_base debug info, so we should not - // remove it. + // When libcalls are emitted for thread context, the frame base vreg + // has an implicit use in the DW_AT_frame_base debug info, so we + // should not remove it. bool NeedsRegForDebug = - MFI.isFrameBaseVirtual() && - OldReg == MFI.getFrameBaseVreg() && + MFI.isFrameBaseVirtual() && OldReg == MFI.getFrameBaseVreg() && MF.getFunction().getSubprogram() && MF.getSubtarget().hasLibcallThreadContext(); - if (UseEmpty[OldReg.virtRegIndex()] && - !NeedsRegForDebug) { + if (UseEmpty[OldReg.virtRegIndex()] && !NeedsRegForDebug) { unsigned Opc = getDropOpcode(RC); MachineInstr *Drop = BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc)) From fb482d1bea5b5a0fb0c499f408025a36cf9c3c4f Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 11 May 2026 15:38:05 +0100 Subject: [PATCH 115/134] Remove extra line --- clang/test/Driver/wasm-toolchain.c | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/test/Driver/wasm-toolchain.c b/clang/test/Driver/wasm-toolchain.c index 492366516cdc6..29a94aeec77a9 100644 --- a/clang/test/Driver/wasm-toolchain.c +++ b/clang/test/Driver/wasm-toolchain.c @@ -303,4 +303,3 @@ // RUN: | FileCheck -check-prefix=LINK_WALI_BASIC %s // LINK_WALI_BASIC: "-cc1" {{.*}} "-o" "[[temp:[^"]*]]" // LINK_WALI_BASIC: wasm-ld{{.*}}" "-L/foo/lib/wasm32-linux-muslwali" "crt1.o" "[[temp]]" "-lc" "{{.*[/\\]}}libclang_rt.builtins.a" "-o" "a.out" - From aa5c37fd1d95c05b6b429221b78149a8e4e34203 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 11 May 2026 15:39:11 +0100 Subject: [PATCH 116/134] Newline --- lld/wasm/SyntheticSections.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index 74ac9aa944772..d1a01c7ec3f9d 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -61,6 +61,7 @@ void writeGetTLSBase(const Ctx &ctx, raw_ostream &os) { writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "__tls_base"); } } + } // namespace bool DylinkSection::isNeeded() const { From b92a49cdb3d231a68a0625b9ef042a838cc83216 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 11 May 2026 15:41:30 +0100 Subject: [PATCH 117/134] Newline --- llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp index f211d9e120526..9015ceab87fb7 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -933,7 +933,6 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { bool CanMove = SameBlock && isSafeToMove(Def, &Use, Insert, MFI, MRI, Optimize) && !TreeWalker.isOnStack(Reg); - if (CanMove && hasSingleUse(Reg, MRI, MF, Optimize, DefI, LIS)) { Insert = moveForSingleUse(Reg, Use, DefI, MBB, Insert, LIS, MFI, MRI); From a50c1e735434074db2c2a7953154c6e94048ce31 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 12 May 2026 08:34:59 +0100 Subject: [PATCH 118/134] Reflow --- lld/wasm/Writer.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index bf7a9e75ff9d6..f1f783c8bdab7 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1392,8 +1392,8 @@ void Writer::createInitMemoryFunction() { } // When we initialize the TLS segment we also set the TLS base. - // This allows the runtime to use this - // static copy of the TLS data for the first/main thread. + // This allows the runtime to use this static copy of the TLS data + // for the first/main thread. if (ctx.arg.sharedMemory && s->isTLS()) { if (ctx.isPic) { // Cache the result of the addionion in local 0 @@ -1675,14 +1675,7 @@ void Writer::createInitTLSFunction() { writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); writeUleb128(os, 0, "local index"); - if (ctx.arg.libcallThreadContext) { - writeU8(os, WASM_OPCODE_CALL, "call"); - writeUleb128(os, ctx.sym.setTLSBase->getFunctionIndex(), - "function index"); - } else { - writeU8(os, WASM_OPCODE_GLOBAL_SET, "global.set"); - writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "global index"); - } + writeSetTLSBase(ctx, os); // FIXME(wvo): this local needs to be I64 in wasm64, or we need an extend // op. From b467230209e7fff68645f16ac616d296ba0f3532 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 12 May 2026 11:14:27 +0100 Subject: [PATCH 119/134] Remove unnecessary feature code --- llvm/lib/Target/WebAssembly/WebAssembly.td | 4 ---- llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td | 5 ----- 2 files changed, 9 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.td b/llvm/lib/Target/WebAssembly/WebAssembly.td index 187f99e9df07d..06cf468d02eba 100644 --- a/llvm/lib/Target/WebAssembly/WebAssembly.td +++ b/llvm/lib/Target/WebAssembly/WebAssembly.td @@ -37,10 +37,6 @@ def FeatureCallIndirectOverlong : SubtargetFeature<"call-indirect-overlong", "HasCallIndirectOverlong", "true", "Enable overlong encoding for call_indirect immediates">; -def FeatureLibcallThreadContext : - SubtargetFeature<"libcall-thread-context", "HasLibcallThreadContext", "true", - "Enable using library calls for managing thread context">; - def FeatureExceptionHandling : SubtargetFeature<"exception-handling", "HasExceptionHandling", "true", "Enable Wasm exception handling">; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td index 9f9e39aa17d3c..95b2021176b68 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -53,11 +53,6 @@ def HasFP16 : def HasGC : Predicate<"Subtarget->hasGC()">, AssemblerPredicate<(all_of FeatureGC), "gc">; -def HasLibcallThreadContext : - Predicate<"Subtarget->hasLibcallThreadContext()">, - AssemblerPredicate<(all_of FeatureLibcallThreadContext), - "libcall-thread-context">; - def HasMultiMemory : Predicate<"Subtarget->hasMultiMemory()">, AssemblerPredicate<(all_of FeatureMultiMemory), "multimemory">; From 45623058ae80e37417d51670942ffff13a3a02d0 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 12 May 2026 11:24:06 +0100 Subject: [PATCH 120/134] Formatting --- llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp index 96cb8ca538a67..cd4fd045ee17f 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp @@ -41,9 +41,8 @@ WebAssemblySubtarget::initializeSubtargetDependencies(StringRef CPU, ParseSubtargetFeatures(CPU, /*TuneCPU*/ CPU, FS); // WASIP3 implies using the libcall thread context. - if (!HasLibcallThreadContext && TargetTriple.getOS() == Triple::WASIp3) { + if (!HasLibcallThreadContext && TargetTriple.getOS() == Triple::WASIp3) HasLibcallThreadContext = true; - } FeatureBitset Bits = getFeatureBits(); From 92c7b067aac43f0908232c21924415f63c715373 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 12 May 2026 11:24:41 +0100 Subject: [PATCH 121/134] Simplify condition --- llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp index cd4fd045ee17f..6326b7d76db82 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp @@ -41,7 +41,7 @@ WebAssemblySubtarget::initializeSubtargetDependencies(StringRef CPU, ParseSubtargetFeatures(CPU, /*TuneCPU*/ CPU, FS); // WASIP3 implies using the libcall thread context. - if (!HasLibcallThreadContext && TargetTriple.getOS() == Triple::WASIp3) + if (TargetTriple.getOS() == Triple::WASIp3) HasLibcallThreadContext = true; FeatureBitset Bits = getFeatureBits(); From b2d8f85ed2998c727a601cda6ae6ef65b5387ed1 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 12 May 2026 12:26:24 +0100 Subject: [PATCH 122/134] Revert whitespace change --- llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index c25972343c96a..27ea1940e657b 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -236,7 +236,8 @@ MCSymbol *WebAssemblyAsmPrinter::getOrCreateWasmSymbol(StringRef Name) { if (Name == "__stack_pointer" || Name == "__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 From 5ebc91d61d427714a851b3775034360167125aa5 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 12 May 2026 12:27:06 +0100 Subject: [PATCH 123/134] fmt --- lld/wasm/Writer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index f1f783c8bdab7..a2172bc74ccb4 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1392,7 +1392,7 @@ void Writer::createInitMemoryFunction() { } // When we initialize the TLS segment we also set the TLS base. - // This allows the runtime to use this static copy of the TLS data + // This allows the runtime to use this static copy of the TLS data // for the first/main thread. if (ctx.arg.sharedMemory && s->isTLS()) { if (ctx.isPic) { From f17746113981caaa359bc6aed5c3a8845dd6ceaf Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 12 May 2026 12:38:51 +0100 Subject: [PATCH 124/134] Assert for frame lowering issues --- .../Target/WebAssembly/WebAssemblyFrameLowering.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index 25b5b62f05d44..e68c3495fa4cf 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -407,13 +407,12 @@ WebAssemblyFrameLowering::getDwarfFrameBase(const MachineFunction &MF) const { if (needsSP(MF) && MFI.isFrameBaseVirtual()) { unsigned LocalNum = MFI.getFrameBaseLocal(); Loc.Location.WasmLoc = {WebAssembly::TI_LOCAL, LocalNum}; - } else if (MF.getSubtarget() - .hasLibcallThreadContext()) { - // There is no __stack_pointer global in libcall thread context mode, so - // TI_GLOBAL_RELOC would produce a bogus relocation. Ideally, this case - // would never happen, but if it does, fall back to a CFA directive. - Loc.Kind = DwarfFrameBase::CFA; } else { + // There is no __stack_pointer global in libcall thread context mode, so + // TI_GLOBAL_RELOC would produce a bogus relocation. We take care to ensure + // that this code is not reached in that case, but assert here to be sure. + assert(!MF.getSubtarget().hasLibcallThreadContext()); + // TODO: This should work on a breakpoint at a function with no frame, // but probably won't work for traversing up the stack. Loc.Location.WasmLoc = {WebAssembly::TI_GLOBAL_RELOC, 0}; From 9a7eac90f39ec0f26f5d15869f1ae9ca812ac835 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 12 May 2026 12:49:50 +0100 Subject: [PATCH 125/134] Clean up error in wasm-ld --- lld/wasm/Writer.cpp | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index a2172bc74ccb4..1758953292160 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -645,20 +645,15 @@ void Writer::populateTargetFeatures() { }; tlsUsed = tlsUsed || llvm::any_of(file->segments, isTLS); - // Older versions of LLVM will not disallow the `libcall-thread-context` - // feature when emitting globals for thread context, so we use the presence - // of an imported `__stack_pointer` symbol as a heuristic to detect this - // case and disallow the feature. - if (!disallowed.contains("libcall-thread-context") && - ctx.arg.libcallThreadContext) { - if (llvm::any_of(file->getSymbols(), [](const auto &sym) { - return sym && sym->getName() == "__stack_pointer" && - sym->kind() == Symbol::UndefinedGlobalKind && - sym->importModule && sym->importModule == "env"; - })) { - disallowed.insert({"libcall-thread-context", std::string(fileName)}); - } - } + // Ensure that we're not mixing incompatible thread context models + if (ctx.arg.libcallThreadContext && + llvm::any_of(file->getSymbols(), [](const auto &sym) { + return sym && sym->getName() == "__stack_pointer" && + sym->kind() == Symbol::UndefinedGlobalKind && + sym->importModule && sym->importModule == "env"; + })) + error(fileName + ": object file uses globals for thread context, " + "but --libcall-thread-context was specified"); } if (inferFeatures) @@ -680,15 +675,6 @@ void Writer::populateTargetFeatures() { "' feature must be used in order to use shared memory"); } - // Special case for `libcall-thread-context` to give a more specific error - // message - if (ctx.arg.libcallThreadContext) - if (disallowed.contains("libcall-thread-context")) - error("--libcall-thread-context is disallowed by " + - disallowed["libcall-thread-context"] + - " because it uses globals for thread context rather than library " - "function calls."); - if (tlsUsed) { for (auto feature : {"atomics", "bulk-memory"}) if (!allowed.contains(feature)) From 7b0520d7f5456f26b8cf11aca7b1e46b6f166d3c Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Tue, 12 May 2026 12:52:31 +0100 Subject: [PATCH 126/134] fmt --- llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp | 3 +-- llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 27ea1940e657b..c25972343c96a 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -236,8 +236,7 @@ MCSymbol *WebAssemblyAsmPrinter::getOrCreateWasmSymbol(StringRef Name) { if (Name == "__stack_pointer" || Name == "__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 diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index e68c3495fa4cf..50f820086c5a6 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -412,7 +412,7 @@ WebAssemblyFrameLowering::getDwarfFrameBase(const MachineFunction &MF) const { // TI_GLOBAL_RELOC would produce a bogus relocation. We take care to ensure // that this code is not reached in that case, but assert here to be sure. assert(!MF.getSubtarget().hasLibcallThreadContext()); - + // TODO: This should work on a breakpoint at a function with no frame, // but probably won't work for traversing up the stack. Loc.Location.WasmLoc = {WebAssembly::TI_GLOBAL_RELOC, 0}; From 880a277fcc3022fdd17ef5f5fa92fce1a8e8d82f Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 13 May 2026 09:25:59 +0100 Subject: [PATCH 127/134] fix tests --- lld/test/wasm/thread-context-abi-mismatch.s | 3 ++- llvm/test/CodeGen/WebAssembly/tls-local-exec.ll | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lld/test/wasm/thread-context-abi-mismatch.s b/lld/test/wasm/thread-context-abi-mismatch.s index 69a707e4c86ab..ac1822e89434b 100644 --- a/lld/test/wasm/thread-context-abi-mismatch.s +++ b/lld/test/wasm/thread-context-abi-mismatch.s @@ -10,7 +10,8 @@ # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/stack-pointer.o %t/stack-pointer.s # RUN: not wasm-ld --libcall-thread-context %t/start.o %t/stack-pointer.o -o %t/fail.wasm 2>&1 | FileCheck %s -# CHECK: error: --libcall-thread-context is disallowed by {{.*}} because it uses globals for thread context rather than library function calls. +# CHECK: stack-pointer.o: object file uses globals for thread context, but --libcall-thread-context was specified +# | ^ #--- start.s .globl _start diff --git a/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll b/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll index 586f5234d9bc4..1807ea2263338 100644 --- a/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll +++ b/llvm/test/CodeGen/WebAssembly/tls-local-exec.ll @@ -1,16 +1,16 @@ ; Run the tests with the `localexec` TLS mode specified. ; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,TLS %s ; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS %s -; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+libcall-thread-context,bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS-LIBCALL %s +; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -mtriple=wasm32-wasip3 -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS-LIBCALL %s ; Also, run the same tests without a specified TLS mode--this should still emit `localexec` code on non-Emscripten targtes which don't currently support dynamic linking. ; RUN: sed -e 's/\[\[TLS_MODE\]\]//' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,TLS %s ; RUN: sed -e 's/\[\[TLS_MODE\]\]//' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS %s -; RUN: sed -e 's/\[\[TLS_MODE\]\]//' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+libcall-thread-context,bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS-LIBCALL %s +; RUN: sed -e 's/\[\[TLS_MODE\]\]//' %s | llc -mtriple=wasm32-wasip3 -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=bulk-memory,atomics -fast-isel - | FileCheck --check-prefixes=CHECK,TLS-LIBCALL %s ; Finally, when bulk memory is disabled, no TLS code should be generated. ; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=-bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,NO-TLS %s -; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+libcall-thread-context,-bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,NO-TLS %s +; RUN: sed -e 's/\[\[TLS_MODE\]\]/(localexec)/' %s | llc -mtriple=wasm32-wasip3 -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=-bulk-memory,atomics - | FileCheck --check-prefixes=CHECK,NO-TLS %s target triple = "wasm32-unknown-unknown" ; CHECK-LABEL: address_of_tls: From c363a1ac32c82795d3f9bb794b351ad0492e4358 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 20 May 2026 08:41:24 +0100 Subject: [PATCH 128/134] Add macro test --- clang/test/Preprocessor/wasm-target-features.c | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/test/Preprocessor/wasm-target-features.c b/clang/test/Preprocessor/wasm-target-features.c index 62dc330b6cad5..d5d0c241d86a3 100644 --- a/clang/test/Preprocessor/wasm-target-features.c +++ b/clang/test/Preprocessor/wasm-target-features.c @@ -217,6 +217,7 @@ // GENERIC-NOT: #define __wasm_simd128__ 1{{$}} // GENERIC-NOT: #define __wasm_tail_call__ 1{{$}} // GENERIC-NOT: #define __wasm_wide_arithmetic__ 1{{$}} +// GENERIC-NOT: #define __wasm_libcall_thread_context__ 1{{$}} // RUN: %clang -E -dM %s -o - 2>&1 \ // RUN: -target wasm32-unknown-unknown -mcpu=bleeding-edge \ From a9c8aa0d59da471a168e401bc8aacb79183b3025 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 20 May 2026 08:43:01 +0100 Subject: [PATCH 129/134] Update test --- lld/test/wasm/thread-context-abi-mismatch.s | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lld/test/wasm/thread-context-abi-mismatch.s b/lld/test/wasm/thread-context-abi-mismatch.s index ac1822e89434b..c4e3c778d11bf 100644 --- a/lld/test/wasm/thread-context-abi-mismatch.s +++ b/lld/test/wasm/thread-context-abi-mismatch.s @@ -3,15 +3,13 @@ # RUN: split-file %s %t # Test that the presence of an import of __stack_pointer from the env module is treated -# as an indication that the global thread context ABI is being used, even if the -# libcall-thread-context feature is not disallowed. +# as an indication that the global thread context ABI is being used. # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/start.o %t/start.s # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/stack-pointer.o %t/stack-pointer.s # RUN: not wasm-ld --libcall-thread-context %t/start.o %t/stack-pointer.o -o %t/fail.wasm 2>&1 | FileCheck %s # CHECK: stack-pointer.o: object file uses globals for thread context, but --libcall-thread-context was specified -# | ^ #--- start.s .globl _start From d20cda19e2dcbb52193668153d0983dffdb86e32 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 20 May 2026 08:46:26 +0100 Subject: [PATCH 130/134] Update thread context test --- lld/test/wasm/thread-context-abi-mismatch.s | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/lld/test/wasm/thread-context-abi-mismatch.s b/lld/test/wasm/thread-context-abi-mismatch.s index c4e3c778d11bf..069534cbe5762 100644 --- a/lld/test/wasm/thread-context-abi-mismatch.s +++ b/lld/test/wasm/thread-context-abi-mismatch.s @@ -1,23 +1,17 @@ # Test that linking object files with mismatched thread context ABIs fails with an error. - -# RUN: split-file %s %t - -# Test that the presence of an import of __stack_pointer from the env module is treated +# The presence of an import of __stack_pointer from the env module should be treated # as an indication that the global thread context ABI is being used. -# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/start.o %t/start.s -# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/stack-pointer.o %t/stack-pointer.s -# RUN: not wasm-ld --libcall-thread-context %t/start.o %t/stack-pointer.o -o %t/fail.wasm 2>&1 | FileCheck %s +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s +# RUN: not wasm-ld --libcall-thread-context %t.o -o %t.wasm 2>&1 | FileCheck %s -# CHECK: stack-pointer.o: object file uses globals for thread context, but --libcall-thread-context was specified +# CHECK: object file uses globals for thread context, but --libcall-thread-context was specified -#--- start.s .globl _start _start: .functype _start () -> () end_function -#--- stack-pointer.s .globaltype __stack_pointer, i32 .globl use_stack_pointer From bf8aef56520e553ee17ea882d0750f9cf116ad2c Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 20 May 2026 08:47:46 +0100 Subject: [PATCH 131/134] Remove unneeded arguments from createUndefinedFunction --- lld/wasm/Driver.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 5405b9f55b0d9..95d6d86962987 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -885,9 +885,7 @@ createUndefinedGlobal(StringRef name, llvm::wasm::WasmGlobalType *type) { } static UndefinedFunction * -createUndefinedFunction(StringRef name, std::optional importName, - std::optional importModule, - WasmSignature *signature) { +createUndefinedFunction(StringRef name, WasmSignature *signature) { auto *sym = cast(symtab->addUndefinedFunction( name, importName, importModule, WASM_SYMBOL_UNDEFINED, nullptr, signature, true)); @@ -988,12 +986,10 @@ static void createSyntheticSymbols() { ctx.sym.tlsAlign->markLive(); static WasmSignature setTLSBaseSignature{{}, {ValType::I32}}; ctx.sym.setTLSBase = - createUndefinedFunction("__wasm_set_tls_base", std::nullopt, - std::nullopt, &setTLSBaseSignature); + createUndefinedFunction("__wasm_set_tls_base", &setTLSBaseSignature); static WasmSignature getTLSBaseSignature{{ValType::I32}, {}}; ctx.sym.getTLSBase = - createUndefinedFunction("__wasm_get_tls_base", std::nullopt, - std::nullopt, &getTLSBaseSignature); + createUndefinedFunction("__wasm_get_tls_base", &getTLSBaseSignature); } } } From 33a19dd5d005eab222cfd53b92a89409414785ee Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 20 May 2026 09:41:12 +0100 Subject: [PATCH 132/134] Fix build --- lld/wasm/Driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 95d6d86962987..6486a256ba617 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -887,7 +887,7 @@ createUndefinedGlobal(StringRef name, llvm::wasm::WasmGlobalType *type) { static UndefinedFunction * createUndefinedFunction(StringRef name, WasmSignature *signature) { auto *sym = cast(symtab->addUndefinedFunction( - name, importName, importModule, WASM_SYMBOL_UNDEFINED, nullptr, signature, + name, std::nullopt, std::nullopt, WASM_SYMBOL_UNDEFINED, nullptr, signature, true)); ctx.arg.allowUndefinedSymbols.insert(sym->getName()); sym->isUsedInRegularObj = true; From 58f864b0b72732c547232a052c0e7065180b2266 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 20 May 2026 09:41:18 +0100 Subject: [PATCH 133/134] Add debug info test --- .../WebAssembly/thread-context-abi.ll | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 llvm/test/DebugInfo/WebAssembly/thread-context-abi.ll diff --git a/llvm/test/DebugInfo/WebAssembly/thread-context-abi.ll b/llvm/test/DebugInfo/WebAssembly/thread-context-abi.ll new file mode 100644 index 0000000000000..641529c209559 --- /dev/null +++ b/llvm/test/DebugInfo/WebAssembly/thread-context-abi.ll @@ -0,0 +1,39 @@ +; Ensure that using libcall thread context with an empty function produces a frame base +; that uses a local, and that using the global thread context produces a frame base that +; uses the __stack_pointer global. + +; Test generated via: clang --target=wasm32-unknown-unknown-wasm foo.c -g -O2 +; void foo() {} + +; RUN: llc < %s -filetype=obj -mtriple=wasm32-wasip3 -o - | llvm-dwarfdump - | FileCheck %s --check-prefix=LIBCALL +; RUN: llc < %s -filetype=obj -o - | llvm-dwarfdump - | FileCheck %s --check-prefix=GLOBAL + +target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20" +target triple = "wasm32-unknown-unknown" + +define hidden void @foo() local_unnamed_addr #0 !dbg !9 { + ret void +} + +attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+multivalue,+mutable-globals,+nontrapping-fptoint,+reference-types,+sign-ext" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3} +!llvm.ident = !{!4} +!llvm.errno.tbaa = !{!5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 23.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "") +!2 = !{i32 7, !"Dwarf Version", i32 4} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{!"clang version 23.0.0"} +!5 = !{!6, !6, i64 0} +!6 = !{!"int", !7, i64 0} +!7 = !{!"omnipotent char", !8, i64 0} +!8 = !{!"Simple C/C++ TBAA"} +!9 = distinct !DISubprogram(name: "caller", scope: !1, file: !1, line: 2, type: !10, scopeLine: 2, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, keyInstructions: true) +!10 = !DISubroutineType(types: !11) +!11 = !{null} + +; LIBCALL: DW_AT_frame_base (DW_OP_WASM_location 0x0 0x0, DW_OP_stack_value) +; GLOBAL: DW_AT_frame_base (DW_OP_WASM_location 0x3 0x0, DW_OP_stack_value) From 4d25f806c77c7e75a7aa291f1118e98707a6e9e9 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Wed, 20 May 2026 09:41:52 +0100 Subject: [PATCH 134/134] fmt --- lld/wasm/Driver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 6486a256ba617..f2eec055f65b2 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -884,11 +884,11 @@ createUndefinedGlobal(StringRef name, llvm::wasm::WasmGlobalType *type) { return sym; } -static UndefinedFunction * -createUndefinedFunction(StringRef name, WasmSignature *signature) { +static UndefinedFunction *createUndefinedFunction(StringRef name, + WasmSignature *signature) { auto *sym = cast(symtab->addUndefinedFunction( - name, std::nullopt, std::nullopt, WASM_SYMBOL_UNDEFINED, nullptr, signature, - true)); + name, std::nullopt, std::nullopt, WASM_SYMBOL_UNDEFINED, nullptr, + signature, true)); ctx.arg.allowUndefinedSymbols.insert(sym->getName()); sym->isUsedInRegularObj = true; return sym;