[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