[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