[llvm] 5fd8036 - [SPIRV] Let atomic store store pointers (#201251)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 9 10:52:01 PDT 2026
Author: fineg74
Date: 2026-06-09T17:51:56Z
New Revision: 5fd8036c0cd6eeab4cbc1dea1ca8569c082e874c
URL: https://github.com/llvm/llvm-project/commit/5fd8036c0cd6eeab4cbc1dea1ca8569c082e874c
DIFF: https://github.com/llvm/llvm-project/commit/5fd8036c0cd6eeab4cbc1dea1ca8569c082e874c.diff
LOG: [SPIRV] Let atomic store store pointers (#201251)
SPIRV atomic store permits only integer or floats as per SPIRV spec.
When compiling libc there several places in the code where pointers are
atomically stored 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
parameters to integers of appropriate size and generate atomic store
instruction that uses integers per SPIRV spec.
Added:
llvm/test/CodeGen/SPIRV/transcoding/store-atomic-ptr.ll
Modified:
llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
llvm/lib/Target/SPIRV/SPIRVTypeInst.cpp
llvm/lib/Target/SPIRV/SPIRVTypeInst.h
llvm/test/CodeGen/SPIRV/transcoding/atomic-load-store-unsupported.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index d9bbf6c9371df..34209bc44ba2a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -2061,10 +2061,6 @@ bool SPIRVInstructionSelector::selectAtomicStore(MachineInstr &I) const {
SPIRVTypeInst PtrType = GR.getSPIRVTypeForVReg(Ptr);
SPIRVTypeInst PointeeType = GR.getPointeeType(PtrType);
- if (!PointeeType.isTypeIntOrFloat())
- return diagnoseUnsupported(I,
- "Lowering to SPIR-V of atomic store is only "
- "allowed for integer or floating point types");
assert(I.getNumMemOperands());
const MachineMemOperand &MemOp = **I.memoperands_begin();
@@ -2081,14 +2077,63 @@ bool SPIRVInstructionSelector::selectAtomicStore(MachineInstr &I) const {
if (MemOp.isVolatile() && STI.getTargetTriple().isVulkanOS())
MemSem |= static_cast<uint32_t>(SPIRV::MemorySemantics::Volatile);
Register MemSemReg = buildI32Constant(MemSem | StorageClass, I);
-
MachineIRBuilder MIRBuilder(I);
+
+ if (PointeeType.isTypePtr()) {
+ if (!STI.isPhysicalSPIRV())
+ return diagnoseUnsupported(
+ I, "Lowering to SPIR-V of atomic store is only "
+ "allowed for pointer types for physical addressing model");
+ // If data to store is a pointer type we cast it to an integer type of the
+ // same size as the pointer size using OpConvertPtrToU, bitcast Ptr
+ // parameter to pointer to integer type and then generate OpAtomicStore
+ // with casted values as required by spec.
+ unsigned PtrSize = GR.getPointerSize();
+ SPIRVTypeInst PtrAsIntSpirvType =
+ GR.getOrCreateSPIRVIntegerType(PtrSize, MIRBuilder);
+
+ Register PtrToUVal =
+ MRI->createGenericVirtualRegister(LLT::scalar(PtrSize));
+ MRI->setRegClass(PtrToUVal, MRI->getRegClassOrNull(StoreVal));
+ GR.assignSPIRVTypeToVReg(PtrAsIntSpirvType, PtrToUVal, MIRBuilder.getMF());
+ MIRBuilder.buildInstr(SPIRV::OpConvertPtrToU)
+ .addDef(PtrToUVal)
+ .addUse(GR.getSPIRVTypeID(PtrAsIntSpirvType)) // Result type
+ .addUse(StoreVal) // Pointer operand
+ .constrainAllUses(TII, TRI, RBI);
+
+ 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);
+
+ StoreVal = PtrToUVal;
+ Ptr = PtrCastedToMatchValReg;
+ PointeeType = PtrAsIntSpirvType;
+ }
+
+ if (!PointeeType.isTypeIntOrFloat())
+ return diagnoseUnsupported(I,
+ "Lowering to SPIR-V of atomic store is only "
+ "allowed for integer or floating point types");
+
auto AtomicStore = MIRBuilder.buildInstr(SPIRV::OpAtomicStore)
.addUse(Ptr)
.addUse(ScopeReg)
.addUse(MemSemReg)
.addUse(StoreVal);
AtomicStore.constrainAllUses(TII, TRI, RBI);
+
return true;
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVTypeInst.cpp b/llvm/lib/Target/SPIRV/SPIRVTypeInst.cpp
index 7a7d62f9297f5..58857b6a3eac2 100644
--- a/llvm/lib/Target/SPIRV/SPIRVTypeInst.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVTypeInst.cpp
@@ -38,4 +38,8 @@ bool SPIRVTypeInst::isTypeIntN(unsigned N) const {
bool SPIRVTypeInst::isAnyTypeFloat() const {
return MI->getOpcode() == SPIRV::OpTypeFloat;
}
+
+bool SPIRVTypeInst::isTypePtr() const {
+ return MI->getOpcode() == SPIRV::OpTypePointer;
+}
} // namespace llvm
diff --git a/llvm/lib/Target/SPIRV/SPIRVTypeInst.h b/llvm/lib/Target/SPIRV/SPIRVTypeInst.h
index 6e6f971a37549..2c7e21375f326 100644
--- a/llvm/lib/Target/SPIRV/SPIRVTypeInst.h
+++ b/llvm/lib/Target/SPIRV/SPIRVTypeInst.h
@@ -55,6 +55,8 @@ class SPIRVTypeInst {
bool isAnyTypeFloat() const;
// Returns true if this is an OpTypeInt or OpTypeFloat instruction.
bool isTypeIntOrFloat() const { return isTypeIntN() || isAnyTypeFloat(); }
+ // Returns true if this is an OpTypePointer instruction.
+ bool isTypePtr() const;
friend struct DenseMapInfo<SPIRVTypeInst>;
};
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 b6c055ff3b7de..b5ed65c829f7b 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/atomic-load-store-unsupported.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/atomic-load-store-unsupported.ll
@@ -6,8 +6,11 @@
; RUN: not llc -O0 -mtriple=spirv64-- %t/store-vector.ll -o /dev/null 2>&1 | FileCheck --check-prefix=FAIL-STORE-VEC %s
+; RUN: not llc -O0 -mtriple=spirv %t/store-ptr-vulkan.ll -o /dev/null 2>&1 | FileCheck --check-prefix=FAIL-STORE-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
;--- load-vector.ll
define <2 x i32> @load_vector_acquire(ptr addrspace(1) %ptr) {
@@ -20,3 +23,9 @@ define void @store_vector_release(ptr addrspace(1) %ptr, <2 x i32> %val) {
store atomic <2 x i32> %val, ptr addrspace(1) %ptr release, align 8
ret void
}
+
+;--- store-ptr-vulkan.ll
+define void @store_vector_release(ptr addrspace(1) %ptr, ptr addrspace(1) %val) {
+ store atomic ptr addrspace(1) %val, ptr addrspace(1) %ptr monotonic, align 8
+ ret void
+}
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/store-atomic-ptr.ll b/llvm/test/CodeGen/SPIRV/transcoding/store-atomic-ptr.ll
new file mode 100644
index 0000000000000..223b59da2797f
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/transcoding/store-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 'store atomic' LLVM IR instructions are lowered correctly to
+; OpAtomicStore 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 void @store_ptr(ptr addrspace(4) %ptr, ptr addrspace(4) %val) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#Ptr:]] = OpFunctionParameter %[[#PtrInt8Ptr]]
+; CHECK: %[[#Val:]] = OpFunctionParameter %[[#Int8Ptr]]
+; SPIRV32: %[[#ConvertVal:]] = OpConvertPtrToU %[[#Int32]] %[[#Val]]
+; SPIRV32: %[[#ConvertPtr:]] = OpBitcast %[[#Int32Ptr]] %[[#Ptr]]
+; SPIRV64: %[[#ConvertVal:]] = OpConvertPtrToU %[[#Int64]] %[[#Val]]
+; SPIRV64: %[[#ConvertPtr:]] = OpBitcast %[[#Int64Ptr]] %[[#Ptr]]
+; CHECK: OpAtomicStore %[[#ConvertPtr]] %[[#]] %[[#]] %[[#ConvertVal]]
+; CHECK: OpReturn
+ store atomic ptr addrspace(4) %val, ptr addrspace(4) %ptr monotonic, align 8
+ ret void
+}
More information about the llvm-commits
mailing list