[clang] [lld] [llvm] [WebAssembly] WASIP3 and component model threading support (PR #175800)

Sy Brand via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 20 01:12:20 PST 2026


================
@@ -1272,6 +1310,77 @@ static void checkZOptions(opt::InputArgList &args) {
       warn("unknown -z value: " + StringRef(arg->getValue()));
 }
 
+// Determine the thread context ABI based on object file features.
+// This must be called after LTO, since LTO object files are needed.
+static void determineThreadContextABI(ArrayRef<ObjFile *> files) {
+  // A complication is that a user may attempt to link together object files
+  // compiled with different versions of LLVM, where one does not specifiy
+  // -component-model-thread-context when using the global thread context ABI.
+  // They may also attempt to link object files with the global ABI compiled with
+  // older LLVM versions, but link them with a newer wasm-ld. To ensure the correct behavior
+  // in both of these cases, we treat the import of a __stack_pointer global from the env module
+  // as an indication that the global thread context ABI is being used.
+
+  enum class ThreadContextABI {
+    Undetermined,
+    ComponentModelBuiltins,
+    Globals
+  };
+
+  ThreadContextABI threadContextABI = ThreadContextABI::Undetermined;
+
+  for (ObjFile *obj : files) {
+    auto targetFeatures = obj->getWasmObj()->getTargetFeatures();
+    auto threadContextFeature = llvm::find_if(targetFeatures,
+                              [](const auto &f) {
+                                return f.Name == "component-model-thread-context";
+                              });
+
+    bool usesComponentModelThreadContext = threadContextFeature != targetFeatures.end() &&
+                                    threadContextFeature->Prefix == WASM_FEATURE_PREFIX_USED;
+
+    if (threadContextFeature == targetFeatures.end()) {
+      // If the feature is not explicitly used or disallowed, check for the presence of a __stack_pointer
+      // import in this specific file to determine if the global thread context ABI is being used.
+      bool hasStackPointerImport = llvm::any_of(obj->getSymbols(), [](const auto &sym) {
+        return sym && sym->getName() == "__stack_pointer" && 
+               sym->kind() == Symbol::UndefinedGlobalKind &&
+               sym->importModule && sym->importModule == "env";
+      });
+      if (!hasStackPointerImport) {
+        // No __stack_pointer import, so this is probably an object file compiled from assembly or
+        // some other source that doesn't care about the thread context ABI. As such, we let it pass.
+        continue;
+      }
+      // Treat this as using the globals ABI
+      usesComponentModelThreadContext = false;
+    }     
+
+    if (usesComponentModelThreadContext) {
+      if (threadContextABI == ThreadContextABI::Undetermined) {
+        threadContextABI = ThreadContextABI::ComponentModelBuiltins;
+      } else if (threadContextABI != ThreadContextABI::ComponentModelBuiltins) {
+        error("thread context ABI mismatch: " + obj->getName() +
+              " uses component-model-thread-context but other files disallow it");
+      }
+    } else {
+      if (threadContextABI == ThreadContextABI::Undetermined) {
+        threadContextABI = ThreadContextABI::Globals;
+      } else if (threadContextABI != ThreadContextABI::Globals) {
+        error("thread context ABI mismatch: " + obj->getName() +
+              " disallows component-model-thread-context but other files use it"); 
+      }
+    }
----------------
TartanLlama wrote:

I guess a slightly more user-friendly error may help give an idea of what the problem is, then it's a case of googling the string. Something like

```
thread context ABI mismatch: <file> uses the component model thread context ABI, but other files use the global thread context ABI; the files may have been compiled with incompatible feature flags, or with incompatible compiler versions
``` 

https://github.com/llvm/llvm-project/pull/175800


More information about the cfe-commits mailing list