[llvm] 52ea06f - [SPIRV] Add tests documenting incorrect lowering of load/store atomic (#185628)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 11 01:40:15 PDT 2026
Author: Juan Manuel Martinez CaamaƱo
Date: 2026-03-11T09:40:10+01:00
New Revision: 52ea06f88455fca0d2b4defcfda84fe2fdbe362a
URL: https://github.com/llvm/llvm-project/commit/52ea06f88455fca0d2b4defcfda84fe2fdbe362a
DIFF: https://github.com/llvm/llvm-project/commit/52ea06f88455fca0d2b4defcfda84fe2fdbe362a.diff
LOG: [SPIRV] Add tests documenting incorrect lowering of load/store atomic (#185628)
This patch only adds the tests documenting the broken behavior, but does
not fix them.
Added:
llvm/test/CodeGen/SPIRV/transcoding/load-atomic.ll
llvm/test/CodeGen/SPIRV/transcoding/store-atomic.ll
Modified:
Removed:
################################################################################
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/load-atomic.ll b/llvm/test/CodeGen/SPIRV/transcoding/load-atomic.ll
new file mode 100644
index 0000000000000..0ebd3a5ec20ae
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/transcoding/load-atomic.ll
@@ -0,0 +1,111 @@
+; RUN: llc -O0 -mtriple=spirv64-- %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-- %s -o - -filetype=obj | spirv-val %}
+
+; RUN: llc -O0 -mtriple=spirv32-- %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-- %s -o - -filetype=obj | spirv-val %}
+
+;; Check that 'load atomic' LLVM IR instructions are lowered.
+;; NOTE: The current lowering is incorrect: 'load atomic' should produce
+;; OpAtomicLoad but currently produces OpLoad, silently dropping the atomic
+;; ordering. This test documents the broken behaviour so it can be fixed.
+
+; CHECK-DAG: %[[#Int32:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#Float:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#Int32Vec:]] = OpTypeVector %[[#Int32]] 2
+
+define i32 @load_i32_unordered(ptr addrspace(1) %ptr) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#]] = OpLoad %[[#Int32]] %[[#ptr]] Aligned 4
+; CHECK: OpReturnValue
+ %val = load atomic i32, ptr addrspace(1) %ptr unordered, align 4
+ ret i32 %val
+}
+
+define i32 @load_i32_monotonic(ptr addrspace(1) %ptr) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#]] = OpLoad %[[#Int32]] %[[#ptr]] Aligned 4
+; CHECK: OpReturnValue
+ %val = load atomic i32, ptr addrspace(1) %ptr monotonic, align 4
+ ret i32 %val
+}
+
+define i32 @load_i32_acquire(ptr addrspace(1) %ptr) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#]] = OpLoad %[[#Int32]] %[[#ptr]] Aligned 4
+; CHECK: OpReturnValue
+ %val = load atomic i32, ptr addrspace(1) %ptr acquire, align 4
+ ret i32 %val
+}
+
+define i32 @load_i32_seq_cst(ptr addrspace(1) %ptr) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#]] = OpLoad %[[#Int32]] %[[#ptr]] Aligned 4
+; CHECK: OpReturnValue
+ %val = load atomic i32, ptr addrspace(1) %ptr seq_cst, align 4
+ ret i32 %val
+}
+
+; -- test with
diff erent syncscopes
+
+define i32 @load_i32_acquire_singlethread(ptr addrspace(1) %ptr) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#]] = OpLoad %[[#Int32]] %[[#ptr]] Aligned 4
+; CHECK: OpReturnValue
+ %val = load atomic i32, ptr addrspace(1) %ptr syncscope("singlethread") acquire, align 4
+ ret i32 %val
+}
+
+define i32 @load_i32_acquire_subgroup(ptr addrspace(1) %ptr) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#]] = OpLoad %[[#Int32]] %[[#ptr]] Aligned 4
+; CHECK: OpReturnValue
+ %val = load atomic i32, ptr addrspace(1) %ptr syncscope("subgroup") acquire, align 4
+ ret i32 %val
+}
+
+define i32 @load_i32_acquire_workgroup(ptr addrspace(1) %ptr) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#]] = OpLoad %[[#Int32]] %[[#ptr]] Aligned 4
+; CHECK: OpReturnValue
+ %val = load atomic i32, ptr addrspace(1) %ptr syncscope("workgroup") acquire, align 4
+ ret i32 %val
+}
+
+define i32 @load_i32_acquire_device(ptr addrspace(1) %ptr) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#]] = OpLoad %[[#Int32]] %[[#ptr]] Aligned 4
+; CHECK: OpReturnValue
+ %val = load atomic i32, ptr addrspace(1) %ptr syncscope("device") acquire, align 4
+ ret i32 %val
+}
+
+; -- test with a
diff erent scalar type
+
+define float @load_float_acquire(ptr addrspace(1) %ptr) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#load:]] = OpLoad %[[#Int32]] %[[#ptr]] Aligned 8
+; CHECK: %[[#val:]] = OpBitcast %[[#Float]] %[[#load]]
+; CHECK: OpReturnValue %[[#val]]
+ %val = load atomic float, ptr addrspace(1) %ptr acquire, align 8
+ ret float %val
+}
+
+; -- test with a vector type
+
+define <2 x i32> @load_vector_acquire(ptr addrspace(1) %ptr) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#]] = OpLoad %[[#Int32Vec]] %[[#ptr]] Aligned 8
+; CHECK: OpReturnValue
+ %val = load atomic <2 x i32>, ptr addrspace(1) %ptr acquire, align 8
+ ret <2 x i32> %val
+}
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/store-atomic.ll b/llvm/test/CodeGen/SPIRV/transcoding/store-atomic.ll
new file mode 100644
index 0000000000000..b11b26451d086
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/transcoding/store-atomic.ll
@@ -0,0 +1,121 @@
+; RUN: llc -O0 -mtriple=spirv64-- %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-- %s -o - -filetype=obj | spirv-val %}
+
+; RUN: llc -O0 -mtriple=spirv32-- %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-- %s -o - -filetype=obj | spirv-val %}
+
+;; Check that 'store atomic' LLVM IR instructions are lowered.
+;; NOTE: The current lowering is incorrect: 'store atomic' should produce
+;; OpAtomicStore but currently produces OpStore, silently dropping the atomic
+;; ordering. This test documents the broken behaviour so it can be fixed.
+
+; CHECK-DAG: %[[#Int32:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#Float:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#Int32Vec:]] = OpTypeVector %[[#Int32]] 2
+
+define void @store_i32_unordered(ptr addrspace(1) %ptr, i32 %val) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#val:]] = OpFunctionParameter %[[#Int32]]
+; CHECK: OpStore %[[#ptr]] %[[#val]] Aligned 4
+; CHECK: OpReturn
+ store atomic i32 %val, ptr addrspace(1) %ptr unordered, align 4
+ ret void
+}
+
+define void @store_i32_monotonic(ptr addrspace(1) %ptr, i32 %val) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#val:]] = OpFunctionParameter %[[#Int32]]
+; CHECK: OpStore %[[#ptr]] %[[#val]] Aligned 4
+; CHECK: OpReturn
+ store atomic i32 %val, ptr addrspace(1) %ptr monotonic, align 4
+ ret void
+}
+
+define void @store_i32_release(ptr addrspace(1) %ptr, i32 %val) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#val:]] = OpFunctionParameter %[[#Int32]]
+; CHECK: OpStore %[[#ptr]] %[[#val]] Aligned 4
+; CHECK: OpReturn
+ store atomic i32 %val, ptr addrspace(1) %ptr release, align 4
+ ret void
+}
+
+define void @store_i32_seq_cst(ptr addrspace(1) %ptr, i32 %val) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#val:]] = OpFunctionParameter %[[#Int32]]
+; CHECK: OpStore %[[#ptr]] %[[#val]] Aligned 4
+; CHECK: OpReturn
+ store atomic i32 %val, ptr addrspace(1) %ptr seq_cst, align 4
+ ret void
+}
+
+; -- test with
diff erent syncscopes
+
+define void @store_i32_release_singlethread(ptr addrspace(1) %ptr, i32 %val) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#val:]] = OpFunctionParameter %[[#Int32]]
+; CHECK: OpStore %[[#ptr]] %[[#val]] Aligned 4
+; CHECK: OpReturn
+ store atomic i32 %val, ptr addrspace(1) %ptr syncscope("singlethread") release, align 4
+ ret void
+}
+
+define void @store_i32_release_subgroup(ptr addrspace(1) %ptr, i32 %val) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#val:]] = OpFunctionParameter %[[#Int32]]
+; CHECK: OpStore %[[#ptr]] %[[#val]] Aligned 4
+; CHECK: OpReturn
+ store atomic i32 %val, ptr addrspace(1) %ptr syncscope("subgroup") release, align 4
+ ret void
+}
+
+define void @store_i32_release_workgroup(ptr addrspace(1) %ptr, i32 %val) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#val:]] = OpFunctionParameter %[[#Int32]]
+; CHECK: OpStore %[[#ptr]] %[[#val]] Aligned 4
+; CHECK: OpReturn
+ store atomic i32 %val, ptr addrspace(1) %ptr syncscope("workgroup") release, align 4
+ ret void
+}
+
+define void @store_i32_release_device(ptr addrspace(1) %ptr, i32 %val) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#val:]] = OpFunctionParameter %[[#Int32]]
+; CHECK: OpStore %[[#ptr]] %[[#val]] Aligned 4
+; CHECK: OpReturn
+ store atomic i32 %val, ptr addrspace(1) %ptr syncscope("device") release, align 4
+ ret void
+}
+
+; -- test with a
diff erent scalar type
+
+define void @store_float_release(ptr addrspace(1) %ptr, float %val) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#val:]] = OpFunctionParameter %[[#Float]]
+; CHECK: %[[#cast:]] = OpBitcast %[[#Int32]] %[[#val]]
+; CHECK: OpStore %[[#ptr]] %[[#cast]] Aligned 8
+; CHECK: OpReturn
+ store atomic float %val, ptr addrspace(1) %ptr release, align 8
+ ret void
+}
+
+; -- test with a vector type
+
+define void @store_vector_release(ptr addrspace(1) %ptr, <2 x i32> %val) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#val:]] = OpFunctionParameter %[[#Int32Vec]]
+; CHECK: OpStore %[[#ptr]] %[[#val]] Aligned 8
+; CHECK: OpReturn
+ store atomic <2 x i32> %val, ptr addrspace(1) %ptr release, align 8
+ ret void
+}
More information about the llvm-commits
mailing list