Skip to content

[Support/BLAKE3] Make g_cpu_features thread safe #147948

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 12, 2025

Conversation

slydiman
Copy link
Contributor

@slydiman slydiman commented Jul 10, 2025

g_cpu_features can be updated multiple times by get_cpu_features(), which reports a thread sanitizer error when used with multiple lld threads.

This PR updates BLAKE3 to v1.8.2.

@llvmbot
Copy link
Member

llvmbot commented Jul 10, 2025

@llvm/pr-subscribers-llvm-support

Author: Dmitry Vasilyev (slydiman)

Changes

g_cpu_features can be updated multiple times by get_cpu_features(), which reports a thread sanitizer error when used with multiple lld threads.


Full diff: https://github.com/llvm/llvm-project/pull/147948.diff

1 Files Affected:

  • (modified) llvm/lib/Support/BLAKE3/blake3_dispatch.c (+37-5)
diff --git a/llvm/lib/Support/BLAKE3/blake3_dispatch.c b/llvm/lib/Support/BLAKE3/blake3_dispatch.c
index e96e714225f41..6c156f123dd5b 100644
--- a/llvm/lib/Support/BLAKE3/blake3_dispatch.c
+++ b/llvm/lib/Support/BLAKE3/blake3_dispatch.c
@@ -14,6 +14,36 @@
 #endif
 #endif
 
+/* Atomic access abstraction (since MSVC does not do C11 yet) */
+#if defined(_MSC_VER) && !defined(__clang__)
+#if !defined(IS_X86)
+#include <intrin.h>
+#endif
+#pragma warning(disable : 5105)
+#ifndef FORCEINLINE
+#define FORCEINLINE inline __forceinline
+#endif
+typedef volatile long atomic32_t;
+static FORCEINLINE int32_t atomic_load32(atomic32_t *src) { 
+  return _InterlockedOr(src, 0); 
+}
+static FORCEINLINE void atomic_store32(atomic32_t *dst, int32_t val) {
+  _InterlockedExchange(dst, val);
+}
+#else
+#include <stdatomic.h>
+#ifndef FORCEINLINE
+#define FORCEINLINE inline __attribute__((__always_inline__))
+#endif
+typedef volatile _Atomic(int32_t) atomic32_t;
+static FORCEINLINE int32_t atomic_load32(atomic32_t *src) {
+  return atomic_load_explicit(src, memory_order_relaxed);
+}
+static FORCEINLINE void atomic_store32(atomic32_t *dst, int32_t val) {
+  atomic_store_explicit(dst, val, memory_order_relaxed);
+}
+#endif
+
 #define MAYBE_UNUSED(x) (void)((x))
 
 #if defined(IS_X86)
@@ -76,7 +106,7 @@ enum cpu_feature {
 #if !defined(BLAKE3_TESTING)
 static /* Allow the variable to be controlled manually for testing */
 #endif
-    enum cpu_feature g_cpu_features = UNDEFINED;
+    atomic32_t g_cpu_features = UNDEFINED;
 
 LLVM_ATTRIBUTE_USED
 #if !defined(BLAKE3_TESTING)
@@ -84,9 +114,10 @@ static
 #endif
     enum cpu_feature
     get_cpu_features(void) {
-
-  if (g_cpu_features != UNDEFINED) {
-    return g_cpu_features;
+  enum cpu_feature _cpu_features;
+  _cpu_features = (enum cpu_feature)atomic_load32(&g_cpu_features);
+  if (_cpu_features != UNDEFINED) {
+    return _cpu_features;
   } else {
 #if defined(IS_X86)
     uint32_t regs[4] = {0};
@@ -125,10 +156,11 @@ static
         }
       }
     }
-    g_cpu_features = features;
+    atomic_store32(&g_cpu_features, (int32_t)features);
     return features;
 #else
     /* How to detect NEON? */
+    atomic_store32(&g_cpu_features, 0);
     return 0;
 #endif
   }

@Meinersbur
Copy link
Member

This seems to have been fixed upstream: BLAKE3-team/BLAKE3@12823b8

Update instead?

@slydiman
Copy link
Contributor Author

Update instead?

Done. Thanks.

@Meinersbur Meinersbur requested a review from rnk July 11, 2025 10:27
@Meinersbur
Copy link
Member

Why not update the entire BLAKE3? Wie generally do not want to fork third-party software, but update it as the need arises. Every LLVM-private change will make eventually updating it more difficult. This incliudes cherry-picked patches from the upstream repository. See also https://reviews.llvm.org/D121510#3383116

Copy link
Contributor

@akyrtzi akyrtzi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for updating to latest BLAKE3!
Are the first 2 commits of this PR redundant now, could you merge down to one commit?
Otherwise LGTM.

Copy link
Member

@Meinersbur Meinersbur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@akyrtzi The LLVM repository only allows squashed merges. It even is encouraged to never force-push to a PR branch since it may cause GitHub to lose track of comments on source lines.

@slydiman slydiman merged commit d2ad63a into llvm:main Jul 12, 2025
9 checks passed
@nikic
Copy link
Contributor

nikic commented Jul 14, 2025

This causes linker error when linking both libblake3 and LLVM statically.

  = note: /usr/bin/ld: /checkout/obj/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/libblake3-5c167293c56e5670.rlib(b8423798394d5395-blake3_avx512_x86-64_unix.o): in function `blake3_xof_many_avx512':
          (.text+0x3ac0): multiple definition of `blake3_xof_many_avx512'; /checkout/obj/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/librustc_llvm-65facbdddbd830de.rlib(blake3_avx512_x86-64_unix.S.o):(.text+0x3ac0): first defined here
          /usr/bin/ld: /checkout/obj/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/libblake3-5c167293c56e5670.rlib(b8423798394d5395-blake3_avx512_x86-64_unix.o): in function `blake3_xof_many_avx512':
          (.text+0x3ac0): multiple definition of `_blake3_xof_many_avx512'; /checkout/obj/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/librustc_llvm-65facbdddbd830de.rlib(blake3_avx512_x86-64_unix.S.o):(.text+0x3ac0): first defined here
          collect2: error: ld returned 1 exit status

nikic added a commit to nikic/llvm-project that referenced this pull request Jul 14, 2025
This symbol was introduced in llvm#147948, but not prefixed, resulting
in conflicts if libblake3 and LLVM are both linked statically
into the same binary.
@nikic
Copy link
Contributor

nikic commented Jul 14, 2025

I think #148607 should fix that.

aeubanks pushed a commit that referenced this pull request Jul 14, 2025
This symbol was introduced in #147948, but not prefixed, resulting in
conflicts if libblake3 and LLVM are both linked statically into the same
binary.
rupprecht added a commit to rupprecht/llvm-project that referenced this pull request Jul 16, 2025
Added by llvm#147948, blake3_xof_many and blake3_compress_subtree_wide cause conflicts when linking llvm and blake3 statically into the same binary. Similar to llvm#148607.
nikic pushed a commit that referenced this pull request Jul 16, 2025
Added by #147948, blake3_xof_many and blake3_compress_subtree_wide cause
conflicts when linking llvm and blake3 statically into the same binary.
Similar to #148607.
nikic added a commit to nikic/llvm-project that referenced this pull request Jul 16, 2025
This was dropped in llvm#147948 and causes symbol conflicts if
libblake3 is also linked.
nikic added a commit to nikic/llvm-project that referenced this pull request Jul 16, 2025
This was dropped in llvm#147948 and causes symbol conflicts if
libblake3 is also linked.
nikic added a commit that referenced this pull request Jul 16, 2025
This was dropped in #147948 and causes symbol conflicts if libblake3 is
also linked.
ilovepi added a commit that referenced this pull request Jul 16, 2025
In #147948 blake3_hash4_neon became a public symbol (no longer static).
Like other APIs introduced, it was not prefixed, resulting in conflicts if
libblake3 and LLVM are both linked statically into the same binary.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants