[llvm] [NVPTX] Fix scoped atomic when given runtime values (PR #185883)
Joseph Huber via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 16 08:46:51 PDT 2026
https://github.com/jhuber6 updated https://github.com/llvm/llvm-project/pull/185883
>From e0409287036ce47bfd23c8c671671257f74f2dd6 Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Wed, 11 Mar 2026 08:37:07 -0500
Subject: [PATCH] [NVPTX] Fix scoped atomic when given runtime values
Summary:
The `__scoped_` atomic builtins will expand to each supported scope in
the case of a runtime value. There are two problems:
1. Singlethreaded scope doesn't exist -> Widen to block scope
2. Cluster is not supported on all tagets -> Widen to device scope
---
llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp | 36 +++++++++++++--------
1 file changed, 22 insertions(+), 14 deletions(-)
diff --git a/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp b/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp
index 99982ff3181b3..8e916126fecb6 100644
--- a/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp
@@ -773,14 +773,9 @@ NVPTX::Scope NVPTXDAGToDAGISel::getOperationScope(MemSDNode *N,
case NVPTX::Ordering::SequentiallyConsistent:
auto S = Scopes[N->getSyncScopeID()];
- // Atomic operations must have a scope greater than thread.
- if (S == NVPTX::Scope::Thread)
- report_fatal_error(
- formatv("Atomics need scope > \"{}\".", ScopeToString(S)));
-
- // If scope is cluster, clusters must be supported.
- if (S == NVPTX::Scope::Cluster)
- Subtarget->failIfClustersUnsupported("cluster scope");
+ // If scope is cluster but clusters aren't supported, widen to device.
+ if (S == NVPTX::Scope::Cluster && !Subtarget->hasClusters())
+ S = NVPTX::Scope::Device;
// If operation is volatile, then its scope is system.
return N->isVolatile() ? NVPTX::Scope::System : S;
@@ -798,8 +793,9 @@ static bool canLowerToLDG(const MemSDNode &N, const NVPTXSubtarget &Subtarget,
static unsigned int getFenceOp(NVPTX::Ordering O, NVPTX::Scope S,
NVPTXSubtarget const *T) {
- if (S == NVPTX::Scope::Cluster)
- T->failIfClustersUnsupported(".cluster scope fence");
+ // If scope is cluster but clusters aren't supported, widen to device.
+ if (S == NVPTX::Scope::Cluster && !T->hasClusters())
+ S = NVPTX::Scope::Device;
// Fall back to .acq_rel if .acquire, .release is not supported.
if (!T->hasSplitAcquireAndReleaseFences() &&
@@ -909,6 +905,11 @@ NVPTXDAGToDAGISel::insertMemoryInstructionFence(SDLoc DL, SDValue &Chain,
getOperationOrderings(N, Subtarget);
auto Scope = getOperationScope(N, InstructionOrdering);
+ // Singlethread scope has no inter-thread synchronization requirements, so
+ // the operation is lowered as plain and the fence is skipped.
+ if (Scope == NVPTX::Scope::Thread)
+ return {NVPTX::Ordering::NotAtomic, Scope};
+
// If a fence is required before the operation, insert it:
switch (NVPTX::Ordering(FenceOrdering)) {
case NVPTX::Ordering::NotAtomic:
@@ -1857,9 +1858,16 @@ void NVPTXDAGToDAGISel::SelectI128toV2I64(SDNode *N) {
bool NVPTXDAGToDAGISel::tryFence(SDNode *N) {
SDLoc DL(N);
assert(N->getOpcode() == ISD::ATOMIC_FENCE);
- unsigned int FenceOp =
- getFenceOp(NVPTX::Ordering(N->getConstantOperandVal(1)),
- Scopes[N->getConstantOperandVal(2)], Subtarget);
+ auto Scope = Scopes[N->getConstantOperandVal(2)];
+
+ // Singlethread fences have no inter-thread synchronization requirements.
+ if (Scope == NVPTX::Scope::Thread) {
+ ReplaceNode(N, N->getOperand(0).getNode());
+ return true;
+ }
+
+ unsigned int FenceOp = getFenceOp(
+ NVPTX::Ordering(N->getConstantOperandVal(1)), Scope, Subtarget);
SDValue Chain = N->getOperand(0);
SDNode *FenceNode = CurDAG->getMachineNode(FenceOp, DL, MVT::Other, Chain);
ReplaceNode(N, FenceNode);
@@ -2310,4 +2318,4 @@ void NVPTXDAGToDAGISel::selectBR_JT(SDNode *N) {
SDValue(Chain, 0), SDValue(Chain, 1)});
ReplaceNode(N, BrxEnd);
-}
\ No newline at end of file
+}
More information about the llvm-commits
mailing list