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