[clang] 99f7a3e - [CIR][SYCL] Emit generic address space for default pointers in device code (#223464)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 15 16:52:35 PDT 2026
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
More information about the cfe-commits
mailing list