[clang][SPIR][SPIRV] Materialize non-generic null pointers via addrspacecast (#161773)

LLVM models ConstantPointerNull as all-zero, but some GPUs (e.g. AMDGPU
and our downstream GPU target) use a non-zero sentinel for null in
private / local address spaces.
SPIR-V is a supported input for our GPU target. This PR preserves a
canonical zero form in the generic AS while allowing later lowering to
substitute the target’s real sentinel.
This commit is contained in:
Wenju He
2025-10-09 09:10:24 +08:00
committed by GitHub
parent a4a98033c3
commit 1ffff05a38
3 changed files with 31 additions and 5 deletions

View File

@@ -61,6 +61,9 @@ public:
QualType SampledType, CodeGenModule &CGM) const;
void
setOCLKernelStubCallingConvention(const FunctionType *&FT) const override;
llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,
llvm::PointerType *T,
QualType QT) const override;
};
class SPIRVTargetCodeGenInfo : public CommonSPIRTargetCodeGenInfo {
public:
@@ -240,6 +243,29 @@ void CommonSPIRTargetCodeGenInfo::setOCLKernelStubCallingConvention(
FT, FT->getExtInfo().withCallingConv(CC_SpirFunction));
}
// LLVM currently assumes a null pointer has the bit pattern 0, but some GPU
// targets use a non-zero encoding for null in certain address spaces.
// Because SPIR(-V) is a generic target and the bit pattern of null in
// non-generic AS is unspecified, materialize null in non-generic AS via an
// addrspacecast from null in generic AS. This allows later lowering to
// substitute the target's real sentinel value.
llvm::Constant *
CommonSPIRTargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM,
llvm::PointerType *PT,
QualType QT) const {
LangAS AS = QT->getUnqualifiedDesugaredType()->isNullPtrType()
? LangAS::Default
: QT->getPointeeType().getAddressSpace();
if (AS == LangAS::Default || AS == LangAS::opencl_generic)
return llvm::ConstantPointerNull::get(PT);
auto &Ctx = CGM.getContext();
auto NPT = llvm::PointerType::get(
PT->getContext(), Ctx.getTargetAddressSpace(LangAS::opencl_generic));
return llvm::ConstantExpr::getAddrSpaceCast(
llvm::ConstantPointerNull::get(NPT), PT);
}
LangAS
SPIRVTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
const VarDecl *D) const {

View File

@@ -62,19 +62,19 @@ void testBranchingOnAddressSpaceCast(generic long* ptr) {
if (to_global(ptr))
(void)0;
// CHECK: [[P:%[0-9]+]] = call spir_func [[GLOBAL_VOID:ptr addrspace\(1\)]] @__to_global([[GENERIC_VOID:ptr addrspace\(4\)]] {{%[0-9]+}})
// CHECK-NEXT: [[BOOL:%[a-z0-9]+]] = icmp ne ptr addrspace(1) [[P]], null
// CHECK-NEXT: [[BOOL:%[a-z0-9]+]] = icmp ne ptr addrspace(1) [[P]], addrspacecast (ptr addrspace(4) null to ptr addrspace(1))
// CHECK-NEXT: br i1 [[BOOL]]
if (to_local(ptr))
(void)0;
// CHECK: [[P:%[0-9]+]] = call spir_func [[LOCAL_VOID:ptr addrspace\(3\)]] @__to_local([[GENERIC_VOID]] {{%[0-9]+}})
// CHECK-NEXT: [[BOOL:%[a-z0-9]+]] = icmp ne ptr addrspace(3) [[P]], null
// CHECK-NEXT: [[BOOL:%[a-z0-9]+]] = icmp ne ptr addrspace(3) [[P]], addrspacecast (ptr addrspace(4) null to ptr addrspace(3))
// CHECK-NEXT: br i1 [[BOOL]]
if (to_private(ptr))
(void)0;
// CHECK: [[P:%[0-9]+]] = call spir_func [[PRIVATE_VOID:ptr]] @__to_private([[GENERIC_VOID]] {{%[0-9]+}})
// CHECK-NEXT: [[BOOL:%[a-z0-9]+]] = icmp ne ptr [[P]], null
// CHECK-NEXT: [[BOOL:%[a-z0-9]+]] = icmp ne ptr [[P]], addrspacecast (ptr addrspace(4) null to ptr)
// CHECK-NEXT: br i1 [[BOOL]]
}

View File

@@ -35,9 +35,9 @@ void tmpl(T t) {}
// CHECK-DAG: [[LOC]].ascast = addrspacecast ptr [[LOC]] to ptr addrspace(4)
// CHECK-DAG: [[PRIV]].ascast = addrspacecast ptr [[PRIV]] to ptr addrspace(4)
LOC = nullptr;
// CHECK-DAG: store ptr addrspace(3) null, ptr addrspace(4) [[LOC]].ascast, align 8
// CHECK-DAG: store ptr addrspace(3) addrspacecast (ptr addrspace(4) null to ptr addrspace(3)), ptr addrspace(4) [[LOC]].ascast, align 8
GLOB = nullptr;
// CHECK-DAG: store ptr addrspace(1) null, ptr addrspace(4) [[GLOB]].ascast, align 8
// CHECK-DAG: store ptr addrspace(1) addrspacecast (ptr addrspace(4) null to ptr addrspace(1)), ptr addrspace(4) [[GLOB]].ascast, align 8
// Explicit conversions
// From named address spaces to default address space