[llvm] [SPIRV] Let atomic store store pointers (PR #201251)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 3 17:54:49 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-spir-v
Author: fineg74
<details>
<summary>Changes</summary>
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/201251.diff
6 Files Affected:
- (modified) llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (+48-10)
- (modified) llvm/lib/Target/SPIRV/SPIRVTypeInst.cpp (+4)
- (modified) llvm/lib/Target/SPIRV/SPIRVTypeInst.h (+2)
- (modified) llvm/test/CodeGen/SPIRV/transcoding/atomic-load-store-unsupported.ll (+1-1)
- (added) llvm/test/CodeGen/SPIRV/transcoding/store-atomic-ptr-64.ll (+23)
- (added) llvm/test/CodeGen/SPIRV/transcoding/store-atomic-ptr.ll (+23)
``````````diff
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index c575932cd8709..a791e92517ece 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -2051,10 +2051,10 @@ 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");
+ if (!PointeeType.isTypeIntOrFloat() && !PointeeType.isTypePtr())
+ return diagnoseUnsupported(
+ I, "Lowering to SPIR-V of atomic store is only "
+ "allowed for integer, floating point or pointer types");
assert(I.getNumMemOperands());
const MachineMemOperand &MemOp = **I.memoperands_begin();
@@ -2073,12 +2073,50 @@ bool SPIRVInstructionSelector::selectAtomicStore(MachineInstr &I) const {
Register MemSemReg = buildI32Constant(MemSem | StorageClass, I);
MachineIRBuilder MIRBuilder(I);
- auto AtomicStore = MIRBuilder.buildInstr(SPIRV::OpAtomicStore)
- .addUse(Ptr)
- .addUse(ScopeReg)
- .addUse(MemSemReg)
- .addUse(StoreVal);
- AtomicStore.constrainAllUses(TII, TRI, RBI);
+
+ if (PointeeType.isTypePtr()) {
+ auto PtrSize = GR.getPointerSize();
+ SPIRVTypeInst SpirvType =
+ GR.getOrCreateSPIRVIntegerType(PtrSize, MIRBuilder);
+
+ Register NewVRegVal =
+ MRI->createGenericVirtualRegister(LLT::scalar(PtrSize));
+ MRI->setRegClass(NewVRegVal, MRI->getRegClassOrNull(StoreVal));
+ GR.assignSPIRVTypeToVReg(SpirvType, NewVRegVal, MIRBuilder.getMF());
+ MIRBuilder.buildInstr(SPIRV::OpConvertPtrToU)
+ .addDef(NewVRegVal)
+ .addUse(GR.getSPIRVTypeID(SpirvType)) // Result type
+ .addUse(StoreVal) // Pointer operand
+ .constrainAllUses(TII, TRI, RBI);
+
+ Register NewVRegPtr =
+ MRI->createGenericVirtualRegister(LLT::scalar(PtrSize));
+ MRI->setRegClass(NewVRegPtr, MRI->getRegClassOrNull(Ptr));
+ SPIRVTypeInst PtrType = GR.getOrCreateSPIRVPointerType(
+ SpirvType, MIRBuilder,
+ addressSpaceToStorageClass(MemOp.getAddrSpace(), STI));
+ GR.assignSPIRVTypeToVReg(PtrType, NewVRegPtr, MIRBuilder.getMF());
+
+ MIRBuilder.buildInstr(SPIRV::OpBitcast)
+ .addDef(NewVRegPtr)
+ .addUse(GR.getSPIRVTypeID(PtrType))
+ .addUse(Ptr)
+ .constrainAllUses(TII, TRI, RBI);
+
+ MIRBuilder.buildInstr(SPIRV::OpAtomicStore)
+ .addUse(NewVRegPtr)
+ .addUse(ScopeReg)
+ .addUse(MemSemReg)
+ .addUse(NewVRegVal)
+ .constrainAllUses(TII, TRI, RBI);
+ } else {
+ 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 39648ef622d3e..0d371f441cf9e 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..18848af7cd995 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/atomic-load-store-unsupported.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/atomic-load-store-unsupported.ll
@@ -7,7 +7,7 @@
; RUN: not llc -O0 -mtriple=spirv64-- %t/store-vector.ll -o /dev/null 2>&1 | FileCheck --check-prefix=FAIL-STORE-VEC %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-VEC: error:{{.*}}atomic store is only allowed for integer, floating point or pointer types
;--- load-vector.ll
define <2 x i32> @load_vector_acquire(ptr addrspace(1) %ptr) {
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/store-atomic-ptr-64.ll b/llvm/test/CodeGen/SPIRV/transcoding/store-atomic-ptr-64.ll
new file mode 100644
index 0000000000000..ff3b3100fd501
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/transcoding/store-atomic-ptr-64.ll
@@ -0,0 +1,23 @@
+; RUN: llc -O0 -mtriple=spirv64-- %s -o - | FileCheck %s
+; 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
+
+; CHECK-DAG: %[[#Int64:]] = OpTypeInt 64 0
+; CHECK-DAG: %[[#Int8:]] = OpTypeInt 8 0
+; CHECK-DAG: %[[#Int64Ptr:]] = OpTypePointer Generic %[[#Int64]]
+; CHECK-DAG: %[[#Int8Ptr:]] = OpTypePointer Generic %[[#Int8]]
+; CHECK-DAG: %[[#PtrInt8Ptr:]] = OpTypePointer Generic %[[#Int8Ptr]]
+
+define void @store_ptr(ptr addrspace(4) %ptr, ptr addrspace(4) %val) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#PtrInt8Ptr]]
+; CHECK: %[[#val:]] = OpFunctionParameter %[[#Int8Ptr]]
+; CHECK: %[[#convertVal:]] = OpConvertPtrToU %[[#Int64:]] %[[#val:]]
+; CHECK: %[[#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
+}
\ No newline at end of file
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..f940553b33128
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/transcoding/store-atomic-ptr.ll
@@ -0,0 +1,23 @@
+; RUN: llc -O0 -mtriple=spirv32-- %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-- %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
+
+; CHECK-DAG: %[[#Int32:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#Int8:]] = OpTypeInt 8 0
+; CHECK-DAG: %[[#Int32Ptr:]] = OpTypePointer Generic %[[#Int32]]
+; CHECK-DAG: %[[#Int8Ptr:]] = OpTypePointer Generic %[[#Int8]]
+; CHECK-DAG: %[[#PtrInt8Ptr:]] = OpTypePointer Generic %[[#Int8Ptr]]
+
+define void @store_ptr(ptr addrspace(4) %ptr, ptr addrspace(4) %val) {
+; CHECK-LABEL: OpFunction %[[#]]
+; CHECK: %[[#ptr:]] = OpFunctionParameter %[[#PtrInt8Ptr]]
+; CHECK: %[[#val:]] = OpFunctionParameter %[[#Int8Ptr]]
+; CHECK: %[[#convertVal:]] = OpConvertPtrToU %[[#Int32:]] %[[#val:]]
+; CHECK: %[[#convertPtr:]] = OpBitcast %[[#Int32Ptr:]] %[[#ptr:]]
+; CHECK: OpAtomicStore %[[#convertPtr]] %[[#]] %[[#]] %[[#convertVal]]
+; CHECK: OpReturn
+ store atomic ptr addrspace(4) %val, ptr addrspace(4) %ptr monotonic, align 8
+ ret void
+}
\ No newline at end of file
``````````
</details>
https://github.com/llvm/llvm-project/pull/201251
More information about the llvm-commits
mailing list