[llvm] [SPIRV] Preserve FP types in atomic load/store instead of casting to integer (PR #194583)
Viktoria Maximova via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 28 03:20:47 PDT 2026
https://github.com/vmaksimo created https://github.com/llvm/llvm-project/pull/194583
The default `TargetLowering::shouldCastAtomicLoadInIR`/`shouldCastAtomicStoreInIR` cast all FP atomics to integer, producing unnecessary bitcasts in SPIR-V output. Override both to return None, matching the existing `shouldCastAtomicRMWIInIR` behavior and letting `OpAtomicLoad`/`OpAtomicStore` operate on FP types directly.
Also updated 16-bit atomics tests to use native load/store atomic instructions now that the SPIRV backend supports them (landed in #185696).
AI-assisted: Claude Sonnet 4.6 (commercial SaaS)
>From 23702b0612a0852455c36322a01e80ece741f951 Mon Sep 17 00:00:00 2001
From: "Maksimova, Viktoria" <viktoria.maksimova at intel.com>
Date: Tue, 28 Apr 2026 02:24:25 -0700
Subject: [PATCH] [SPIRV] Preserve FP types in atomic load/store instead of
casting to integer
The default TargetLowering::shouldCastAtomicLoadInIR/shouldCastAtomicStoreInIR
cast all FP atomics to integer, producing unnecessary bitcasts in SPIR-V output.
Override both to return None, matching the existing shouldCastAtomicRMWIInIR
behavior and letting OpAtomicLoad/OpAtomicStore operate on FP types directly.
Update 16-bit atomics tests to use native load/store atomic instructions
now that the SPIRV backend supports them (landed in #185696).
AI-assisted: Claude Sonnet 4.6 (commercial SaaS)
---
llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp | 15 +++++++++++++++
llvm/lib/Target/SPIRV/SPIRVISelLowering.h | 2 ++
.../atomic_bfloat16_load_store_xchg.ll | 15 ++++-----------
.../atomic_int16_load_store_xchg_cmpxchg.ll | 14 ++++----------
.../test/CodeGen/SPIRV/transcoding/load-atomic.ll | 3 +--
.../CodeGen/SPIRV/transcoding/store-atomic.ll | 3 +--
6 files changed, 27 insertions(+), 25 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp
index 7a0ff22f3ef16..89201f83e58dd 100644
--- a/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp
@@ -685,3 +685,18 @@ SPIRVTargetLowering::shouldCastAtomicRMWIInIR(AtomicRMWInst *RMWI) const {
// SPIR-V only supports atomic exchange for integer and floating-point types.
return AtomicExpansionKind::None;
}
+
+TargetLowering::AtomicExpansionKind
+SPIRVTargetLowering::shouldCastAtomicLoadInIR(LoadInst *LI) const {
+ // TODO: pointer load should return CastToInteger, but
+ // convertAtomicLoadToIntegerType uses BitCast which asserts on pointer types.
+ return AtomicExpansionKind::None;
+}
+
+TargetLowering::AtomicExpansionKind
+SPIRVTargetLowering::shouldCastAtomicStoreInIR(StoreInst *SI) const {
+ // TODO: pointer store should return CastToInteger, but
+ // convertAtomicStoreToIntegerType uses BitCast which asserts on pointer
+ // types.
+ return AtomicExpansionKind::None;
+}
diff --git a/llvm/lib/Target/SPIRV/SPIRVISelLowering.h b/llvm/lib/Target/SPIRV/SPIRVISelLowering.h
index cfc9f66358bda..aec6ffda0cea8 100644
--- a/llvm/lib/Target/SPIRV/SPIRVISelLowering.h
+++ b/llvm/lib/Target/SPIRV/SPIRVISelLowering.h
@@ -82,6 +82,8 @@ class SPIRVTargetLowering : public TargetLowering {
shouldExpandAtomicRMWInIR(const AtomicRMWInst *RMW) const override;
AtomicExpansionKind
shouldCastAtomicRMWIInIR(AtomicRMWInst *RMWI) const override;
+ AtomicExpansionKind shouldCastAtomicLoadInIR(LoadInst *LI) const override;
+ AtomicExpansionKind shouldCastAtomicStoreInIR(StoreInst *SI) const override;
};
} // namespace llvm
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_16bit_atomics/atomic_bfloat16_load_store_xchg.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_16bit_atomics/atomic_bfloat16_load_store_xchg.ll
index edd3c64ecb3a0..ff34aa00d2c45 100644
--- a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_16bit_atomics/atomic_bfloat16_load_store_xchg.ll
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_16bit_atomics/atomic_bfloat16_load_store_xchg.ll
@@ -14,14 +14,13 @@
; CHECK-DAG: %[[#TyInt32:]] = OpTypeInt 32 0
; CHECK-DAG: %[[#Const42:]] = OpConstant %[[#TyBF16]] 16936{{$}}
; CHECK-DAG: %[[#Const0:]] = OpConstantNull %[[#TyBF16]]
-; CHECK-DAG: %[[#ScopeDevice:]] = OpConstant %[[#TyInt32]] 1{{$}}
; CHECK-DAG: %[[#ScopeAllSvmDevices:]] = OpConstantNull %[[#TyInt32]]
; CHECK-DAG: %[[#MemSem528:]] = OpConstant %[[#TyInt32]] 528{{$}}
; CHECK-DAG: %[[#Val:]] = OpVariable %[[#TyBF16Ptr]] CrossWorkgroup %[[#Const0]]
-; CHECK: OpAtomicLoad %[[#TyBF16]] %[[#Val]] %[[#ScopeDevice]] %[[#MemSem528]]
-; CHECK: OpAtomicStore %[[#Val]] %[[#ScopeDevice]] %[[#MemSem528]] %[[#Const42]]
+; CHECK: OpAtomicLoad %[[#TyBF16]] %[[#Val]] %[[#ScopeAllSvmDevices]] %[[#MemSem528]]
+; CHECK: OpAtomicStore %[[#Val]] %[[#ScopeAllSvmDevices]] %[[#MemSem528]] %[[#Const42]]
; CHECK: OpAtomicExchange %[[#TyBF16]] %[[#Val]] %[[#ScopeAllSvmDevices]] %[[#MemSem528]] %[[#Const42]]
@@ -29,14 +28,8 @@
define spir_func void @test_atomic_bfloat16_load_store_xchg() {
entry:
-; TODO: 'load atomic'/'store atomic' LLVM instructions are not yet lowered to
-; OpAtomicLoad/OpAtomicStore by the SPIRV backend; use OCL builtins instead.
-; TODO: test Vulkan path as well once we support atomic load/store.
- %load = call spir_func bfloat @_Z11atomic_loadPU3AS1VU7_AtomicDF16b(ptr addrspace(1) @val)
- call spir_func void @_Z12atomic_storePU3AS1VU7_AtomicDF16bDF16b(ptr addrspace(1) @val, bfloat 42.000000e+00)
+ %load = load atomic bfloat, ptr addrspace(1) @val seq_cst, align 2
+ store atomic bfloat 42.000000e+00, ptr addrspace(1) @val seq_cst, align 2
%xchg = atomicrmw xchg ptr addrspace(1) @val, bfloat 42.000000e+00 seq_cst
ret void
}
-
-declare spir_func bfloat @_Z11atomic_loadPU3AS1VU7_AtomicDF16b(ptr addrspace(1))
-declare spir_func void @_Z12atomic_storePU3AS1VU7_AtomicDF16bDF16b(ptr addrspace(1), bfloat)
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_16bit_atomics/atomic_int16_load_store_xchg_cmpxchg.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_16bit_atomics/atomic_int16_load_store_xchg_cmpxchg.ll
index 8d74032b4d66a..ebade9c2fbd9e 100644
--- a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_16bit_atomics/atomic_int16_load_store_xchg_cmpxchg.ll
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_16bit_atomics/atomic_int16_load_store_xchg_cmpxchg.ll
@@ -15,14 +15,13 @@
; CHECK-DAG: %[[#Const0:]] = OpConstantNull %[[#TyInt16]]
; CHECK-DAG: %[[#Const1:]] = OpConstant %[[#TyInt16]] 1{{$}}
; CHECK-DAG: %[[#Const42:]] = OpConstant %[[#TyInt16]] 42{{$}}
-; CHECK-DAG: %[[#ScopeDevice:]] = OpConstant %[[#TyInt32]] 1{{$}}
; CHECK-DAG: %[[#ScopeAllSvmDevices:]] = OpConstantNull %[[#TyInt32]]
; CHECK-DAG: %[[#MemSem528:]] = OpConstant %[[#TyInt32]] 528{{$}}
; CHECK-DAG: %[[#Val:]] = OpVariable %[[#TyInt16Ptr]] CrossWorkgroup %[[#Const0]]
-; CHECK: OpAtomicLoad %[[#TyInt16]] %[[#Val]] %[[#ScopeDevice]] %[[#MemSem528]]
-; CHECK: OpAtomicStore %[[#Val]] %[[#ScopeDevice]] %[[#MemSem528]] %[[#Const42]]
+; CHECK: OpAtomicLoad %[[#TyInt16]] %[[#Val]] %[[#ScopeAllSvmDevices]] %[[#MemSem528]]
+; CHECK: OpAtomicStore %[[#Val]] %[[#ScopeAllSvmDevices]] %[[#MemSem528]] %[[#Const42]]
; CHECK: OpAtomicExchange %[[#TyInt16]] %[[#Val]] %[[#ScopeAllSvmDevices]] %[[#MemSem528]] %[[#Const42]]
; CHECK: OpAtomicCompareExchange %[[#TyInt16]] %[[#]] %[[#ScopeAllSvmDevices]] %[[#MemSem528]] %[[#MemSem528]] %[[#Const42]] %[[#Const1]]
@@ -31,14 +30,9 @@
define spir_func void @test_atomic_int16_basic() {
entry:
-; TODO: 'load atomic'/'store atomic' LLVM instructions are not yet lowered to
-; OpAtomicLoad/OpAtomicStore by the SPIRV backend; use OCL builtins instead.
- %load = call spir_func i16 @_Z11atomic_loadPU3AS1VU7_Atomics(ptr addrspace(1) @val)
- call spir_func void @_Z12atomic_storePU3AS1VU7_Atomicss(ptr addrspace(1) @val, i16 42)
+ %load = load atomic i16, ptr addrspace(1) @val seq_cst, align 2
+ store atomic i16 42, ptr addrspace(1) @val seq_cst, align 2
%xchg = atomicrmw xchg ptr addrspace(1) @val, i16 42 seq_cst
%cmpxchg = cmpxchg ptr addrspace(1) @val, i16 1, i16 42 seq_cst seq_cst
ret void
}
-
-declare spir_func i16 @_Z11atomic_loadPU3AS1VU7_Atomics(ptr addrspace(1))
-declare spir_func void @_Z12atomic_storePU3AS1VU7_Atomicss(ptr addrspace(1), i16)
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/load-atomic.ll b/llvm/test/CodeGen/SPIRV/transcoding/load-atomic.ll
index d04e17ae79635..29cba25cc6cb4 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/load-atomic.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/load-atomic.ll
@@ -101,8 +101,7 @@ define i32 @load_i32_acquire_device(ptr addrspace(1) %ptr) {
define float @load_float_acquire(ptr addrspace(1) %ptr) {
; CHECK-LABEL: OpFunction %[[#]]
; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#]]
-; CHECK: %[[#load:]] = OpAtomicLoad %[[#Int32]] %[[#ptr]] %[[#Const0]] %[[#Const514]]
-; CHECK: %[[#val:]] = OpBitcast %[[#Float]] %[[#load]]
+; CHECK: %[[#val:]] = OpAtomicLoad %[[#Float]] %[[#ptr]] %[[#Const0]] %[[#Const514]]
; CHECK: OpReturnValue %[[#val]]
%val = load atomic float, ptr addrspace(1) %ptr acquire, align 8
ret float %val
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/store-atomic.ll b/llvm/test/CodeGen/SPIRV/transcoding/store-atomic.ll
index 2830b212bd089..5e81f207e09f5 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/store-atomic.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/store-atomic.ll
@@ -110,8 +110,7 @@ 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: OpAtomicStore %[[#ptr]] %[[#Const0]] %[[#Const516]] %[[#cast]]
+; CHECK: OpAtomicStore %[[#ptr]] %[[#Const0]] %[[#Const516]] %[[#val]]
; CHECK: OpReturn
store atomic float %val, ptr addrspace(1) %ptr release, align 8
ret void
More information about the llvm-commits
mailing list