From 46125974edf4f29e6e7dd877b71f2661406f5764 Mon Sep 17 00:00:00 2001 From: Wenju He Date: Fri, 3 Oct 2025 06:20:44 +0200 Subject: [PATCH 1/2] [clang][SPIR][SPIRV] Materialize non-generic null pointers via addrspacecast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- clang/lib/CodeGen/Targets/SPIR.cpp | 24 +++++++++++++++++++ clang/test/CodeGenOpenCL/builtins.cl | 6 ++--- .../CodeGenSYCL/address-space-conversions.cpp | 4 ++-- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp index 4aa63143a66cd..b1c1d65b4f5e1 100644 --- a/clang/lib/CodeGen/Targets/SPIR.cpp +++ b/clang/lib/CodeGen/Targets/SPIR.cpp @@ -61,6 +61,9 @@ class CommonSPIRTargetCodeGenInfo : public TargetCodeGenInfo { 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,27 @@ 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 virtual target and the bit pattern of a non-generic +// null is unspecified, materialize non-generic null via an addrspacecast from +// the generic null. +// 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 { + auto &Ctx = CGM.getContext(); + if (PT->getAddressSpace() == + Ctx.getTargetAddressSpace(LangAS::opencl_generic)) + return llvm::ConstantPointerNull::get(PT); + + 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 { diff --git a/clang/test/CodeGenOpenCL/builtins.cl b/clang/test/CodeGenOpenCL/builtins.cl index aa666c7b671b9..708d1b84f4838 100644 --- a/clang/test/CodeGenOpenCL/builtins.cl +++ b/clang/test/CodeGenOpenCL/builtins.cl @@ -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]] } diff --git a/clang/test/CodeGenSYCL/address-space-conversions.cpp b/clang/test/CodeGenSYCL/address-space-conversions.cpp index fa7acb0d99433..ea52be53ea906 100644 --- a/clang/test/CodeGenSYCL/address-space-conversions.cpp +++ b/clang/test/CodeGenSYCL/address-space-conversions.cpp @@ -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 From 5c5e13ee5e95791c9795714fec01efbe92dbecd4 Mon Sep 17 00:00:00 2001 From: Wenju He Date: Fri, 3 Oct 2025 13:12:22 +0200 Subject: [PATCH 2/2] move getTargetNullPointerValue implementation into CommonSPIRTargetCodeGenInfo::getNullPointer --- clang/lib/CodeGen/Targets/SPIR.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp index b1c1d65b4f5e1..6974df200a6cf 100644 --- a/clang/lib/CodeGen/Targets/SPIR.cpp +++ b/clang/lib/CodeGen/Targets/SPIR.cpp @@ -253,11 +253,15 @@ llvm::Constant * CommonSPIRTargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM, llvm::PointerType *PT, QualType QT) const { - auto &Ctx = CGM.getContext(); - if (PT->getAddressSpace() == - Ctx.getTargetAddressSpace(LangAS::opencl_generic)) + LangAS AS; + if (QT->getUnqualifiedDesugaredType()->isNullPtrType()) + AS = LangAS::Default; + else + AS = 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(