Add test_atomic_c11 (C11 version of test_atomic_cxx). NFC (#26930)
diff --git a/test/core/test_atomic_c11.c b/test/core/test_atomic_c11.c
new file mode 100644
index 0000000..6ee24ff
--- /dev/null
+++ b/test/core/test_atomic_c11.c
@@ -0,0 +1,157 @@
+// Copyright 2026 The Emscripten Authors.  All rights reserved.
+// Emscripten is available under two separate licenses, the MIT license and the
+// University of Illinois/NCSA Open Source License.  Both these licenses can be
+// found in the LICENSE file.
+
+//------------------------------------------------------------------------------
+//  test C11 atomics
+//
+//  This is a trasnliteration of the test_atomic_cxx.cpp test into C11 atomics.
+//------------------------------------------------------------------------------
+#include <assert.h>
+#include <stdatomic.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#define TEST(TYPE, UNSIGNED_TYPE, MASK0, MASK1, MASK2)                         \
+  {                                                                            \
+    const TYPE numMemoryOrders = 6;                                            \
+    memory_order memoryOrder[] = {                                             \
+      memory_order_relaxed,                                                    \
+      memory_order_consume,                                                    \
+      memory_order_acquire,                                                    \
+      memory_order_release,                                                    \
+      memory_order_acq_rel,                                                    \
+      memory_order_seq_cst,                                                    \
+    };                                                                         \
+                                                                               \
+    _Atomic TYPE atomicDog = 5;                                                \
+    printf("is_lock_free: %s\n",                                               \
+           atomic_is_lock_free(&atomicDog) ? "true" : "false");                \
+    printf("value: %lld\n", (long long)(TYPE)atomicDog);                       \
+                                                                               \
+    for (TYPE i = 0; i < numMemoryOrders; i++) {                               \
+      atomic_store_explicit(&atomicDog, i, memoryOrder[i]);                    \
+      printf("store/load %lld: %lld\n",                                        \
+             (long long)i,                                                     \
+             (long long)atomic_load_explicit(&atomicDog, memoryOrder[i]));     \
+    }                                                                          \
+                                                                               \
+    for (TYPE i = 0; i < numMemoryOrders; i++) {                               \
+      TYPE old = atomic_exchange_explicit(&atomicDog, i, memoryOrder[i]);      \
+      printf("exchange %lld: old=%lld new=%lld\n",                             \
+             (long long)i,                                                     \
+             (long long)old,                                                   \
+             (long long)(TYPE)atomicDog);                                      \
+    }                                                                          \
+                                                                               \
+    for (TYPE i = 0; i < numMemoryOrders; i++) {                               \
+      TYPE expected = i;                                                       \
+      bool success = atomic_compare_exchange_weak_explicit(                    \
+        &atomicDog, &expected, i + 1, memoryOrder[i], memoryOrder[i]);         \
+      i = expected;                                                            \
+      printf("compare_exchange_weak %lld: success = %s\n",                     \
+             (long long)i,                                                     \
+             success ? "true" : "false");                                      \
+    }                                                                          \
+                                                                               \
+    for (TYPE i = 0; i < numMemoryOrders; i++) {                               \
+      TYPE expected = i;                                                       \
+      bool success = atomic_compare_exchange_strong_explicit(                  \
+        &atomicDog, &expected, i + 1, memoryOrder[i], memoryOrder[i]);         \
+      i = expected;                                                            \
+      printf("compare_exchange_strong %lld: success = %s\n",                   \
+             (long long)i,                                                     \
+             success ? "true" : "false");                                      \
+    }                                                                          \
+                                                                               \
+    atomicDog = MASK2;                                                         \
+    for (TYPE i = 0; i < numMemoryOrders; i++) {                               \
+      TYPE old = atomic_fetch_add_explicit(&atomicDog, 1, memoryOrder[i]);     \
+      printf("fetch_add %lld: old=%llx new=%llx\n",                            \
+             (long long)i,                                                     \
+             (long long)old,                                                   \
+             (long long)(TYPE)atomicDog);                                      \
+    }                                                                          \
+                                                                               \
+    for (TYPE i = 0; i < numMemoryOrders; i++) {                               \
+      TYPE old = atomic_fetch_sub_explicit(&atomicDog, 1, memoryOrder[i]);     \
+      printf("fetch_sub %lld: old=%llx new=%llx\n",                            \
+             (long long)i,                                                     \
+             (long long)old,                                                   \
+             (long long)(TYPE)atomicDog);                                      \
+    }                                                                          \
+                                                                               \
+    for (TYPE i = 0; i < numMemoryOrders; i++) {                               \
+      atomic_store_explicit(&atomicDog, MASK0, memoryOrder[i]);                \
+      TYPE old =                                                               \
+        atomic_fetch_and_explicit(&atomicDog, (TYPE)1 << i, memoryOrder[i]);   \
+      printf("fetch_and %lld: old=%llx, new=%llx\n",                           \
+             (long long)i,                                                     \
+             (unsigned long long)(UNSIGNED_TYPE)old,                           \
+             (unsigned long long)(UNSIGNED_TYPE)atomicDog);                    \
+    }                                                                          \
+                                                                               \
+    atomicDog = 0;                                                             \
+    for (TYPE i = 0; i < numMemoryOrders; i++) {                               \
+      TYPE old =                                                               \
+        atomic_fetch_or_explicit(&atomicDog, (TYPE)1 << i, memoryOrder[i]);    \
+      printf("fetch_or %lld: old=%llx, new=%llx\n",                            \
+             (long long)i,                                                     \
+             (unsigned long long)(UNSIGNED_TYPE)old,                           \
+             (unsigned long long)(UNSIGNED_TYPE)atomicDog);                    \
+    }                                                                          \
+                                                                               \
+    atomicDog = 0;                                                             \
+    for (TYPE i = 0; i < numMemoryOrders; i++) {                               \
+      TYPE old =                                                               \
+        atomic_fetch_xor_explicit(&atomicDog, (TYPE)1 << i, memoryOrder[i]);   \
+      printf("fetch_xor %lld: old=%llx, new=%llx\n",                           \
+             (long long)i,                                                     \
+             (unsigned long long)(UNSIGNED_TYPE)old,                           \
+             (unsigned long long)(UNSIGNED_TYPE)atomicDog);                    \
+    }                                                                          \
+                                                                               \
+    atomicDog = 0;                                                             \
+    atomicDog++;                                                               \
+    printf("operator++: %lld\n", (long long)(TYPE)(atomicDog));                \
+    atomicDog--;                                                               \
+    printf("operator--: %lld\n", (long long)(TYPE)(atomicDog));                \
+                                                                               \
+    atomicDog += 10;                                                           \
+    printf("operator+=: %lld\n", (long long)(TYPE)(atomicDog));                \
+    atomicDog -= 5;                                                            \
+    printf("operator-=: %lld\n", (long long)(TYPE)(atomicDog));                \
+    atomicDog |= MASK0;                                                        \
+    printf("operator|=: %llx\n",                                               \
+           (unsigned long long)(UNSIGNED_TYPE)(atomicDog));                    \
+    atomicDog &= MASK1;                                                        \
+    printf("operator&=: %llx\n",                                               \
+           (unsigned long long)(UNSIGNED_TYPE)(atomicDog));                    \
+    atomicDog ^= MASK2;                                                        \
+    printf("operator^=: %llx\n",                                               \
+           (unsigned long long)(UNSIGNED_TYPE)(atomicDog));                    \
+  }
+
+int main() {
+  // test 8, 16, 32 and 64-bit data types
+  printf("\n8 bits\n\n");
+  TEST(char, unsigned char, 0xFF, 0xF0, 0x0F);
+  printf("\n16 bits\n\n");
+  TEST(short, unsigned short, 0xFFFF, 0xF0F0, 0x0F0F);
+  printf("\n32 bits\n\n");
+  TEST(int, unsigned int, 0xFFFFFFFF, 0xF0F0F0F0, 0x0F0F0F0F);
+  printf("\n64 bits\n\n");
+  TEST(long long, unsigned long long, 0xFFFFFFFFFFFFFFFF,
+       0xF0F0F0F0F0F0F0F0, 0x0F0F0F0F0F0F0F0F);
+
+  // test atomic_flag (should also have memory_orders, but probably doesn't
+  // matter to find the missing atomic functions)
+  atomic_flag af = ATOMIC_FLAG_INIT;
+  atomic_flag_clear(&af);
+  bool b = atomic_flag_test_and_set(&af);
+  printf("atomic_flag: %s\n", b ? "true" : "false");
+
+  printf("done.\n");
+  return 0;
+}
diff --git a/test/core/test_atomic_cxx.cpp b/test/core/test_atomic_cxx.cpp
index 1f64e1a..0c30fa6 100644
--- a/test/core/test_atomic_cxx.cpp
+++ b/test/core/test_atomic_cxx.cpp
@@ -28,8 +28,8 @@
 
     // test atomic<int>
     std::atomic<dog> atomicDog(5);
-    printf("atomic<int>.is_lock_free(): %s\n", atomicDog.is_lock_free() ? "true" : "false");
-    printf("atomic<int> value: %lld\n", (long long)TYPE(atomicDog));
+    printf("is_lock_free: %s\n", atomicDog.is_lock_free() ? "true" : "false");
+    printf("value: %lld\n", (long long)TYPE(atomicDog));
 
     // test store/load
     for (TYPE i = 0; i < numMemoryOrders; i++) {
diff --git a/test/core/test_atomic_cxx.out b/test/core/test_atomic_cxx.out
index c74c742..db264c9 100644
--- a/test/core/test_atomic_cxx.out
+++ b/test/core/test_atomic_cxx.out
@@ -1,8 +1,8 @@
 
 8 bits
 
-atomic<int>.is_lock_free(): true
-atomic<int> value: 5
+is_lock_free: true
+value: 5
 store/load 0: 0
 store/load 1: 1
 store/load 2: 2
@@ -57,8 +57,8 @@
 
 16 bits
 
-atomic<int>.is_lock_free(): true
-atomic<int> value: 5
+is_lock_free: true
+value: 5
 store/load 0: 0
 store/load 1: 1
 store/load 2: 2
@@ -113,8 +113,8 @@
 
 32 bits
 
-atomic<int>.is_lock_free(): true
-atomic<int> value: 5
+is_lock_free: true
+value: 5
 store/load 0: 0
 store/load 1: 1
 store/load 2: 2
@@ -169,8 +169,8 @@
 
 64 bits
 
-atomic<int>.is_lock_free(): true
-atomic<int> value: 5
+is_lock_free: true
+value: 5
 store/load 0: 0
 store/load 1: 1
 store/load 2: 2
diff --git a/test/test_core.py b/test/test_core.py
index 7d52e6f..7533ba5 100644
--- a/test/test_core.py
+++ b/test/test_core.py
@@ -6275,6 +6275,14 @@
     self.do_core_test('test_atomic.c')
 
   @also_with_pthreads
+  def test_atomic_c11(self):
+    if '-pthread' in self.cflags and self.is_wasm2js():
+      self.skipTest('atomics support missing')
+    # Re-use the out file from the C++ atomic test since they should have
+    # identical output.
+    self.do_runf('core/test_atomic_c11.c', read_file(test_file('core/test_atomic_cxx.out')))
+
+  @also_with_pthreads
   def test_atomic_cxx(self):
     if '-pthread' in self.cflags and self.is_wasm2js():
       self.skipTest('atomics support missing')