[clang] [AMDGPU] Add and support '-fsanitize=concurrency' in the AMDGPU toolchain (PR #207712)
Joseph Huber via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 6 05:18:23 PDT 2026
https://github.com/jhuber6 created https://github.com/llvm/llvm-project/pull/207712
Summary:
Adds a new `-fsanitize=concurrency` that is supported by the AMDGPU
target. This re-uses the TSan instrumentation but links a different
runtime. This was suggested in the dicussions at
https://discourse.llvm.org/t/rfc-a-thread-concurrency-sanitizer-for-gpus-in-compiler-rt/91113
and is done to keep users from confusing the probabalistic sampling that
users like KCSan do with the traditional, deterministic happends-before
model.
>From 4c92e2b971024751b871e687d4e65659779f37b0 Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Sun, 5 Jul 2026 11:41:50 -0500
Subject: [PATCH] [AMDGPU] Add and support '-fsanitize=concurrency' in the
AMDGPU toolchain
Summary:
Adds a new `-fsanitize=concurrency` that is supported by the AMDGPU
target. This re-uses the TSan instrumentation but links a different
runtime. This was suggested in the dicussions at
https://discourse.llvm.org/t/rfc-a-thread-concurrency-sanitizer-for-gpus-in-compiler-rt/91113
and is done to keep users from confusing the probabalistic sampling that
users like KCSan do with the traditional, deterministic happends-before
model.
---
clang/include/clang/Basic/Sanitizers.def | 3 +++
clang/include/clang/Driver/SanitizerArgs.h | 3 +++
clang/lib/Driver/SanitizerArgs.cpp | 11 ++++++++++-
clang/lib/Driver/ToolChains/AMDGPU.cpp | 1 +
clang/lib/Driver/ToolChains/Clang.cpp | 13 +++++++++++++
clang/lib/Driver/ToolChains/CommonArgs.cpp | 2 ++
.../lib/amdgcn-amd-amdhsa/libclang_rt.csan.a | 0
clang/test/Driver/amdgpu-toolchain.c | 7 +++++++
clang/test/Driver/fsanitize.c | 5 +++++
9 files changed, 44 insertions(+), 1 deletion(-)
create mode 100644 clang/test/Driver/Inputs/resource_dir_with_per_target_subdir/lib/amdgcn-amd-amdhsa/libclang_rt.csan.a
diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def
index da85431625026..9499eb37de67c 100644
--- a/clang/include/clang/Basic/Sanitizers.def
+++ b/clang/include/clang/Basic/Sanitizers.def
@@ -79,6 +79,9 @@ SANITIZER("type", Type)
// ThreadSanitizer
SANITIZER("thread", Thread)
+// ConcurrencySanitizer
+SANITIZER("concurrency", Concurrency)
+
// Numerical stability sanitizer.
SANITIZER("numerical", NumericalStability)
diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index 6a01b3e36d44c..78f577a412ecb 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -104,6 +104,9 @@ class SanitizerArgs {
}
bool needsTysanRt() const { return Sanitizers.has(SanitizerKind::Type); }
bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); }
+ bool needsCsanRt() const {
+ return Sanitizers.has(SanitizerKind::Concurrency);
+ }
bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); }
bool needsFuzzer() const { return Sanitizers.has(SanitizerKind::Fuzzer); }
bool needsLsanRt() const {
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index e813efc89073d..09ab10b922c15 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -1486,7 +1486,16 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
if (Sanitizers.empty())
return;
- CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers)));
+
+ // The concurrency sampler re-uses the thread sanitizer instrumentation. We
+ // lower it to `-fsanitize=thread` but the driver selects a differnt runtime.
+ SanitizerSet EmittedSanitizers = Sanitizers;
+ if (EmittedSanitizers.has(SanitizerKind::Concurrency)) {
+ EmittedSanitizers.set(SanitizerKind::Concurrency, false);
+ EmittedSanitizers.set(SanitizerKind::Thread, true);
+ }
+ CmdArgs.push_back(
+ Args.MakeArgString("-fsanitize=" + toString(EmittedSanitizers)));
if (!SuppressUBSanFeature.empty())
CmdArgs.push_back(
diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp
index 032c108d3d10d..a9d96674a57aa 100644
--- a/clang/lib/Driver/ToolChains/AMDGPU.cpp
+++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp
@@ -1161,6 +1161,7 @@ SanitizerMask AMDGPUToolChain::getSupportedSanitizers(
// arch xnack support.
if (!BA || isXnackAvailable(getTriple(), BA.ArchName))
SupportedMask |= SanitizerKind::Address;
+ SupportedMask |= SanitizerKind::Concurrency;
return SupportedMask;
}
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index fe01e6ffd59ef..192210567853b 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -9734,6 +9734,17 @@ static bool requiresUBSanRT(unsigned ID) {
}
}
+// Options that need the csan compiler-rt library on the target toolchain.
+static bool requiresCSanRT(unsigned ID) {
+ switch (ID) {
+ case options::OPT_fsanitize_EQ:
+ case options::OPT_fno_sanitize_EQ:
+ return true;
+ default:
+ return false;
+ }
+}
+
void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -9813,6 +9824,8 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
// Without this check using it on the host would result in linker errors.
if (requiresUBSanRT(ID) && !ToolChainHasRT(TC, "ubsan_minimal"))
return false;
+ if (requiresCSanRT(ID) && !ToolChainHasRT(TC, "csan"))
+ return false;
// Don't forward -mllvm to toolchains that don't support LLVM.
return TC.HasNativeLLVMSupport() || ID != OPT_mllvm;
};
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index dfd13fbe8a4eb..021d616ca001d 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -1722,6 +1722,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("tsan_cxx");
}
+ if (!SanArgs.needsSharedRt() && SanArgs.needsCsanRt())
+ StaticRuntimes.push_back("csan");
if (!SanArgs.needsSharedRt() && SanArgs.needsTysanRt())
StaticRuntimes.push_back("tysan");
if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt()) {
diff --git a/clang/test/Driver/Inputs/resource_dir_with_per_target_subdir/lib/amdgcn-amd-amdhsa/libclang_rt.csan.a b/clang/test/Driver/Inputs/resource_dir_with_per_target_subdir/lib/amdgcn-amd-amdhsa/libclang_rt.csan.a
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/clang/test/Driver/amdgpu-toolchain.c b/clang/test/Driver/amdgpu-toolchain.c
index 135129b739603..ef6bd854dd031 100644
--- a/clang/test/Driver/amdgpu-toolchain.c
+++ b/clang/test/Driver/amdgpu-toolchain.c
@@ -63,3 +63,10 @@
// RUN: | FileCheck -check-prefixes=UBSAN %s
// UBSAN: ld.lld
// UBSAN-SAME: "[[RESOURCE_DIR:.+]]{{/|\\\\}}lib{{/|\\\\}}amdgcn-amd-amdhsa{{/|\\\\}}libclang_rt.ubsan_minimal.a"
+
+// RUN: %clang -### --target=amdgcn-amd-amdhsa -mcpu=gfx906 -nogpulib \
+// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \
+// RUN: -fsanitize=concurrency %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=CSAN %s
+// CSAN: ld.lld
+// CSAN-SAME: "[[RESOURCE_DIR:.+]]{{/|\\\\}}lib{{/|\\\\}}amdgcn-amd-amdhsa{{/|\\\\}}libclang_rt.csan.a"
diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c
index f6a82d899d5bf..6e34c868608c4 100644
--- a/clang/test/Driver/fsanitize.c
+++ b/clang/test/Driver/fsanitize.c
@@ -292,6 +292,11 @@
// RUN: not %clang --target=i386-apple-tvos-simulator -fsanitize=thread %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TSAN-I386-TVOSSIMULATOR
// CHECK-TSAN-I386-TVOSSIMULATOR: unsupported option '-fsanitize=thread' for target 'i386-apple-tvos-simulator'
+// RUN: not %clang --target=x86_64-linux-gnu -fsanitize=concurrency %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CSAN-X86-64-LINUX
+// CHECK-CSAN-X86-64-LINUX: unsupported option '-fsanitize=concurrency' for target 'x86_64-unknown-linux-gnu'
+// RUN: not %clang --target=aarch64-apple-darwin -fsanitize=concurrency %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CSAN-AARCH64-DARWIN
+// CHECK-CSAN-AARCH64-DARWIN: unsupported option '-fsanitize=concurrency' for target 'arm64-apple-darwin'
+
// RUN: %clang --target=x86_64-linux-gnu -fsanitize=thread -fsanitize-thread-memory-access %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TSAN-MEMORY-ACCESS
// CHECK-TSAN-MEMORY-ACCESS-NOT: -cc1{{.*}}tsan-instrument-memory-accesses=0
// CHECK-TSAN-MEMORY-ACCESS-NOT: -cc1{{.*}}tsan-instrument-memintrinsics=0
More information about the cfe-commits
mailing list