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
+


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to