Skip to content

Commit 3cfd0c0

Browse files
authored
[SPIRV][RFC] Rework / extend support for memory scopes (#106429)
This change adds support for correctly lowering the `__scoped` Clang builtins, and corresponding scoped LLVM instructions. These were previously unconditionally lowered to Device scope, which is possibly incorrect. Furthermore, the default / implicit scope is changed from Device (an OpenCL assumption) to AllSvmDevices (aka System), since the SPIR-V BE is not OpenCL specific / can ingest IR coming from other language front-ends. OpenCL defaulting to Device scope is now reflected in the front-end handling of atomic ops, which seems preferable.
1 parent 4c3fccd commit 3cfd0c0

24 files changed

+775
-226
lines changed

clang/lib/Basic/Targets/SPIR.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,9 @@ class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public BaseSPIRVTargetInfo {
335335
PointerWidth = PointerAlign = 32;
336336
SizeType = TargetInfo::UnsignedInt;
337337
PtrDiffType = IntPtrType = TargetInfo::SignedInt;
338+
// SPIR-V has core support for atomic ops, and Int32 is always available;
339+
// we take the maximum because it's possible the Host supports wider types.
340+
MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 32);
338341
resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-"
339342
"v96:128-v192:256-v256:256-v512:512-v1024:1024-G1");
340343
}
@@ -356,6 +359,9 @@ class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public BaseSPIRVTargetInfo {
356359
PointerWidth = PointerAlign = 64;
357360
SizeType = TargetInfo::UnsignedLong;
358361
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
362+
// SPIR-V has core support for atomic ops, and Int64 is always available;
363+
// we take the maximum because it's possible the Host supports wider types.
364+
MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 64);
359365
resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-"
360366
"v96:128-v192:256-v256:256-v512:512-v1024:1024-G1");
361367
}

clang/lib/CodeGen/CGAtomic.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -766,8 +766,19 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *Expr, Address Dest,
766766
// LLVM atomic instructions always have synch scope. If clang atomic
767767
// expression has no scope operand, use default LLVM synch scope.
768768
if (!ScopeModel) {
769+
llvm::SyncScope::ID SS;
770+
if (CGF.getLangOpts().OpenCL)
771+
// OpenCL approach is: "The functions that do not have memory_scope
772+
// argument have the same semantics as the corresponding functions with
773+
// the memory_scope argument set to memory_scope_device." See ref.:
774+
// https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_C.html#atomic-functions
775+
SS = CGF.getTargetHooks().getLLVMSyncScopeID(CGF.getLangOpts(),
776+
SyncScope::OpenCLDevice,
777+
Order, CGF.getLLVMContext());
778+
else
779+
SS = llvm::SyncScope::System;
769780
EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
770-
Order, CGF.CGM.getLLVMContext().getOrInsertSyncScopeID(""));
781+
Order, SS);
771782
return;
772783
}
773784

clang/lib/CodeGen/Targets/SPIR.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,36 @@ class SPIRVTargetCodeGenInfo : public CommonSPIRTargetCodeGenInfo {
5858
SPIRVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
5959
: CommonSPIRTargetCodeGenInfo(std::make_unique<SPIRVABIInfo>(CGT)) {}
6060
void setCUDAKernelCallingConvention(const FunctionType *&FT) const override;
61+
llvm::SyncScope::ID getLLVMSyncScopeID(const LangOptions &LangOpts,
62+
SyncScope Scope,
63+
llvm::AtomicOrdering Ordering,
64+
llvm::LLVMContext &Ctx) const override;
6165
};
66+
67+
inline StringRef mapClangSyncScopeToLLVM(SyncScope Scope) {
68+
switch (Scope) {
69+
case SyncScope::HIPSingleThread:
70+
case SyncScope::SingleScope:
71+
return "singlethread";
72+
case SyncScope::HIPWavefront:
73+
case SyncScope::OpenCLSubGroup:
74+
case SyncScope::WavefrontScope:
75+
return "subgroup";
76+
case SyncScope::HIPWorkgroup:
77+
case SyncScope::OpenCLWorkGroup:
78+
case SyncScope::WorkgroupScope:
79+
return "workgroup";
80+
case SyncScope::HIPAgent:
81+
case SyncScope::OpenCLDevice:
82+
case SyncScope::DeviceScope:
83+
return "device";
84+
case SyncScope::SystemScope:
85+
case SyncScope::HIPSystem:
86+
case SyncScope::OpenCLAllSVMDevices:
87+
return "";
88+
}
89+
return "";
90+
}
6291
} // End anonymous namespace.
6392

6493
void CommonSPIRABIInfo::setCCs() {
@@ -188,6 +217,13 @@ void SPIRVTargetCodeGenInfo::setCUDAKernelCallingConvention(
188217
}
189218
}
190219

220+
llvm::SyncScope::ID
221+
SPIRVTargetCodeGenInfo::getLLVMSyncScopeID(const LangOptions &, SyncScope Scope,
222+
llvm::AtomicOrdering,
223+
llvm::LLVMContext &Ctx) const {
224+
return Ctx.getOrInsertSyncScopeID(mapClangSyncScopeToLLVM(Scope));
225+
}
226+
191227
/// Construct a SPIR-V target extension type for the given OpenCL image type.
192228
static llvm::Type *getSPIRVImageType(llvm::LLVMContext &Ctx, StringRef BaseType,
193229
StringRef OpenCLName,

clang/test/CodeGen/scoped-atomic-ops.c

Lines changed: 223 additions & 113 deletions
Large diffs are not rendered by default.
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
2+
// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -O3 -o - -triple=amdgcn-amd-amdhsa \
3+
// RUN: | FileCheck %s --check-prefix=AMDGCN
4+
// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -O3 -o - -triple=spirv64-unknown-unknown \
5+
// RUN: | FileCheck %s --check-prefix=SPIRV
6+
7+
// AMDGCN-LABEL: define dso_local i32 @load(
8+
// AMDGCN-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
9+
// AMDGCN-NEXT: [[ENTRY:.*:]]
10+
// AMDGCN-NEXT: [[TMP0:%.*]] = load atomic i32, ptr [[P]] syncscope("agent") seq_cst, align 4
11+
// AMDGCN-NEXT: ret i32 [[TMP0]]
12+
//
13+
// SPIRV-LABEL: define spir_func i32 @load(
14+
// SPIRV-SAME: ptr addrspace(4) nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
15+
// SPIRV-NEXT: [[ENTRY:.*:]]
16+
// SPIRV-NEXT: [[TMP0:%.*]] = load atomic i32, ptr addrspace(4) [[P]] syncscope("device") seq_cst, align 4
17+
// SPIRV-NEXT: ret i32 [[TMP0]]
18+
//
19+
int load(int *p) { return __atomic_load_n(p, __ATOMIC_SEQ_CST); }
20+
// AMDGCN-LABEL: define dso_local void @store(
21+
// AMDGCN-SAME: ptr nocapture noundef writeonly [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
22+
// AMDGCN-NEXT: [[ENTRY:.*:]]
23+
// AMDGCN-NEXT: store atomic i32 [[X]], ptr [[P]] syncscope("agent") seq_cst, align 4
24+
// AMDGCN-NEXT: ret void
25+
//
26+
// SPIRV-LABEL: define spir_func void @store(
27+
// SPIRV-SAME: ptr addrspace(4) nocapture noundef writeonly [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
28+
// SPIRV-NEXT: [[ENTRY:.*:]]
29+
// SPIRV-NEXT: store atomic i32 [[X]], ptr addrspace(4) [[P]] syncscope("device") seq_cst, align 4
30+
// SPIRV-NEXT: ret void
31+
//
32+
void store(int *p, int x) { return __atomic_store_n(p, x, __ATOMIC_SEQ_CST); }
33+
// AMDGCN-LABEL: define dso_local i32 @add(
34+
// AMDGCN-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
35+
// AMDGCN-NEXT: [[ENTRY:.*:]]
36+
// AMDGCN-NEXT: [[TMP0:%.*]] = atomicrmw add ptr [[P]], i32 [[X]] syncscope("agent") seq_cst, align 4
37+
// AMDGCN-NEXT: ret i32 [[TMP0]]
38+
//
39+
// SPIRV-LABEL: define spir_func i32 @add(
40+
// SPIRV-SAME: ptr addrspace(4) nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
41+
// SPIRV-NEXT: [[ENTRY:.*:]]
42+
// SPIRV-NEXT: [[TMP0:%.*]] = atomicrmw add ptr addrspace(4) [[P]], i32 [[X]] syncscope("device") seq_cst, align 4
43+
// SPIRV-NEXT: ret i32 [[TMP0]]
44+
//
45+
int add(int *p, int x) { return __atomic_fetch_add(p, x, __ATOMIC_SEQ_CST); }
46+
// AMDGCN-LABEL: define dso_local float @fadd(
47+
// AMDGCN-SAME: ptr nocapture noundef [[P:%.*]], float noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
48+
// AMDGCN-NEXT: [[ENTRY:.*:]]
49+
// AMDGCN-NEXT: [[TMP0:%.*]] = atomicrmw fadd ptr [[P]], float [[X]] syncscope("agent") seq_cst, align 4
50+
// AMDGCN-NEXT: ret float [[TMP0]]
51+
//
52+
// SPIRV-LABEL: define spir_func float @fadd(
53+
// SPIRV-SAME: ptr addrspace(4) nocapture noundef [[P:%.*]], float noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
54+
// SPIRV-NEXT: [[ENTRY:.*:]]
55+
// SPIRV-NEXT: [[TMP0:%.*]] = atomicrmw fadd ptr addrspace(4) [[P]], float [[X]] syncscope("device") seq_cst, align 4
56+
// SPIRV-NEXT: ret float [[TMP0]]
57+
//
58+
float fadd(float *p, float x) { return __atomic_fetch_add(p, x, __ATOMIC_SEQ_CST); }
59+
// AMDGCN-LABEL: define dso_local i32 @sub(
60+
// AMDGCN-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
61+
// AMDGCN-NEXT: [[ENTRY:.*:]]
62+
// AMDGCN-NEXT: [[TMP0:%.*]] = atomicrmw sub ptr [[P]], i32 [[X]] syncscope("agent") seq_cst, align 4
63+
// AMDGCN-NEXT: ret i32 [[TMP0]]
64+
//
65+
// SPIRV-LABEL: define spir_func i32 @sub(
66+
// SPIRV-SAME: ptr addrspace(4) nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
67+
// SPIRV-NEXT: [[ENTRY:.*:]]
68+
// SPIRV-NEXT: [[TMP0:%.*]] = atomicrmw sub ptr addrspace(4) [[P]], i32 [[X]] syncscope("device") seq_cst, align 4
69+
// SPIRV-NEXT: ret i32 [[TMP0]]
70+
//
71+
int sub(int *p, int x) { return __atomic_fetch_sub(p, x, __ATOMIC_SEQ_CST); }
72+
// AMDGCN-LABEL: define dso_local float @fsub(
73+
// AMDGCN-SAME: ptr nocapture noundef [[P:%.*]], float noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
74+
// AMDGCN-NEXT: [[ENTRY:.*:]]
75+
// AMDGCN-NEXT: [[TMP0:%.*]] = atomicrmw fsub ptr [[P]], float [[X]] syncscope("agent") seq_cst, align 4
76+
// AMDGCN-NEXT: ret float [[TMP0]]
77+
//
78+
// SPIRV-LABEL: define spir_func float @fsub(
79+
// SPIRV-SAME: ptr addrspace(4) nocapture noundef [[P:%.*]], float noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
80+
// SPIRV-NEXT: [[ENTRY:.*:]]
81+
// SPIRV-NEXT: [[TMP0:%.*]] = atomicrmw fsub ptr addrspace(4) [[P]], float [[X]] syncscope("device") seq_cst, align 4
82+
// SPIRV-NEXT: ret float [[TMP0]]
83+
//
84+
float fsub(float *p, float x) { return __atomic_fetch_sub(p, x, __ATOMIC_SEQ_CST); }
85+
// AMDGCN-LABEL: define dso_local i32 @and(
86+
// AMDGCN-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
87+
// AMDGCN-NEXT: [[ENTRY:.*:]]
88+
// AMDGCN-NEXT: [[TMP0:%.*]] = atomicrmw and ptr [[P]], i32 [[X]] syncscope("agent") seq_cst, align 4
89+
// AMDGCN-NEXT: ret i32 [[TMP0]]
90+
//
91+
// SPIRV-LABEL: define spir_func i32 @and(
92+
// SPIRV-SAME: ptr addrspace(4) nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
93+
// SPIRV-NEXT: [[ENTRY:.*:]]
94+
// SPIRV-NEXT: [[TMP0:%.*]] = atomicrmw and ptr addrspace(4) [[P]], i32 [[X]] syncscope("device") seq_cst, align 4
95+
// SPIRV-NEXT: ret i32 [[TMP0]]
96+
//
97+
int and(int *p, int x) { return __atomic_fetch_and(p, x, __ATOMIC_SEQ_CST); }
98+
// AMDGCN-LABEL: define dso_local i32 @nand(
99+
// AMDGCN-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
100+
// AMDGCN-NEXT: [[ENTRY:.*:]]
101+
// AMDGCN-NEXT: [[TMP0:%.*]] = atomicrmw nand ptr [[P]], i32 [[X]] syncscope("agent") seq_cst, align 4
102+
// AMDGCN-NEXT: ret i32 [[TMP0]]
103+
//
104+
// SPIRV-LABEL: define spir_func i32 @nand(
105+
// SPIRV-SAME: ptr addrspace(4) nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
106+
// SPIRV-NEXT: [[ENTRY:.*:]]
107+
// SPIRV-NEXT: [[TMP0:%.*]] = atomicrmw nand ptr addrspace(4) [[P]], i32 [[X]] syncscope("device") seq_cst, align 4
108+
// SPIRV-NEXT: ret i32 [[TMP0]]
109+
//
110+
int nand(int *p, int x) { return __atomic_fetch_nand(p, x, __ATOMIC_SEQ_CST); }
111+
// AMDGCN-LABEL: define dso_local i32 @or(
112+
// AMDGCN-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
113+
// AMDGCN-NEXT: [[ENTRY:.*:]]
114+
// AMDGCN-NEXT: [[TMP0:%.*]] = atomicrmw or ptr [[P]], i32 [[X]] syncscope("agent") seq_cst, align 4
115+
// AMDGCN-NEXT: ret i32 [[TMP0]]
116+
//
117+
// SPIRV-LABEL: define spir_func i32 @or(
118+
// SPIRV-SAME: ptr addrspace(4) nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
119+
// SPIRV-NEXT: [[ENTRY:.*:]]
120+
// SPIRV-NEXT: [[TMP0:%.*]] = atomicrmw or ptr addrspace(4) [[P]], i32 [[X]] syncscope("device") seq_cst, align 4
121+
// SPIRV-NEXT: ret i32 [[TMP0]]
122+
//
123+
int or(int *p, int x) { return __atomic_fetch_or(p, x, __ATOMIC_SEQ_CST); }
124+
// AMDGCN-LABEL: define dso_local i32 @xor(
125+
// AMDGCN-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
126+
// AMDGCN-NEXT: [[ENTRY:.*:]]
127+
// AMDGCN-NEXT: [[TMP0:%.*]] = atomicrmw xor ptr [[P]], i32 [[X]] syncscope("agent") seq_cst, align 4
128+
// AMDGCN-NEXT: ret i32 [[TMP0]]
129+
//
130+
// SPIRV-LABEL: define spir_func i32 @xor(
131+
// SPIRV-SAME: ptr addrspace(4) nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
132+
// SPIRV-NEXT: [[ENTRY:.*:]]
133+
// SPIRV-NEXT: [[TMP0:%.*]] = atomicrmw xor ptr addrspace(4) [[P]], i32 [[X]] syncscope("device") seq_cst, align 4
134+
// SPIRV-NEXT: ret i32 [[TMP0]]
135+
//
136+
int xor(int *p, int x) { return __atomic_fetch_xor(p, x, __ATOMIC_SEQ_CST); }
137+
// AMDGCN-LABEL: define dso_local i32 @min(
138+
// AMDGCN-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
139+
// AMDGCN-NEXT: [[ENTRY:.*:]]
140+
// AMDGCN-NEXT: [[TMP0:%.*]] = atomicrmw min ptr [[P]], i32 [[X]] syncscope("agent") seq_cst, align 4
141+
// AMDGCN-NEXT: ret i32 [[TMP0]]
142+
//
143+
// SPIRV-LABEL: define spir_func i32 @min(
144+
// SPIRV-SAME: ptr addrspace(4) nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
145+
// SPIRV-NEXT: [[ENTRY:.*:]]
146+
// SPIRV-NEXT: [[TMP0:%.*]] = atomicrmw min ptr addrspace(4) [[P]], i32 [[X]] syncscope("device") seq_cst, align 4
147+
// SPIRV-NEXT: ret i32 [[TMP0]]
148+
//
149+
int min(int *p, int x) { return __atomic_fetch_min(p, x, __ATOMIC_SEQ_CST); }
150+
// AMDGCN-LABEL: define dso_local float @fmin(
151+
// AMDGCN-SAME: ptr nocapture noundef [[P:%.*]], float noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
152+
// AMDGCN-NEXT: [[ENTRY:.*:]]
153+
// AMDGCN-NEXT: [[TMP0:%.*]] = atomicrmw fmin ptr [[P]], float [[X]] syncscope("agent") seq_cst, align 4
154+
// AMDGCN-NEXT: ret float [[TMP0]]
155+
//
156+
// SPIRV-LABEL: define spir_func float @fmin(
157+
// SPIRV-SAME: ptr addrspace(4) nocapture noundef [[P:%.*]], float noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
158+
// SPIRV-NEXT: [[ENTRY:.*:]]
159+
// SPIRV-NEXT: [[TMP0:%.*]] = atomicrmw fmin ptr addrspace(4) [[P]], float [[X]] syncscope("device") seq_cst, align 4
160+
// SPIRV-NEXT: ret float [[TMP0]]
161+
//
162+
float fmin(float *p, float x) { return __atomic_fetch_min(p, x, __ATOMIC_SEQ_CST); }
163+
// AMDGCN-LABEL: define dso_local i32 @max(
164+
// AMDGCN-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
165+
// AMDGCN-NEXT: [[ENTRY:.*:]]
166+
// AMDGCN-NEXT: [[TMP0:%.*]] = atomicrmw max ptr [[P]], i32 [[X]] syncscope("agent") seq_cst, align 4
167+
// AMDGCN-NEXT: ret i32 [[TMP0]]
168+
//
169+
// SPIRV-LABEL: define spir_func i32 @max(
170+
// SPIRV-SAME: ptr addrspace(4) nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
171+
// SPIRV-NEXT: [[ENTRY:.*:]]
172+
// SPIRV-NEXT: [[TMP0:%.*]] = atomicrmw max ptr addrspace(4) [[P]], i32 [[X]] syncscope("device") seq_cst, align 4
173+
// SPIRV-NEXT: ret i32 [[TMP0]]
174+
//
175+
int max(int *p, int x) { return __atomic_fetch_max(p, x, __ATOMIC_SEQ_CST); }
176+
// AMDGCN-LABEL: define dso_local float @fmax(
177+
// AMDGCN-SAME: ptr nocapture noundef [[P:%.*]], float noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
178+
// AMDGCN-NEXT: [[ENTRY:.*:]]
179+
// AMDGCN-NEXT: [[TMP0:%.*]] = atomicrmw fmax ptr [[P]], float [[X]] syncscope("agent") seq_cst, align 4
180+
// AMDGCN-NEXT: ret float [[TMP0]]
181+
//
182+
// SPIRV-LABEL: define spir_func float @fmax(
183+
// SPIRV-SAME: ptr addrspace(4) nocapture noundef [[P:%.*]], float noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
184+
// SPIRV-NEXT: [[ENTRY:.*:]]
185+
// SPIRV-NEXT: [[TMP0:%.*]] = atomicrmw fmax ptr addrspace(4) [[P]], float [[X]] syncscope("device") seq_cst, align 4
186+
// SPIRV-NEXT: ret float [[TMP0]]
187+
//
188+
float fmax(float *p, float x) { return __atomic_fetch_max(p, x, __ATOMIC_SEQ_CST); }
189+
// AMDGCN-LABEL: define dso_local i32 @xchg(
190+
// AMDGCN-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
191+
// AMDGCN-NEXT: [[ENTRY:.*:]]
192+
// AMDGCN-NEXT: [[TMP0:%.*]] = atomicrmw xchg ptr [[P]], i32 [[X]] syncscope("agent") seq_cst, align 4
193+
// AMDGCN-NEXT: ret i32 [[TMP0]]
194+
//
195+
// SPIRV-LABEL: define spir_func i32 @xchg(
196+
// SPIRV-SAME: ptr addrspace(4) nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
197+
// SPIRV-NEXT: [[ENTRY:.*:]]
198+
// SPIRV-NEXT: [[TMP0:%.*]] = atomicrmw xchg ptr addrspace(4) [[P]], i32 [[X]] syncscope("device") seq_cst, align 4
199+
// SPIRV-NEXT: ret i32 [[TMP0]]
200+
//
201+
int xchg(int *p, int x) { return __atomic_exchange_n(p, x, __ATOMIC_SEQ_CST); }
202+
// AMDGCN-LABEL: define dso_local range(i32 0, 2) i32 @cmpxchg(
203+
// AMDGCN-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
204+
// AMDGCN-NEXT: [[ENTRY:.*:]]
205+
// AMDGCN-NEXT: [[TMP0:%.*]] = cmpxchg ptr [[P]], i32 [[X]], i32 [[Y]] syncscope("agent") seq_cst seq_cst, align 4
206+
// AMDGCN-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1
207+
// AMDGCN-NEXT: [[CONV:%.*]] = zext i1 [[TMP1]] to i32
208+
// AMDGCN-NEXT: ret i32 [[CONV]]
209+
//
210+
// SPIRV-LABEL: define spir_func range(i32 0, 2) i32 @cmpxchg(
211+
// SPIRV-SAME: ptr addrspace(4) nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
212+
// SPIRV-NEXT: [[ENTRY:.*:]]
213+
// SPIRV-NEXT: [[TMP0:%.*]] = cmpxchg ptr addrspace(4) [[P]], i32 [[X]], i32 [[Y]] syncscope("device") seq_cst seq_cst, align 4
214+
// SPIRV-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1
215+
// SPIRV-NEXT: [[CONV:%.*]] = zext i1 [[TMP1]] to i32
216+
// SPIRV-NEXT: ret i32 [[CONV]]
217+
//
218+
int cmpxchg(int *p, int x, int y) { return __atomic_compare_exchange(p, &x, &y, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
219+
// AMDGCN-LABEL: define dso_local range(i32 0, 2) i32 @cmpxchg_weak(
220+
// AMDGCN-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
221+
// AMDGCN-NEXT: [[ENTRY:.*:]]
222+
// AMDGCN-NEXT: [[TMP0:%.*]] = cmpxchg weak ptr [[P]], i32 [[X]], i32 [[Y]] syncscope("agent") seq_cst seq_cst, align 4
223+
// AMDGCN-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1
224+
// AMDGCN-NEXT: [[CONV:%.*]] = zext i1 [[TMP1]] to i32
225+
// AMDGCN-NEXT: ret i32 [[CONV]]
226+
//
227+
// SPIRV-LABEL: define spir_func range(i32 0, 2) i32 @cmpxchg_weak(
228+
// SPIRV-SAME: ptr addrspace(4) nocapture noundef [[P:%.*]], i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
229+
// SPIRV-NEXT: [[ENTRY:.*:]]
230+
// SPIRV-NEXT: [[TMP0:%.*]] = cmpxchg weak ptr addrspace(4) [[P]], i32 [[X]], i32 [[Y]] syncscope("device") seq_cst seq_cst, align 4
231+
// SPIRV-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1
232+
// SPIRV-NEXT: [[CONV:%.*]] = zext i1 [[TMP1]] to i32
233+
// SPIRV-NEXT: ret i32 [[CONV]]
234+
//
235+
int cmpxchg_weak(int *p, int x, int y) { return __atomic_compare_exchange(p, &x, &y, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }

clang/test/Sema/scoped-atomic-ops.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// RUN: %clang_cc1 -x c -triple=amdgcn-amd-amdhsa -verify -fsyntax-only %s
22
// RUN: %clang_cc1 -x c -triple=x86_64-pc-linux-gnu -verify -fsyntax-only %s
3+
// RUN: %clang_cc1 -x c -triple=spirv64-unknown-unknown -verify -fsyntax-only %s
34

45
int fi1a(int *i) {
56
int v;

llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1351,7 +1351,8 @@ Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {
13511351
SmallVector<Value *> Args;
13521352
for (auto &Op : I.operands())
13531353
Args.push_back(Op);
1354-
Args.push_back(B.getInt32(I.getSyncScopeID()));
1354+
Args.push_back(B.getInt32(
1355+
static_cast<uint32_t>(getMemScope(I.getContext(), I.getSyncScopeID()))));
13551356
Args.push_back(B.getInt32(
13561357
static_cast<uint32_t>(getMemSemantics(I.getSuccessOrdering()))));
13571358
Args.push_back(B.getInt32(

0 commit comments

Comments
 (0)