[clang] 73dd189 - [CIR][SYCL] Implement SYCLUniqueStableNameExpr codegen (#231209)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 13 08:05:28 PDT 2026
Author: Konstantinos Parasyris
Date: 2026-10-13T08:05:22-07:00
New Revision: 73dd1890eefbb976b76aa80495ccc6b5e83b2eb0
URL: https://github.com/llvm/llvm-project/commit/73dd1890eefbb976b76aa80495ccc6b5e83b2eb0
DIFF: https://github.com/llvm/llvm-project/commit/73dd1890eefbb976b76aa80495ccc6b5e83b2eb0.diff
LOG: [CIR][SYCL] Implement SYCLUniqueStableNameExpr codegen (#231209)
Adds `SYCLUniqueStableNameExpr` support in CIR.
Added:
clang/test/CIR/CodeGenSYCL/unique-stable-name.cpp
Modified:
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
clang/lib/CIR/CodeGen/CIRGenModule.cpp
clang/lib/CIR/CodeGen/CIRGenModule.h
Removed:
################################################################################
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index fbf3e90d14369a..74266450ddc9fe 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -272,11 +272,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
mlir::Value VisitPseudoObjectExpr(PseudoObjectExpr *e) {
return cgf.emitPseudoObjectRValue(e).getValue();
}
- mlir::Value VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *e) {
- cgf.cgm.errorNYI(e->getSourceRange(),
- "ScalarExprEmitter: sycl unique stable name");
- return {};
- }
+ mlir::Value VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *e);
mlir::Value VisitEmbedExpr(EmbedExpr *e) {
assert(e->getDataElementCount() == 1);
auto it = e->begin();
@@ -1828,6 +1824,24 @@ mlir::Value ScalarExprEmitter::emitCompoundAssign(
return emitLoadOfLValue(lhs, e->getExprLoc());
}
+mlir::Value
+ScalarExprEmitter::VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *e) {
+ ASTContext &context = cgf.getContext();
+ mlir::Location loc = cgf.getLoc(e->getSourceRange());
+ cir::GlobalOp globalConstStr =
+ cgf.cgm.createGlobalString(loc, e->ComputeName(context), "__usn_str");
+
+ // Unlike LLVM IR, CIR pointers are typed, so the bitcast and the address
+ // space cast are emitted as separate operations when both are needed.
+ mlir::Value addr = builder.createGetGlobal(loc, globalConstStr);
+ auto exprTy = mlir::cast<cir::PointerType>(convertType(e->getType()));
+ auto addrTy = mlir::cast<cir::PointerType>(addr.getType());
+ if (addrTy.getAddrSpace() != exprTy.getAddrSpace())
+ addr = cgf.performAddrSpaceCast(
+ addr, builder.getPointerTo(addrTy.getPointee(), exprTy.getAddrSpace()));
+ return builder.createBitcast(loc, addr, exprTy);
+}
+
mlir::Value ScalarExprEmitter::VisitExprWithCleanups(ExprWithCleanups *e) {
CIRGenFunction::FullExprCleanupScope scope(cgf, e->getSubExpr());
mlir::Value v = Visit(e->getSubExpr());
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 470ee306afebe8..1d6553313b24b4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -2330,6 +2330,19 @@ CIRGenModule::getAddrOfConstantStringFromLiteral(const StringLiteral *s,
return builder.getGlobalViewAttr(ptrTy, gv);
}
+cir::GlobalOp CIRGenModule::createGlobalString(mlir::Location loc,
+ StringRef str, StringRef name) {
+ mlir::Attribute init = builder.getString(str, convertType(astContext.CharTy),
+ /*size=*/std::nullopt);
+
+ // Unlike LLVM IR, CIR doesn't automatically unique names for globals, so
+ // we need to do that explicitly.
+ return generateStringLiteral(loc, mlir::cast<mlir::TypedAttr>(init),
+ cir::GlobalLinkageKind::PrivateLinkage, *this,
+ getUniqueGlobalName(name.str()),
+ CharUnits::One());
+}
+
mlir::ptr::MemorySpaceAttrInterface
CIRGenModule::getGlobalCIRAddressSpace(LangAS as) {
return getTargetCIRGenInfo().getGlobalCIRAddressSpace(as);
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 0578ccaae80861..60feb64f1e9276 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -473,6 +473,11 @@ class CIRGenModule : public CIRGenTypeCache {
getAddrOfConstantStringFromLiteral(const StringLiteral *s,
llvm::StringRef name = ".str");
+ /// Create a private constant global holding the null-terminated string
+ /// \p str, mirroring llvm::IRBuilder::CreateGlobalString.
+ cir::GlobalOp createGlobalString(mlir::Location loc, llvm::StringRef str,
+ llvm::StringRef name);
+
/// Returns the address space for temporary allocations in the language. This
/// ensures that the allocated variable's address space matches the
/// expectations of the AST, rather than using the target's allocation address
diff --git a/clang/test/CIR/CodeGenSYCL/unique-stable-name.cpp b/clang/test/CIR/CodeGenSYCL/unique-stable-name.cpp
new file mode 100644
index 00000000000000..b074cc6241be65
--- /dev/null
+++ b/clang/test/CIR/CodeGenSYCL/unique-stable-name.cpp
@@ -0,0 +1,145 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsycl-is-host \
+// RUN: -Wno-unevaluated-expression -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck %s --check-prefix=CIR-HOST --input-file=%t.cir
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsycl-is-host \
+// RUN: -Wno-unevaluated-expression -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck %s --check-prefixes=LLVM-HOST,CIR-LLVM-HOST --input-file=%t-cir.ll
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsycl-is-host \
+// RUN: -Wno-unevaluated-expression -emit-llvm %s -o %t.ll
+// RUN: FileCheck %s --check-prefixes=LLVM-HOST,OGCG-HOST --input-file=%t.ll
+// RUN: %clang_cc1 -triple spir64-unknown-unknown \
+// RUN: -aux-triple x86_64-unknown-linux-gnu -fsycl-is-device \
+// RUN: -Wno-unevaluated-expression -fclangir -emit-cir %s -o %t-dev.cir
+// RUN: FileCheck %s --check-prefix=CIR-DEV --input-file=%t-dev.cir
+// RUN: %clang_cc1 -triple spir64-unknown-unknown \
+// RUN: -aux-triple x86_64-unknown-linux-gnu -fsycl-is-device \
+// RUN: -Wno-unevaluated-expression -fclangir -emit-llvm %s -o %t-dev-cir.ll
+// RUN: FileCheck %s --check-prefixes=LLVM-DEV,CIR-LLVM-DEV --input-file=%t-dev-cir.ll
+// RUN: %clang_cc1 -triple spir64-unknown-unknown \
+// RUN: -aux-triple x86_64-unknown-linux-gnu -fsycl-is-device \
+// RUN: -Wno-unevaluated-expression -emit-llvm %s -o %t-dev.ll
+// RUN: FileCheck %s --check-prefixes=LLVM-DEV,OGCG-DEV --input-file=%t-dev.ll
+
+// __builtin_sycl_unique_stable_name evaluated at run time emits a private
+// "__usn_str" global in the global constant address space, cast to the type
+// of the expression. Constant-evaluated uses are folded to a string literal.
+
+// 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(); }
+
+void use(const char *);
+
+// A global initializer is constant-folded to a string literal.
+const char *global_name = __builtin_sycl_unique_stable_name(int);
+
+// CIR-HOST: cir.global "private" constant cir_private dso_local @[[GLOBAL_STR:[^ ]+]] = #cir.const_array<"_ZTSi" : !cir.array<!s8i x 5>, trailing_zeros> : !cir.array<!s8i x 6> align(1)
+// CIR-HOST: cir.global external @global_name = #cir.global_view<@[[GLOBAL_STR]]> : !cir.ptr<!s8i> align(8)
+// CIR-HOST: cir.global "private" constant cir_private dso_local @[[LAMBDA:__usn_str]] = #cir.const_array<"_ZTSZ9host_onlyvEUlvE_" : !cir.array<!s8i x 22>, trailing_zeros> : !cir.array<!s8i x 23> align(1)
+// CIR-HOST: cir.global "private" constant cir_private dso_local @[[INT:__usn_str\.[0-9]+]] = #cir.const_array<"_ZTSi" : !cir.array<!s8i x 5>, trailing_zeros> : !cir.array<!s8i x 6> align(1)
+// CIR-HOST: cir.global "private" constant cir_private dso_local @[[CONSTEXPR_STR:[^ ]+]] = #cir.const_array<"_ZTSl" : !cir.array<!s8i x 5>, trailing_zeros> : !cir.array<!s8i x 6> align(1)
+// CIR-HOST: cir.global "private" constant cir_private dso_local @[[TPL_INT:__usn_str\.[0-9]+]] = #cir.const_array<"_ZTSi" : !cir.array<!s8i x 5>, trailing_zeros> : !cir.array<!s8i x 6> align(1)
+// CIR-HOST: cir.global "private" constant cir_private dso_local @[[TPL_LAMBDA:__usn_str\.[0-9]+]] = #cir.const_array<"_ZTSZ9host_onlyvEUlvE_" : !cir.array<!s8i x 22>, trailing_zeros> : !cir.array<!s8i x 23> align(1)
+
+// CIR-LLVM-HOST: @[[GLOBAL_STR:[^ ]+]] = private constant [6 x i8] c"_ZTSi\00", align 1
+// CIR-LLVM-HOST: @global_name = global ptr @[[GLOBAL_STR]], align 8
+// CIR-LLVM-HOST: @[[LAMBDA:__usn_str]] = private constant [23 x i8] c"_ZTSZ9host_onlyvEUlvE_\00", align 1
+// CIR-LLVM-HOST: @[[INT:__usn_str\.[0-9]+]] = private constant [6 x i8] c"_ZTSi\00", align 1
+// CIR-LLVM-HOST: @[[CONSTEXPR_STR:[^ ]+]] = private constant [6 x i8] c"_ZTSl\00", align 1
+// CIR-LLVM-HOST: @[[TPL_INT:__usn_str\.[0-9]+]] = private constant [6 x i8] c"_ZTSi\00", align 1
+// CIR-LLVM-HOST: @[[TPL_LAMBDA:__usn_str\.[0-9]+]] = private constant [23 x i8] c"_ZTSZ9host_onlyvEUlvE_\00", align 1
+
+// OGCG-HOST: @[[GLOBAL_STR:[^ ]+]] = private unnamed_addr constant [6 x i8] c"_ZTSi\00", align 1
+// OGCG-HOST: @global_name = global ptr @[[GLOBAL_STR]], align 8
+// OGCG-HOST: @[[LAMBDA:__usn_str]] = private unnamed_addr constant [23 x i8] c"_ZTSZ9host_onlyvEUlvE_\00", align 1
+// OGCG-HOST: @[[INT:__usn_str\.[0-9]+]] = private unnamed_addr constant [6 x i8] c"_ZTSi\00", align 1
+// OGCG-HOST: @[[CONSTEXPR_STR:[^ ]+]] = private unnamed_addr constant [6 x i8] c"_ZTSl\00", align 1
+// OGCG-HOST: @[[TPL_INT:__usn_str\.[0-9]+]] = private unnamed_addr constant [6 x i8] c"_ZTSi\00", align 1
+// OGCG-HOST: @[[TPL_LAMBDA:__usn_str\.[0-9]+]] = private unnamed_addr constant [23 x i8] c"_ZTSZ9host_onlyvEUlvE_\00", align 1
+
+// CIR-DEV: cir.global "private" constant cir_private dso_local target_address_space(1) @[[KERNEL_LAMBDA:__usn_str]] = #cir.const_array<"_ZTSZZ4mainENKUlvE_clEvEUlvE_" : !cir.array<!s8i x 29>, trailing_zeros> : !cir.array<!s8i x 30> align(1)
+// CIR-DEV: cir.global "private" constant cir_private dso_local target_address_space(1) @[[KERNEL_CONSTEXPR:[^ ]+]] = #cir.const_array<"_ZTSc" : !cir.array<!s8i x 5>, trailing_zeros> : !cir.array<!s8i x 6> align(1)
+
+// CIR-LLVM-DEV: @[[KERNEL_LAMBDA:__usn_str]] = private addrspace(1) constant [30 x i8] c"_ZTSZZ4mainENKUlvE_clEvEUlvE_\00", align 1
+// CIR-LLVM-DEV: @[[KERNEL_CONSTEXPR:[^ ]+]] = private addrspace(1) constant [6 x i8] c"_ZTSc\00", align 1
+
+// OGCG-DEV: @[[KERNEL_LAMBDA:__usn_str]] = private unnamed_addr addrspace(1) constant [30 x i8] c"_ZTSZZ4mainENKUlvE_clEvEUlvE_\00", align 1
+// OGCG-DEV: @[[KERNEL_CONSTEXPR:[^ ]+]] = private unnamed_addr addrspace(1) constant [6 x i8] c"_ZTSc\00", align 1
+
+template <typename T>
+void template_param() {
+ use(__builtin_sycl_unique_stable_name(T));
+}
+
+void host_only() {
+ auto l = [] {};
+ use(__builtin_sycl_unique_stable_name(decltype(l)));
+ template_param<int>();
+ template_param<decltype(l)>();
+
+ // The operand is unevaluated.
+ int i = 0;
+ use(__builtin_sycl_unique_stable_name(decltype(i++)));
+
+ // A constexpr use is constant-folded to a string literal.
+ constexpr const char *c = __builtin_sycl_unique_stable_name(long);
+ use(c);
+}
+
+// CIR-HOST-LABEL: cir.func {{.*}} @_Z9host_onlyv()
+// CIR-HOST: %[[L:.*]] = cir.get_global @[[LAMBDA]] : !cir.ptr<!cir.array<!s8i x 23>>
+// CIR-HOST: %[[L_CAST:.*]] = cir.cast bitcast %[[L]] : !cir.ptr<!cir.array<!s8i x 23>> -> !cir.ptr<!s8i>
+// CIR-HOST: cir.call @_Z3usePKc(%[[L_CAST]])
+// CIR-HOST: %[[I:.*]] = cir.get_global @[[INT]] : !cir.ptr<!cir.array<!s8i x 6>>
+// CIR-HOST: %[[I_CAST:.*]] = cir.cast bitcast %[[I]] : !cir.ptr<!cir.array<!s8i x 6>> -> !cir.ptr<!s8i>
+// CIR-HOST: cir.call @_Z3usePKc(%[[I_CAST]])
+// CIR-HOST: cir.const #cir.global_view<@[[CONSTEXPR_STR]]> : !cir.ptr<!s8i>
+
+// LLVM-HOST-LABEL: define dso_local void @_Z9host_onlyv()
+// LLVM-HOST: call void @_Z3usePKc(ptr noundef @[[LAMBDA]])
+// LLVM-HOST: call void @_Z3usePKc(ptr noundef @[[INT]])
+// LLVM-HOST: store ptr @[[CONSTEXPR_STR]], ptr %{{.*}}, align 8
+
+// CIR-HOST-LABEL: cir.func {{.*}} @_Z14template_paramIiEvv()
+// CIR-HOST: %[[T:.*]] = cir.get_global @[[TPL_INT]] : !cir.ptr<!cir.array<!s8i x 6>>
+// CIR-HOST: %[[T_CAST:.*]] = cir.cast bitcast %[[T]] : !cir.ptr<!cir.array<!s8i x 6>> -> !cir.ptr<!s8i>
+// CIR-HOST: cir.call @_Z3usePKc(%[[T_CAST]])
+
+// LLVM-HOST-LABEL: define linkonce_odr void @_Z14template_paramIiEvv()
+// LLVM-HOST: call void @_Z3usePKc(ptr noundef @[[TPL_INT]])
+
+// CIR-HOST-LABEL: cir.func {{.*}} @_Z14template_paramIZ9host_onlyvEUlvE_Evv()
+// CIR-HOST: %[[T:.*]] = cir.get_global @[[TPL_LAMBDA]] : !cir.ptr<!cir.array<!s8i x 23>>
+// CIR-HOST: %[[T_CAST:.*]] = cir.cast bitcast %[[T]] : !cir.ptr<!cir.array<!s8i x 23>> -> !cir.ptr<!s8i>
+// CIR-HOST: cir.call @_Z3usePKc(%[[T_CAST]])
+
+// LLVM-HOST-LABEL: define internal void @_Z14template_paramIZ9host_onlyvEUlvE_Evv()
+// LLVM-HOST: call void @_Z3usePKc(ptr noundef @[[TPL_LAMBDA]])
+
+int main() {
+ kernel_single_task<class K>([] {
+ auto x = [] {};
+ use(__builtin_sycl_unique_stable_name(decltype(x)));
+ constexpr const char *c = __builtin_sycl_unique_stable_name(char);
+ use(c);
+ });
+}
+
+// On the device, the global is in the global constant address space and is
+// cast to the generic address space of the expression type.
+
+// CIR-DEV-LABEL: cir.func {{.*}} @_ZZ4mainENKUlvE_clEv(
+// CIR-DEV: %[[G:.*]] = cir.get_global @[[KERNEL_LAMBDA]] : !cir.ptr<!cir.array<!s8i x 30>, target_address_space(1)>
+// CIR-DEV: %[[AS:.*]] = cir.cast address_space %[[G]] : !cir.ptr<!cir.array<!s8i x 30>, target_address_space(1)> -> !cir.ptr<!cir.array<!s8i x 30>, target_address_space(4)>
+// CIR-DEV: %[[CAST:.*]] = cir.cast bitcast %[[AS]] : !cir.ptr<!cir.array<!s8i x 30>, target_address_space(4)> -> !cir.ptr<!s8i, target_address_space(4)>
+// CIR-DEV: cir.call @_Z3usePKc(%[[CAST]])
+// CIR-DEV: cir.const #cir.global_view<@[[KERNEL_CONSTEXPR]]> : !cir.ptr<!s8i, target_address_space(4)>
+
+// LLVM-DEV-LABEL: define internal spir_func void @_ZZ4mainENKUlvE_clEv(
+// LLVM-DEV: call spir_func void @_Z3usePKc(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[KERNEL_LAMBDA]] to ptr addrspace(4)))
+// LLVM-DEV: store ptr addrspace(4) addrspacecast (ptr addrspace(1) @[[KERNEL_CONSTEXPR]] to ptr addrspace(4)), ptr addrspace(4) %{{.*}}, align 8
+
More information about the cfe-commits
mailing list