Author: Konstantinos Parasyris Date: 2026-09-15T16:52:30-07:00 New Revision: 99f7a3ee4b76e0b77552f57a7cc9a4262ceddbd9
URL: https://github.com/llvm/llvm-project/commit/99f7a3ee4b76e0b77552f57a7cc9a4262ceddbd9 DIFF: https://github.com/llvm/llvm-project/commit/99f7a3ee4b76e0b77552f57a7cc9a4262ceddbd9.diff LOG: [CIR][SYCL] Emit generic address space for default pointers in device code (#223464) Added: clang/test/CIR/CodeGenSYCL/kernel-caller-address-space.cpp Modified: clang/lib/CIR/CodeGen/CIRGenModule.cpp clang/lib/CIR/CodeGen/CIRGenTypes.cpp clang/lib/CIR/CodeGen/CIRGenTypes.h Removed: ################################################################################ diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index bdc2707723283..3af6ce4ce6e94 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -2344,8 +2344,9 @@ LangAS CIRGenModule::getLangTempAllocaAddressSpace() const { if (getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice) assert(!cir::MissingFeatures::openMP()); + if (getLangOpts().SYCLIsDevice) - errorNYI("SYCL temp address space"); + return LangAS::Default; return LangAS::Default; } diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp index f2cb875e908a7..9e5b8bbb82cb1 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -544,7 +544,8 @@ mlir::Type CIRGenTypes::convertType(QualType type) { const ReferenceType *refTy = cast<ReferenceType>(ty); QualType elemTy = refTy->getPointeeType(); auto pointeeType = convertTypeForMem(elemTy); - resultType = builder.getPointerTo(pointeeType, elemTy.getAddressSpace()); + resultType = + builder.getPointerTo(pointeeType, getPointerAddressSpace(elemTy)); assert(resultType && "Cannot get pointer type?"); break; } @@ -556,7 +557,8 @@ mlir::Type CIRGenTypes::convertType(QualType type) { mlir::Type pointeeType = convertType(elemTy); - resultType = builder.getPointerTo(pointeeType, elemTy.getAddressSpace()); + resultType = + builder.getPointerTo(pointeeType, getPointerAddressSpace(elemTy)); break; } @@ -871,6 +873,23 @@ void CIRGenTypes::updateCompletedType(const TagDecl *td) { assert(!cir::MissingFeatures::generateDebugInfo()); } +mlir::ptr::MemorySpaceAttrInterface +CIRGenTypes::getPointerAddressSpace(clang::QualType pointeeTy) const { + // An explicit source address space is carried directly. + if (pointeeTy.getAddressSpace() != LangAS::Default) + return cir::toCIRAddressSpaceAttr(getMLIRContext(), + pointeeTy.getAddressSpace()); + + // Resolve a default-address-space pointee through getTargetAddressSpace, as + // classic CodeGen does. This is only non-zero for languages that default to + // a non-default address space (e.g. generic for SYCL device data), and uses + // the program address space for functions. + unsigned targetAS = getTargetAddressSpace(pointeeTy); + if (targetAS == 0) + return {}; + return cir::TargetAddressSpaceAttr::get(&getMLIRContext(), targetAS); +} + unsigned CIRGenTypes::getTargetAddressSpace(QualType ty) const { // Return the address space for the type. If the type is a // function type without an address space qualifier, the diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h b/clang/lib/CIR/CodeGen/CIRGenTypes.h index e2045f9e58d04..852e1f4ab6699 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.h +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h @@ -240,6 +240,14 @@ class CIRGenTypes { arrangeFreeFunctionType(CanQual<FunctionNoProtoType> fnpt); unsigned getTargetAddressSpace(QualType ty) const; + + /// Returns the CIR address space for a pointer/reference to \p pointeeTy, or + /// a null attribute for the default address space. A default-address-space + /// pointee is resolved through getTargetAddressSpace (e.g. generic for SYCL + /// device data, program address space for functions), matching classic + /// CodeGen. + mlir::ptr::MemorySpaceAttrInterface + getPointerAddressSpace(clang::QualType pointeeTy) const; }; } // namespace clang::CIRGen diff --git a/clang/test/CIR/CodeGenSYCL/kernel-caller-address-space.cpp b/clang/test/CIR/CodeGenSYCL/kernel-caller-address-space.cpp new file mode 100644 index 0000000000000..306917a46502b --- /dev/null +++ b/clang/test/CIR/CodeGenSYCL/kernel-caller-address-space.cpp @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -std=c++20 -fsycl-is-device -triple spirv64-unknown-unknown -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -std=c++20 -fsycl-is-device -triple spirv64-unknown-unknown -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -std=c++20 -fsycl-is-device -triple spirv64-unknown-unknown -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM + +// SYCL uses the "generic as default address space" deduction mode: unlike +// OpenCL, the address space is not deduced in Sema, so an unqualified pointer +// reaches CodeGen as LangAS::Default and must be given the generic address +// space during device compilation. This verifies that a pointer captured by a +// SYCL kernel is emitted in the generic address space (address space 4 on the +// SPIR-V target), matching classic CodeGen. + +// Required by sycl_kernel_entry_point semantics. +template <typename KernelName, typename... Ts> +void sycl_kernel_launch(const char *, Ts...) {} + +template <typename KernelName, typename KernelType> +[[clang::sycl_kernel_entry_point(KernelName)]] +void kernel_single_task(KernelType kf) { kf(); } + +struct KN; + +void test(int *p) { + kernel_single_task<KN>([p]() { *p = 42; }); +} + +// The captured pointer lives in the closure object. Its default address space +// is resolved to the generic address space. +// CIR: !cir.ptr<!s32i, target_address_space(4)> + +// The kernel caller entry point receives the closure and casts it to the +// generic address space before invoking the kernel functor. +// CIR-LABEL: cir.func {{.*}}@_ZTS2KN +// CIR: cir.cast address_space {{.*}} -> !cir.ptr<{{.*}}, target_address_space(4)> + +// The kernel functor's operator() reads the captured pointer, which is a +// generic-address-space pointer, and stores through it. +// CIR-LABEL: cir.func {{.*}}@_ZZ4testPiENKUlvE_clEv +// CIR: cir.get_member {{.*}} -> !cir.ptr<!cir.ptr<!s32i, target_address_space(4)>> +// CIR: cir.store {{.*}} : !s32i, !cir.ptr<!s32i, target_address_space(4)> + +// The captured pointer field and the store through it use address space 4, +// matching classic CodeGen. +// LLVM: %class.anon{{.*}} = type { ptr addrspace(4) } +// LLVM-LABEL: define {{.*}}@_ZZ4testPiENKUlvE_clEv(ptr addrspace(4) +// LLVM: store i32 42, ptr addrspace(4) + +struct FPKN; +void callee(); + +void test_fp() { + kernel_single_task<FPKN>([]() { void (*fp)() = callee; fp(); }); +} + +// Unlike data pointers, function pointers use the program address space (0), +// not the generic address space: the pointee is a function type. +// CIR-LABEL: cir.func {{.*}}@_ZZ7test_fpvENKUlvE_clEv +// CIR: cir.alloca {{.*}}"fp"{{.*}}: !cir.ptr<!cir.ptr<!cir.func<()>>> +// LLVM-LABEL: define {{.*}}@_ZZ7test_fpvENKUlvE_clEv +// LLVM: store ptr @_Z6calleev, ptr _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
