https://github.com/tlively created 
https://github.com/llvm/llvm-project/pull/223917

Clang defaults WebAssembly to a single-threaded model unless atomics and 
bulk-memory are enabled, whereas Triple::getDefaultThreadModel() previously 
defaulted to POSIX for all targets. Because Clang only emits the "thread-model" 
module flag when the active thread model differs from the triple's default, 
single-threaded Wasm objects recorded "thread-model"="single" while 
multithreaded objects omitted the flag. When linking mixed objects in LTO, the 
merged module inherited "single", causing passes like LICM and AtomicExpand to 
treat multithreaded programs as single-threaded.

Change Triple::getDefaultThreadModel() to return ThreadModel::Single for 
WebAssembly so that multithreaded objects explicitly record "thread-model"= 
"posix" and single-threaded objects omit the flag. Additionally, update 
WebAssemblyCoalesceFeaturesAndStripAtomics to set the module thread model to 
POSIX when threading features are enabled and no explicit module flag is 
present, ensuring backend passes like AtomicExpandPass preserve atomics in raw 
IR modules compiled via llc.

Assisted-By: Gemini

>From 804a9390fdbb63cbb68e9b278055941824518f3b Mon Sep 17 00:00:00 2001
From: Thomas Lively <[email protected]>
Date: Tue, 15 Sep 2026 22:45:19 -0700
Subject: [PATCH] [WebAssembly] Use Single as the default Triple thread model

Clang defaults WebAssembly to a single-threaded model unless atomics and
bulk-memory are enabled, whereas Triple::getDefaultThreadModel() previously
defaulted to POSIX for all targets. Because Clang only emits the
"thread-model" module flag when the active thread model differs from the
triple's default, single-threaded Wasm objects recorded "thread-model"="single"
while multithreaded objects omitted the flag. When linking mixed objects in LTO,
the merged module inherited "single", causing passes like LICM and AtomicExpand
to treat multithreaded programs as single-threaded.

Change Triple::getDefaultThreadModel() to return ThreadModel::Single for
WebAssembly so that multithreaded objects explicitly record "thread-model"=
"posix" and single-threaded objects omit the flag. Additionally, update
WebAssemblyCoalesceFeaturesAndStripAtomics to set the module thread model to
POSIX when threading features are enabled and no explicit module flag is
present, ensuring backend passes like AtomicExpandPass preserve atomics in raw
IR modules compiled via llc.

Assisted-By: Gemini
---
 clang/test/CodeGen/thread-model.c                      |  8 ++++++++
 .../WebAssemblyCoalesceFeaturesAndStripAtomics.cpp     | 10 +++++++++-
 llvm/lib/TargetParser/Triple.cpp                       |  6 +++++-
 3 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/clang/test/CodeGen/thread-model.c 
b/clang/test/CodeGen/thread-model.c
index cf6eb82c948a0..419615fb40edb 100644
--- a/clang/test/CodeGen/thread-model.c
+++ b/clang/test/CodeGen/thread-model.c
@@ -5,7 +5,15 @@
 // RUN: %clang_cc1 -triple arm-none-linux-gnueabi -mthread-model posix 
-emit-llvm %s -o - | FileCheck %s --check-prefix=POSIX
 // RUN: %clang_cc1 -triple arm-none-linux-gnueabi -emit-llvm %s -o - | 
FileCheck %s --check-prefix=POSIX
 
+// RUN: %clang_cc1 -triple wasm32-unknown-unknown -mthread-model single 
-emit-llvm %s -o - | FileCheck %s --check-prefix=WASM-SINGLE
+// RUN: %clang_cc1 -triple wasm32-unknown-unknown -target-feature +atomics 
-target-feature +bulk-memory -mthread-model posix -emit-llvm %s -o - | 
FileCheck %s --check-prefix=WASM-POSIX
+// RUN: %clang_cc1 -triple wasm32-unknown-unknown -target-feature +atomics 
-target-feature +bulk-memory -emit-llvm %s -o - | FileCheck %s 
--check-prefix=WASM-POSIX
+// RUN: %clang_cc1 -triple wasm32-unknown-unknown -emit-llvm %s -o - | 
FileCheck %s --check-prefix=WASM-SINGLE
+
 void f(void) {}
 
 // SINGLE: !{i32 1, !"thread-model", !"single"}
 // POSIX-NOT: "thread-model"
+
+// WASM-SINGLE-NOT: "thread-model"
+// WASM-POSIX: !{i32 1, !"thread-model", !"posix"}
diff --git 
a/llvm/lib/Target/WebAssembly/WebAssemblyCoalesceFeaturesAndStripAtomics.cpp 
b/llvm/lib/Target/WebAssembly/WebAssemblyCoalesceFeaturesAndStripAtomics.cpp
index a040e531ee020..8c4b24806c9a9 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyCoalesceFeaturesAndStripAtomics.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyCoalesceFeaturesAndStripAtomics.cpp
@@ -197,7 +197,15 @@ static bool coalesceFeaturesAndStripAtomics(Module &M,
   else if (StrippedTLS && !StrippedAtomics)
     stripAtomics(M);
 
-  recordFeatures(M, ST, Features, StrippedAtomics || StrippedTLS);
+  bool Stripped = StrippedAtomics || StrippedTLS;
+  if (!Stripped &&
+      (Features[WebAssembly::FeatureAtomics] ||
+       (CooperativeThreading && Features[WebAssembly::FeatureBulkMemory])) &&
+      !M.getModuleFlag("thread-model")) {
+    M.setThreadModel(ThreadModel::POSIX);
+  }
+
+  recordFeatures(M, ST, Features, Stripped);
 
   // Conservatively assume we have made some change
   return true;
diff --git a/llvm/lib/TargetParser/Triple.cpp b/llvm/lib/TargetParser/Triple.cpp
index ceabfe403e9c3..fb54408c0729f 100644
--- a/llvm/lib/TargetParser/Triple.cpp
+++ b/llvm/lib/TargetParser/Triple.cpp
@@ -2543,7 +2543,11 @@ FloatABI::ABIType Triple::getDefaultFloatABI() const {
   return FloatABI::Hard;
 }
 
-ThreadModel Triple::getDefaultThreadModel() const { return ThreadModel::POSIX; 
}
+ThreadModel Triple::getDefaultThreadModel() const {
+  if (isWasm())
+    return ThreadModel::Single;
+  return ThreadModel::POSIX;
+}
 
 LongDoubleFormat Triple::getDefaultLongDoubleFormat() const {
   switch (getArch()) {

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to