[llvm] [SPIRV] Let atomic load load pointers (PR #202823)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 10 14:52:39 PDT 2026
https://github.com/fineg74 updated https://github.com/llvm/llvm-project/pull/202823
>From 0248f1b829cdaa21de33da2bf9c25aac7fd6305c Mon Sep 17 00:00:00 2001
From: "Fine, Gregory" <gregory.fine at intel.com>
Date: Tue, 9 Jun 2026 17:45:04 -0700
Subject: [PATCH 1/5] Let atomic load load pointers
---
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 72 ++++++++++++++++---
.../atomic-load-store-unsupported.ll | 11 ++-
.../SPIRV/transcoding/load-atomic-ptr.ll | 31 ++++++++
3 files changed, 102 insertions(+), 12 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/transcoding/load-atomic-ptr.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 34209bc44ba2a..19502bca35241 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -1963,10 +1963,10 @@ bool SPIRVInstructionSelector::selectAtomicLoad(Register ResVReg,
unsigned OpOffset = isa<GIntrinsic>(I) ? 1 : 0;
Register Ptr = I.getOperand(1 + OpOffset).getReg();
- if (!ResType.isTypeIntOrFloat())
- return diagnoseUnsupported(I,
- "Lowering to SPIR-V of atomic load is only "
- "allowed for integer or floating point types");
+ if (!ResType.isTypeIntOrFloat() && !ResType.isTypePtr())
+ return diagnoseUnsupported(
+ I, "Lowering to SPIR-V of atomic load is only "
+ "allowed for integer, floating point or pointer types");
assert(I.getNumMemOperands());
const MachineMemOperand &MemOp = **I.memoperands_begin();
@@ -1985,13 +1985,63 @@ bool SPIRVInstructionSelector::selectAtomicLoad(Register ResVReg,
Register MemSemReg = buildI32Constant(MemSem | StorageClass, I);
MachineIRBuilder MIRBuilder(I);
- auto AtomicLoad = MIRBuilder.buildInstr(SPIRV::OpAtomicLoad)
- .addDef(ResVReg)
- .addUse(GR.getSPIRVTypeID(ResType))
- .addUse(Ptr)
- .addUse(ScopeReg)
- .addUse(MemSemReg);
- AtomicLoad.constrainAllUses(TII, TRI, RBI);
+
+ if (ResType.isTypePtr()) {
+ if (!STI.isPhysicalSPIRV())
+ return diagnoseUnsupported(
+ I, "Lowering to SPIR-V of atomic load is only "
+ "allowed for pointer types for physical addressing model");
+ // If data to load is a pointer type we bitcast the Ptr parameter to pointer
+ // to an integer type of the same size as the pointer size and then generate
+ // OpAtomicLoad the return value of that OpAtomicLoad is an integet that is
+ // converted back to a pointer type using OpConvertUToPtr.
+
+ unsigned PtrSize = GR.getPointerSize();
+ SPIRVTypeInst PtrAsIntSpirvType =
+ GR.getOrCreateSPIRVIntegerType(PtrSize, MIRBuilder);
+ Register PtrToUVal =
+ MRI->createGenericVirtualRegister(LLT::scalar(PtrSize));
+ MRI->setRegClass(PtrToUVal, MRI->getRegClassOrNull(ResVReg));
+ GR.assignSPIRVTypeToVReg(PtrAsIntSpirvType, PtrToUVal, MIRBuilder.getMF());
+
+ Register PtrCastedToMatchValReg =
+ MRI->createGenericVirtualRegister(LLT::scalar(PtrSize));
+ MRI->setRegClass(PtrCastedToMatchValReg, MRI->getRegClassOrNull(Ptr));
+ SPIRVTypeInst PtrType = GR.getOrCreateSPIRVPointerType(
+ PtrAsIntSpirvType, MIRBuilder,
+ addressSpaceToStorageClass(MemOp.getAddrSpace(), STI));
+ GR.assignSPIRVTypeToVReg(PtrType, PtrCastedToMatchValReg,
+ MIRBuilder.getMF());
+
+ MIRBuilder.buildInstr(SPIRV::OpBitcast)
+ .addDef(PtrCastedToMatchValReg)
+ .addUse(GR.getSPIRVTypeID(PtrType))
+ .addUse(Ptr)
+ .constrainAllUses(TII, TRI, RBI);
+ ResType = PtrType;
+ Ptr = PtrCastedToMatchValReg;
+
+ MIRBuilder.buildInstr(SPIRV::OpAtomicLoad)
+ .addDef(PtrToUVal)
+ .addUse(GR.getSPIRVTypeID(PtrType))
+ .addUse(PtrCastedToMatchValReg)
+ .addUse(ScopeReg)
+ .addUse(MemSemReg)
+ .constrainAllUses(TII, TRI, RBI);
+ MIRBuilder.buildInstr(SPIRV::OpConvertUToPtr)
+ .addDef(ResVReg)
+ .addUse(GR.getSPIRVTypeID(ResType))
+ .addUse(PtrToUVal)
+ .constrainAllUses(TII, TRI, RBI);
+ } else {
+ auto AtomicLoad = MIRBuilder.buildInstr(SPIRV::OpAtomicLoad)
+ .addDef(ResVReg)
+ .addUse(GR.getSPIRVTypeID(ResType))
+ .addUse(Ptr)
+ .addUse(ScopeReg)
+ .addUse(MemSemReg);
+ AtomicLoad.constrainAllUses(TII, TRI, RBI);
+ }
return true;
}
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/atomic-load-store-unsupported.ll b/llvm/test/CodeGen/SPIRV/transcoding/atomic-load-store-unsupported.ll
index b5ed65c829f7b..37c68ce3108ec 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/atomic-load-store-unsupported.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/atomic-load-store-unsupported.ll
@@ -8,9 +8,12 @@
; RUN: not llc -O0 -mtriple=spirv %t/store-ptr-vulkan.ll -o /dev/null 2>&1 | FileCheck --check-prefix=FAIL-STORE-PTR %s
+; RUN: not llc -O0 -mtriple=spirv %t/load-ptr-vulkan.ll -o /dev/null 2>&1 | FileCheck --check-prefix=FAIL-LOAD-PTR %s
+
; FAIL-LOAD-VEC: error:{{.*}}atomic load is only allowed for integer or floating point types
; FAIL-STORE-VEC: error:{{.*}}atomic store is only allowed for integer or floating point types
; FAIL-STORE-PTR: error:{{.*}}atomic store is only allowed for pointer types for physical addressing model
+; FAIL-LOAD-PTR: error:{{.*}}atomic load is only allowed for pointer types for physical addressing model
;--- load-vector.ll
define <2 x i32> @load_vector_acquire(ptr addrspace(1) %ptr) {
@@ -25,7 +28,13 @@ define void @store_vector_release(ptr addrspace(1) %ptr, <2 x i32> %val) {
}
;--- store-ptr-vulkan.ll
-define void @store_vector_release(ptr addrspace(1) %ptr, ptr addrspace(1) %val) {
+define void @store_ptr_release(ptr addrspace(1) %ptr, ptr addrspace(1) %val) {
store atomic ptr addrspace(1) %val, ptr addrspace(1) %ptr monotonic, align 8
ret void
}
+
+;--- load-ptr-vulkan.ll
+define ptr addrspace(1) @load_ptr_release(ptr addrspace(1) %ptr) {
+ %val = load atomic ptr addrspace(1), ptr addrspace(1) %ptr monotonic, align 8
+ ret ptr addrspace(1) %val
+}
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/load-atomic-ptr.ll b/llvm/test/CodeGen/SPIRV/transcoding/load-atomic-ptr.ll
new file mode 100644
index 0000000000000..a17ee0023f2e0
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/transcoding/load-atomic-ptr.ll
@@ -0,0 +1,31 @@
+; RUN: llc -O0 -mtriple=spirv32 %s -o - | FileCheck %s --check-prefixes=CHECK,SPIRV32
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-- %s -o - -filetype=obj | spirv-val %}
+
+; RUN: llc -O0 -mtriple=spirv64 %s -o - | FileCheck %s --check-prefixes=CHECK,SPIRV64
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-- %s -o - -filetype=obj | spirv-val %}
+
+
+; Check that 'load atomic' LLVM IR instructions are lowered correctly to
+; OpAtomicLoad when a pointer is passed as value.
+
+; SPIRV32-DAG: %[[#Int32:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#Int8:]] = OpTypeInt 8 0
+; SPIRV32-DAG: %[[#Int32Ptr:]] = OpTypePointer Generic %[[#Int32]]
+; CHECK-DAG: %[[#Int8Ptr:]] = OpTypePointer Generic %[[#Int8]]
+; CHECK-DAG: %[[#PtrInt8Ptr:]] = OpTypePointer Generic %[[#Int8Ptr]]
+; SPIRV64-DAG: %[[#Int64:]] = OpTypeInt 64 0
+; SPIRV64-DAG: %[[#Int64Ptr:]] = OpTypePointer Generic %[[#Int64]]
+
+define ptr addrspace(4) @load_ptr(ptr addrspace(4) %ptr) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#Ptr:]] = OpFunctionParameter %[[#PtrInt8Ptr]]
+; SPIRV32: %[[#ConvertPtr:]] = OpBitcast %[[#Int32Ptr]] %[[#Ptr]]
+; SPIRV32: %[[#Val:]] = OpAtomicLoad %[[#Int32Ptr]] %[[#ConvertPtr]] %[[#]] %[[#]]
+; SPIRV32: %[[#ConvertVal:]] = OpConvertUToPtr %[[#Int32Ptr]] %[[#Val]]
+; SPIRV64: %[[#ConvertPtr:]] = OpBitcast %[[#Int64Ptr]] %[[#Ptr]]
+; SPIRV64: %[[#Val:]] = OpAtomicLoad %[[#Int64Ptr]] %[[#ConvertPtr]] %[[#]] %[[#]]
+; SPIRV64: %[[#ConvertVal:]] = OpConvertUToPtr %[[#Int64Ptr]] %[[#Val]]
+; CHECK: OpReturnValue %[[#ConvertVal]]
+ %val = load atomic ptr addrspace(4), ptr addrspace(4) %ptr monotonic, align 8
+ ret ptr addrspace(4) %val
+}
>From c04a5636a968ded2712de54df2974f718942e3ba Mon Sep 17 00:00:00 2001
From: "Fine, Gregory" <gregory.fine at intel.com>
Date: Tue, 9 Jun 2026 18:25:15 -0700
Subject: [PATCH 2/5] Fix a test break
---
.../CodeGen/SPIRV/transcoding/atomic-load-store-unsupported.ll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/atomic-load-store-unsupported.ll b/llvm/test/CodeGen/SPIRV/transcoding/atomic-load-store-unsupported.ll
index 37c68ce3108ec..67ec10e24c5e9 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/atomic-load-store-unsupported.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/atomic-load-store-unsupported.ll
@@ -10,7 +10,7 @@
; RUN: not llc -O0 -mtriple=spirv %t/load-ptr-vulkan.ll -o /dev/null 2>&1 | FileCheck --check-prefix=FAIL-LOAD-PTR %s
-; FAIL-LOAD-VEC: error:{{.*}}atomic load is only allowed for integer or floating point types
+; FAIL-LOAD-VEC: error:{{.*}}atomic load is only allowed for integer, floating point or pointer types
; FAIL-STORE-VEC: error:{{.*}}atomic store is only allowed for integer or floating point types
; FAIL-STORE-PTR: error:{{.*}}atomic store is only allowed for pointer types for physical addressing model
; FAIL-LOAD-PTR: error:{{.*}}atomic load is only allowed for pointer types for physical addressing model
>From f9cfb5932d20ba017672bb7b99287469fe70e3c6 Mon Sep 17 00:00:00 2001
From: "Fine, Gregory" <gregory.fine at intel.com>
Date: Tue, 9 Jun 2026 19:18:54 -0700
Subject: [PATCH 3/5] Fix a test break
---
llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp | 4 +---
llvm/test/CodeGen/SPIRV/transcoding/load-atomic-ptr.ll | 7 +++----
2 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 19502bca35241..c5e40d314838a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -2018,12 +2018,10 @@ bool SPIRVInstructionSelector::selectAtomicLoad(Register ResVReg,
.addUse(GR.getSPIRVTypeID(PtrType))
.addUse(Ptr)
.constrainAllUses(TII, TRI, RBI);
- ResType = PtrType;
- Ptr = PtrCastedToMatchValReg;
MIRBuilder.buildInstr(SPIRV::OpAtomicLoad)
.addDef(PtrToUVal)
- .addUse(GR.getSPIRVTypeID(PtrType))
+ .addUse(GR.getSPIRVTypeID(PtrAsIntSpirvType))
.addUse(PtrCastedToMatchValReg)
.addUse(ScopeReg)
.addUse(MemSemReg)
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/load-atomic-ptr.ll b/llvm/test/CodeGen/SPIRV/transcoding/load-atomic-ptr.ll
index a17ee0023f2e0..070dc7f1c4b7c 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/load-atomic-ptr.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/load-atomic-ptr.ll
@@ -20,11 +20,10 @@ define ptr addrspace(4) @load_ptr(ptr addrspace(4) %ptr) {
; CHECK-LABEL: OpFunction %[[#]]
; CHECK: %[[#Ptr:]] = OpFunctionParameter %[[#PtrInt8Ptr]]
; SPIRV32: %[[#ConvertPtr:]] = OpBitcast %[[#Int32Ptr]] %[[#Ptr]]
-; SPIRV32: %[[#Val:]] = OpAtomicLoad %[[#Int32Ptr]] %[[#ConvertPtr]] %[[#]] %[[#]]
-; SPIRV32: %[[#ConvertVal:]] = OpConvertUToPtr %[[#Int32Ptr]] %[[#Val]]
+; SPIRV32: %[[#Val:]] = OpAtomicLoad %[[#Int32]] %[[#ConvertPtr]] %[[#]] %[[#]]
; SPIRV64: %[[#ConvertPtr:]] = OpBitcast %[[#Int64Ptr]] %[[#Ptr]]
-; SPIRV64: %[[#Val:]] = OpAtomicLoad %[[#Int64Ptr]] %[[#ConvertPtr]] %[[#]] %[[#]]
-; SPIRV64: %[[#ConvertVal:]] = OpConvertUToPtr %[[#Int64Ptr]] %[[#Val]]
+; SPIRV64: %[[#Val:]] = OpAtomicLoad %[[#Int64]] %[[#ConvertPtr]] %[[#]] %[[#]]
+; CHECK: %[[#ConvertVal:]] = OpConvertUToPtr %[[#Int8Ptr]] %[[#Val]]
; CHECK: OpReturnValue %[[#ConvertVal]]
%val = load atomic ptr addrspace(4), ptr addrspace(4) %ptr monotonic, align 8
ret ptr addrspace(4) %val
>From ea511032d801544aac99fcb1395b88d0b0344787 Mon Sep 17 00:00:00 2001
From: "Fine, Gregory" <gregory.fine at intel.com>
Date: Wed, 10 Jun 2026 09:47:57 -0700
Subject: [PATCH 4/5] Address PR comments
---
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 21 ++++++++++---------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index c5e40d314838a..08f948b56f998 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -2001,7 +2001,7 @@ bool SPIRVInstructionSelector::selectAtomicLoad(Register ResVReg,
GR.getOrCreateSPIRVIntegerType(PtrSize, MIRBuilder);
Register PtrToUVal =
MRI->createGenericVirtualRegister(LLT::scalar(PtrSize));
- MRI->setRegClass(PtrToUVal, MRI->getRegClassOrNull(ResVReg));
+ MRI->setRegClass(PtrToUVal, GR.getRegClass(PtrAsIntSpirvType));
GR.assignSPIRVTypeToVReg(PtrAsIntSpirvType, PtrToUVal, MIRBuilder.getMF());
Register PtrCastedToMatchValReg =
@@ -2031,15 +2031,16 @@ bool SPIRVInstructionSelector::selectAtomicLoad(Register ResVReg,
.addUse(GR.getSPIRVTypeID(ResType))
.addUse(PtrToUVal)
.constrainAllUses(TII, TRI, RBI);
- } else {
- auto AtomicLoad = MIRBuilder.buildInstr(SPIRV::OpAtomicLoad)
- .addDef(ResVReg)
- .addUse(GR.getSPIRVTypeID(ResType))
- .addUse(Ptr)
- .addUse(ScopeReg)
- .addUse(MemSemReg);
- AtomicLoad.constrainAllUses(TII, TRI, RBI);
+ return true;
}
+ auto AtomicLoad = MIRBuilder.buildInstr(SPIRV::OpAtomicLoad)
+ .addDef(ResVReg)
+ .addUse(GR.getSPIRVTypeID(ResType))
+ .addUse(Ptr)
+ .addUse(ScopeReg)
+ .addUse(MemSemReg);
+ AtomicLoad.constrainAllUses(TII, TRI, RBI);
+
return true;
}
@@ -2142,7 +2143,7 @@ bool SPIRVInstructionSelector::selectAtomicStore(MachineInstr &I) const {
Register PtrToUVal =
MRI->createGenericVirtualRegister(LLT::scalar(PtrSize));
- MRI->setRegClass(PtrToUVal, MRI->getRegClassOrNull(StoreVal));
+ MRI->setRegClass(PtrToUVal, GR.getRegClass(PtrAsIntSpirvType));
GR.assignSPIRVTypeToVReg(PtrAsIntSpirvType, PtrToUVal, MIRBuilder.getMF());
MIRBuilder.buildInstr(SPIRV::OpConvertPtrToU)
.addDef(PtrToUVal)
>From 15086b2b9603e4111716256a856ff4dafb773640 Mon Sep 17 00:00:00 2001
From: fineg74 <61437305+fineg74 at users.noreply.github.com>
Date: Wed, 10 Jun 2026 14:52:29 -0700
Subject: [PATCH 5/5] Update
llvm/test/CodeGen/SPIRV/transcoding/load-atomic-ptr.ll
Co-authored-by: Dmitry Sidorov <dsidorov at amd.com>
---
llvm/test/CodeGen/SPIRV/transcoding/load-atomic-ptr.ll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/load-atomic-ptr.ll b/llvm/test/CodeGen/SPIRV/transcoding/load-atomic-ptr.ll
index 070dc7f1c4b7c..a5cab068932a4 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/load-atomic-ptr.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/load-atomic-ptr.ll
@@ -16,7 +16,7 @@
; SPIRV64-DAG: %[[#Int64:]] = OpTypeInt 64 0
; SPIRV64-DAG: %[[#Int64Ptr:]] = OpTypePointer Generic %[[#Int64]]
-define ptr addrspace(4) @load_ptr(ptr addrspace(4) %ptr) {
+define ptr addrspace(4) @load_ptr(ptr addrspace(4) %ptr) {
; CHECK-LABEL: OpFunction %[[#]]
; CHECK: %[[#Ptr:]] = OpFunctionParameter %[[#PtrInt8Ptr]]
; SPIRV32: %[[#ConvertPtr:]] = OpBitcast %[[#Int32Ptr]] %[[#Ptr]]
More information about the llvm-commits
mailing list