[llvm] [SPIRV] Let atomic load load pointers (PR #202823)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 9 17:49:53 PDT 2026
https://github.com/fineg74 created https://github.com/llvm/llvm-project/pull/202823
SPIRV atomic load permits only integer or floats as per SPIRV spec. When compiling libc there several places in the code where pointers are atomically loaded causing compilation to break. It can be fixed by using casting in the libc code but in order to keep the libc code clean it is preferrable to do it in SPIRV backend. This change will cast pointer parameter to a pointer to integer of appropriate size and generate atomic load instruction that uses integers per SPIRV spec. The value returned by atomic load is casted to an original pointer type
>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] 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
+}
More information about the llvm-commits
mailing list