Index: clang/docs/LanguageExtensions.rst =================================================================== --- clang/docs/LanguageExtensions.rst +++ clang/docs/LanguageExtensions.rst @@ -2521,12 +2521,9 @@ In order to produce the unique name, the current implementation of the bultin uses Itanium mangling even if the host compilation uses a different name mangling scheme at runtime. The mangler marks all the lambdas required to name -the SYCL kernel and emits a stable local ordering of the respective lambdas, -starting from ``10000``. The initial value of ``10000`` serves as an obvious -differentiator from ordinary lambda mangling numbers but does not serve any -other purpose and may change in the future. The resulting pattern is -demanglable. When non-lambda types are passed to the builtin, the mangler emits -their usual pattern without any special treatment. +the SYCL kernel a nd emits a stable local ordering of the respective lambdas. +The resulting pattern is demanglable. When non-lambda types are passed to the +builtin, the mangler emits their usual pattern without any special treatment. **Syntax**: Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ clang/include/clang/AST/ASTContext.h @@ -3239,31 +3239,10 @@ StringRef getCUIDHash() const; - void AddSYCLKernelNamingDecl(const CXXRecordDecl *RD); - bool IsSYCLKernelNamingDecl(const NamedDecl *RD) const; - unsigned GetSYCLKernelNamingIndex(const NamedDecl *RD); - /// A SourceLocation to store whether we have evaluated a kernel name already, - /// and where it happened. If so, we need to diagnose an illegal use of the - /// builtin. - llvm::MapVector - SYCLUniqueStableNameEvaluatedValues; - private: /// All OMPTraitInfo objects live in this collection, one per /// `pragma omp [begin] declare variant` directive. SmallVector, 4> OMPTraitInfoVector; - - /// A list of the (right now just lambda decls) declarations required to - /// name all the SYCL kernels in the translation unit, so that we can get the - /// correct kernel name, as well as implement - /// __builtin_sycl_unique_stable_name. - llvm::DenseMap> - SYCLKernelNamingTypes; - std::unique_ptr SYCLKernelFilterContext; - void FilterSYCLKernelNamingDecls( - const CXXRecordDecl *RD, - llvm::SmallVectorImpl &Decls); }; /// Insertion operator for diagnostics. Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6409,11 +6409,6 @@ def warn_pointer_sub_null_ptr : Warning< "performing pointer subtraction with a null pointer %select{has|may have}0 undefined behavior">, InGroup, DefaultIgnore; -def err_kernel_invalidates_sycl_unique_stable_name - : Error<"kernel instantiation changes the result of an evaluated " - "'__builtin_sycl_unique_stable_name'">; -def note_sycl_unique_stable_name_evaluated_here - : Note<"'__builtin_sycl_unique_stable_name' evaluated here">; def warn_floatingpoint_eq : Warning< "comparing floating point with == or != is unsafe">, Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -914,10 +914,6 @@ OpaqueParser = P; } - // Does the work necessary to deal with a SYCL kernel lambda. At the moment, - // this just marks the list of lambdas required to name the kernel. - void AddSYCLKernelLambda(const FunctionDecl *FD); - class DelayedDiagnostics; class DelayedDiagnosticsState { Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -11801,86 +11801,3 @@ CUIDHash = llvm::utohexstr(llvm::MD5Hash(LangOpts.CUID), /*LowerCase=*/true); return CUIDHash; } - -// Get the closest named parent, so we can order the sycl naming decls somewhere -// that mangling is meaningful. -static const DeclContext *GetNamedParent(const CXXRecordDecl *RD) { - const DeclContext *DC = RD->getDeclContext(); - - while (!isa(DC)) - DC = DC->getParent(); - return DC; -} - -void ASTContext::AddSYCLKernelNamingDecl(const CXXRecordDecl *RD) { - assert(getLangOpts().isSYCL() && "Only valid for SYCL programs"); - RD = RD->getCanonicalDecl(); - const DeclContext *DC = GetNamedParent(RD); - - assert(RD->getLocation().isValid() && - "Invalid location on kernel naming decl"); - - (void)SYCLKernelNamingTypes[DC].insert(RD); -} - -bool ASTContext::IsSYCLKernelNamingDecl(const NamedDecl *ND) const { - assert(getLangOpts().isSYCL() && "Only valid for SYCL programs"); - const auto *RD = dyn_cast(ND); - if (!RD) - return false; - RD = RD->getCanonicalDecl(); - const DeclContext *DC = GetNamedParent(RD); - - auto Itr = SYCLKernelNamingTypes.find(DC); - - if (Itr == SYCLKernelNamingTypes.end()) - return false; - - return Itr->getSecond().count(RD); -} - -// Filters the Decls list to those that share the lambda mangling with the -// passed RD. -void ASTContext::FilterSYCLKernelNamingDecls( - const CXXRecordDecl *RD, - llvm::SmallVectorImpl &Decls) { - - if (!SYCLKernelFilterContext) - SYCLKernelFilterContext.reset( - ItaniumMangleContext::create(*this, getDiagnostics())); - - llvm::SmallString<128> LambdaSig; - llvm::raw_svector_ostream Out(LambdaSig); - SYCLKernelFilterContext->mangleLambdaSig(RD, Out); - - llvm::erase_if(Decls, [this, &LambdaSig](const CXXRecordDecl *LocalRD) { - llvm::SmallString<128> LocalLambdaSig; - llvm::raw_svector_ostream LocalOut(LocalLambdaSig); - SYCLKernelFilterContext->mangleLambdaSig(LocalRD, LocalOut); - return LambdaSig != LocalLambdaSig; - }); -} - -unsigned ASTContext::GetSYCLKernelNamingIndex(const NamedDecl *ND) { - assert(getLangOpts().isSYCL() && "Only valid for SYCL programs"); - assert(IsSYCLKernelNamingDecl(ND) && - "Lambda not involved in mangling asked for a naming index?"); - - const CXXRecordDecl *RD = cast(ND)->getCanonicalDecl(); - const DeclContext *DC = GetNamedParent(RD); - - auto Itr = SYCLKernelNamingTypes.find(DC); - assert(Itr != SYCLKernelNamingTypes.end() && "Not a valid DeclContext?"); - - const llvm::SmallPtrSet &Set = Itr->getSecond(); - - llvm::SmallVector Decls{Set.begin(), Set.end()}; - - FilterSYCLKernelNamingDecls(RD, Decls); - - llvm::sort(Decls, [](const CXXRecordDecl *LHS, const CXXRecordDecl *RHS) { - return LHS->getLambdaManglingNumber() < RHS->getLambdaManglingNumber(); - }); - - return llvm::find(Decls, RD) - Decls.begin(); -} Index: clang/lib/AST/Expr.cpp =================================================================== --- clang/lib/AST/Expr.cpp +++ clang/lib/AST/Expr.cpp @@ -545,20 +545,10 @@ QualType Ty) { auto MangleCallback = [](ASTContext &Ctx, const NamedDecl *ND) -> llvm::Optional { - // This replaces the 'lambda number' in the mangling with a unique number - // based on its order in the declaration. To provide some level of visual - // notability (actual uniqueness from normal lambdas isn't necessary, as - // these are used differently), we add 10,000 to the number. - // For example: - // _ZTSZ3foovEUlvE10005_ - // Demangles to: typeinfo name for foo()::'lambda10005'() - // Note that the mangler subtracts 2, since with normal lambdas the lambda - // mangling number '0' is an anonymous struct mangle, and '1' is omitted. - // So 10,002 results in the first number being 10,000. - if (Ctx.IsSYCLKernelNamingDecl(ND)) - return 10'002 + Ctx.GetSYCLKernelNamingIndex(ND); - return llvm::None; + if (const auto *RD = dyn_cast(ND)) + return RD->getDeviceLambdaManglingNumber(); }; + std::unique_ptr Ctx{ItaniumMangleContext::create( Context, Context.getDiagnostics(), MangleCallback)}; Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -8674,8 +8674,6 @@ bool VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *E) { std::string ResultStr = E->ComputeName(Info.Ctx); - Info.Ctx.SYCLUniqueStableNameEvaluatedValues[E] = ResultStr; - QualType CharTy = Info.Ctx.CharTy.withConst(); APInt Size(Info.Ctx.getTypeSize(Info.Ctx.getSizeType()), ResultStr.size() + 1); Index: clang/lib/AST/ItaniumCXXABI.cpp =================================================================== --- clang/lib/AST/ItaniumCXXABI.cpp +++ clang/lib/AST/ItaniumCXXABI.cpp @@ -181,6 +181,37 @@ } }; +// A version of this for SYCL that makes sure that 'device' mangling context +// matches the lambda mangling number, so that __builtin_sycl_unique_stable_name +// can be consistently generated between a MS and Itanium host by just referring +// to the device mangling number. +class ItaniumSYCLNumberingContext : public ItaniumNumberingContext { + llvm::DenseMap ManglingNumbers; + using ManglingItr = decltype(ManglingNumbers)::iterator; + +public: + ItaniumSYCLNumberingContext(ItaniumMangleContext *Mangler) + : ItaniumNumberingContext(Mangler) {} + + unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override { + unsigned Number = ItaniumNumberingContext::getManglingNumber(CallOperator); + std::pair emplace_result = + ManglingNumbers.try_emplace(CallOperator, Number); + (void)emplace_result; + assert(emplace_result.second && "Lambda number set multiple times?"); + return Number; + } + + using ItaniumNumberingContext::getManglingNumber; + + unsigned getDeviceManglingNumber(const CXXMethodDecl *CallOperator) override { + ManglingItr Itr = ManglingNumbers.find(CallOperator); + assert(Itr != ManglingNumbers.end() && "Lambda not yet mangled?"); + + return Itr->second; + } +}; + class ItaniumCXXABI : public CXXABI { private: std::unique_ptr Mangler; @@ -249,6 +280,9 @@ std::unique_ptr createMangleNumberingContext() const override { + if (Context.getLangOpts().isSYCL()) + return std::make_unique( + cast(Mangler.get())); return std::make_unique( cast(Mangler.get())); } Index: clang/lib/AST/ItaniumMangle.cpp =================================================================== --- clang/lib/AST/ItaniumMangle.cpp +++ clang/lib/AST/ItaniumMangle.cpp @@ -1518,9 +1518,16 @@ // ::= * + // # Parameter types or 'v' for 'void'. if (const CXXRecordDecl *Record = dyn_cast(TD)) { - if (Record->isLambda() && (Record->getLambdaManglingNumber() || - Context.getDiscriminatorOverride()( - Context.getASTContext(), Record))) { + llvm::Optional DeviceNumber = + Context.getDiscriminatorOverride()(Context.getASTContext(), Record); + + // If we have a device-number via the discriminator, use that to mangle + // the lambda, otherwise use the typical lambda-mangling-number. In either + // case, a '0' should be mangled as a normal unnamed class instead of as a + // lambda. + if (Record->isLambda() && + ((DeviceNumber && *DeviceNumber > 0) || + (!DeviceNumber && Record->getLambdaManglingNumber() > 0))) { assert(!AdditionalAbiTags && "Lambda type cannot have additional abi tags"); mangleLambda(Record); @@ -1960,8 +1967,8 @@ // mangling number for this lambda. llvm::Optional DeviceNumber = Context.getDiscriminatorOverride()(Context.getASTContext(), Lambda); - unsigned Number = DeviceNumber.hasValue() ? *DeviceNumber - : Lambda->getLambdaManglingNumber(); + unsigned Number = + DeviceNumber ? *DeviceNumber : Lambda->getLambdaManglingNumber(); assert(Number > 0 && "Lambda should be mangled as an unnamed class"); if (Number > 1) Index: clang/lib/AST/MicrosoftCXXABI.cpp =================================================================== --- clang/lib/AST/MicrosoftCXXABI.cpp +++ clang/lib/AST/MicrosoftCXXABI.cpp @@ -78,6 +78,19 @@ } }; +class MSSYCLNumberingContext : public MicrosoftNumberingContext { + std::unique_ptr DeviceCtx; + +public: + MSSYCLNumberingContext(MangleContext *DeviceMangler) { + DeviceCtx = createItaniumNumberingContext(DeviceMangler); + } + + unsigned getDeviceManglingNumber(const CXXMethodDecl *CallOperator) override { + return DeviceCtx->getManglingNumber(CallOperator); + } +}; + class MicrosoftCXXABI : public CXXABI { ASTContext &Context; llvm::SmallDenseMap RecordToCopyCtor; @@ -100,6 +113,10 @@ DeviceMangler.reset( Context.createMangleContext(Context.getAuxTargetInfo())); } + else if (Context.getLangOpts().isSYCL()) { + DeviceMangler.reset( + ItaniumMangleContext::create(Context, Context.getDiagnostics())); + } } MemberPointerInfo @@ -162,7 +179,11 @@ if (Context.getLangOpts().CUDA && Context.getAuxTargetInfo()) { assert(DeviceMangler && "Missing device mangler"); return std::make_unique(DeviceMangler.get()); + } else if (Context.getLangOpts().isSYCL()) { + assert(DeviceMangler && "Missing device mangler"); + return std::make_unique(DeviceMangler.get()); } + return std::make_unique(); } }; Index: clang/lib/Sema/SemaSYCL.cpp =================================================================== --- clang/lib/Sema/SemaSYCL.cpp +++ clang/lib/Sema/SemaSYCL.cpp @@ -48,35 +48,3 @@ return DiagKind != SemaDiagnosticBuilder::K_Immediate && DiagKind != SemaDiagnosticBuilder::K_ImmediateWithCallStack; } - -// The SYCL kernel's 'object type' used for diagnostics and naming/mangling is -// the first parameter to a sycl_kernel labeled function template. In SYCL1.2.1, -// this was passed by value, and in SYCL2020, it is passed by reference. -static QualType GetSYCLKernelObjectType(const FunctionDecl *KernelCaller) { - assert(KernelCaller->getNumParams() > 0 && "Insufficient kernel parameters"); - QualType KernelParamTy = KernelCaller->getParamDecl(0)->getType(); - - // SYCL 2020 kernels are passed by reference. - if (KernelParamTy->isReferenceType()) - return KernelParamTy->getPointeeType(); - - // SYCL 1.2.1 - return KernelParamTy; -} - -void Sema::AddSYCLKernelLambda(const FunctionDecl *FD) { - auto MangleCallback = [](ASTContext &Ctx, - const NamedDecl *ND) -> llvm::Optional { - if (const auto *RD = dyn_cast(ND)) - Ctx.AddSYCLKernelNamingDecl(RD); - // We always want to go into the lambda mangling (skipping the unnamed - // struct version), so make sure we return a value here. - return 1; - }; - - QualType Ty = GetSYCLKernelObjectType(FD); - std::unique_ptr Ctx{ItaniumMangleContext::create( - Context, Context.getDiagnostics(), MangleCallback)}; - llvm::raw_null_ostream Out; - Ctx->mangleTypeName(Ty, Out); -} Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -556,26 +556,6 @@ static void instantiateDependentSYCLKernelAttr( Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, const SYCLKernelAttr &Attr, Decl *New) { - // Functions cannot be partially specialized, so if we are being instantiated, - // we are obviously a complete specialization. Since this attribute is only - // valid on function template declarations, we know that this is a full - // instantiation of a kernel. - S.AddSYCLKernelLambda(cast(New)); - - // Evaluate whether this would change any of the already evaluated - // __builtin_sycl_unique_stable_name values. - for (auto &Itr : S.Context.SYCLUniqueStableNameEvaluatedValues) { - const std::string &CurName = Itr.first->ComputeName(S.Context); - if (Itr.second != CurName) { - S.Diag(New->getLocation(), - diag::err_kernel_invalidates_sycl_unique_stable_name); - S.Diag(Itr.first->getLocation(), - diag::note_sycl_unique_stable_name_evaluated_here); - // Update this so future diagnostics work correctly. - Itr.second = CurName; - } - } - New->addAttr(Attr.clone(S.getASTContext())); } Index: clang/test/CodeGenSYCL/unique_stable_name.cpp =================================================================== --- clang/test/CodeGenSYCL/unique_stable_name.cpp +++ clang/test/CodeGenSYCL/unique_stable_name.cpp @@ -1,22 +1,22 @@ // RUN: %clang_cc1 -triple spir64-unknown-unknown-sycldevice -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s -// CHECK: @[[LAMBDA_KERNEL3:[^\w]+]] = private unnamed_addr constant [[LAMBDA_K3_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ4mainEUlPZ4mainEUlvE10000_E10000_\00" +// CHECK: @[[LAMBDA_KERNEL3:[^\w]+]] = private unnamed_addr constant [[LAMBDA_K3_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ4mainEUlPZ4mainEUlvE_E_\00" // CHECK: @[[INT1:[^\w]+]] = private unnamed_addr constant [[INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSi\00" // CHECK: @[[STRING:[^\w]+]] = private unnamed_addr constant [[STRING_SIZE:\[[0-9]+ x i8\]]] c"_ZTSAppL_ZZ4mainE1jE_i\00", // CHECK: @[[INT2:[^\w]+]] = private unnamed_addr constant [[INT_SIZE]] c"_ZTSi\00" -// CHECK: @[[LAMBDA_X:[^\w]+]] = private unnamed_addr constant [[LAMBDA_X_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE_\00" -// CHECK: @[[MACRO_X:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE0_\00" -// CHECK: @[[MACRO_Y:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE1_\00" -// CHECK: @{{.*}} = private unnamed_addr constant [36 x i8] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE2_\00", align 1 -// CHECK: @{{.*}} = private unnamed_addr constant [36 x i8] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE3_\00", align 1 -// CHECK: @[[MACRO_MACRO_X:[^\w]+]] = private unnamed_addr constant [[MACRO_MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE4_\00" -// CHECK: @[[MACRO_MACRO_Y:[^\w]+]] = private unnamed_addr constant [[MACRO_MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE5_\00" +// CHECK: @[[LAMBDA_X:[^\w]+]] = private unnamed_addr constant [[LAMBDA_X_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE_\00" +// CHECK: @[[MACRO_X:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE0_\00" +// CHECK: @[[MACRO_Y:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE1_\00" +// CHECK: @{{.*}} = private unnamed_addr constant [32 x i8] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE2_\00", align 1 +// CHECK: @{{.*}} = private unnamed_addr constant [32 x i8] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE3_\00", align 1 +// CHECK: @[[MACRO_MACRO_X:[^\w]+]] = private unnamed_addr constant [[MACRO_MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE4_\00" +// CHECK: @[[MACRO_MACRO_Y:[^\w]+]] = private unnamed_addr constant [[MACRO_MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE5_\00" // CHECK: @[[INT3:[^\w]+]] = private unnamed_addr constant [[INT_SIZE]] c"_ZTSi\00" -// CHECK: @[[LAMBDA:[^\w]+]] = private unnamed_addr constant [[LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE_\00" +// CHECK: @[[LAMBDA:[^\w]+]] = private unnamed_addr constant [[LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE_\00" // CHECK: @[[LAMBDA_IN_DEP_INT:[^\w]+]] = private unnamed_addr constant [[DEP_INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIiEvvEUlvE_\00", -// CHECK: @[[LAMBDA_IN_DEP_X:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIZZ4mainENKUlvE10001_clEvEUlvE_EvvEUlvE_\00", +// CHECK: @[[LAMBDA_IN_DEP_X:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_EvvEUlvE_\00", // CHECK: @[[LAMBDA_NO_DEP:[^\w]+]] = private unnamed_addr constant [[NO_DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ13lambda_no_depIidEvT_T0_EUlidE_\00", -// CHECK: @[[LAMBDA_TWO_DEP:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA1_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE10001_clEvEUliE_ZZ4mainENKS0_clEvEUldE_EvvEUlvE_\00", -// CHECK: @[[LAMBDA_TWO_DEP2:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA2_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE10001_clEvEUldE_ZZ4mainENKS0_clEvEUliE_EvvEUlvE_\00", +// CHECK: @[[LAMBDA_TWO_DEP:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA1_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_EvvEUlvE_\00", +// CHECK: @[[LAMBDA_TWO_DEP2:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA2_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_EvvEUlvE_\00", extern "C" void puts(const char *) {} Index: clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp =================================================================== --- clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp +++ clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp @@ -38,7 +38,7 @@ // Make sure the following 3 are the same between the host and device compile. // Note that these are NOT the same value as eachother, they differ by the // signature. - // CHECK: private unnamed_addr constant [22 x i8] c"_ZTSZ4mainEUlvE10000_\00" - // CHECK: private unnamed_addr constant [22 x i8] c"_ZTSZ4mainEUliE10000_\00" - // CHECK: private unnamed_addr constant [22 x i8] c"_ZTSZ4mainEUldE10000_\00" + // CHECK: private unnamed_addr constant [17 x i8] c"_ZTSZ4mainEUlvE_\00" + // CHECK: private unnamed_addr constant [17 x i8] c"_ZTSZ4mainEUliE_\00" + // CHECK: private unnamed_addr constant [17 x i8] c"_ZTSZ4mainEUldE_\00" } Index: clang/test/SemaSYCL/unique_stable_name.cpp =================================================================== --- clang/test/SemaSYCL/unique_stable_name.cpp +++ clang/test/SemaSYCL/unique_stable_name.cpp @@ -15,10 +15,6 @@ template void kernel1func(const Func &F1) { constexpr const char *F1_output = __builtin_sycl_unique_stable_name(Func); // #USN_F1 - // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}} - // expected-note@#kernel1func_call{{in instantiation of function template specialization}} - // expected-note@#USN_F1{{'__builtin_sycl_unique_stable_name' evaluated here}} - // expected-note@+1{{in instantiation of function template specialization}} kernel_single_task(F1); // #kernel1_call } @@ -38,10 +34,6 @@ template void kernel2func(const Func &F2) { constexpr const char *F2_output = __builtin_sycl_unique_stable_name(Func); // #USN_F2 - // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}} - // expected-note@#kernel2func_call{{in instantiation of function template specialization}} - // expected-note@#USN_F2{{'__builtin_sycl_unique_stable_name' evaluated here}} - // expected-note@+1{{in instantiation of function template specialization}} kernel_single_task([]() {}); } @@ -93,40 +85,34 @@ kernel_single_task( [=]() { l5(); }); // Used in the kernel, but not the kernel name itself - // kernel6 - expect error + // kernel6 - expect no error // Test that passing the lambda to the unique stable name builtin and then - // using the same lambda in the naming of a kernel causes a diagnostic on the - // kernel use due to the change in results to the stable name. + // using the same lambda in the naming of a kernel does not cause a diagnostic + // on the kernel use due to the change in results to the stable name. auto l6 = []() { return 1; }; constexpr const char *l6_output = __builtin_sycl_unique_stable_name(decltype(l6)); // #USN_l6 - // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}} - // expected-note@#USN_l6{{'__builtin_sycl_unique_stable_name' evaluated here}} - // expected-note@+1{{in instantiation of function template specialization}} kernel_single_task(l6); // Used in the kernel name after builtin - // kernel7 - expect error + // kernel7 - expect no error // Same as kernel11 (below) except make the lambda part of naming the kernel. // Test that passing a lambda to the unique stable name builtin and then - // passing a second lambda to the kernel throws an error because the first - // lambda is included in the signature of the second lambda, hence it changes - // the mangling of the kernel. + // passing a second lambda to the kernel does not throw an error because the + // first lambda is included in the signature of the second lambda, but does + // not change the mangling of the kernel. auto l7 = []() { return 1; }; auto l8 = [](decltype(l7) *derp = nullptr) { return 2; }; constexpr const char *l7_output = __builtin_sycl_unique_stable_name(decltype(l7)); // #USN_l7 - // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}} - // expected-note@#USN_l7{{'__builtin_sycl_unique_stable_name' evaluated here}} - // expected-note@+1{{in instantiation of function template specialization}} kernel_single_task(l8); - // kernel8 and kernel9 - expect error - // Tests that passing a lambda to the unique stable name builtin and passing it - // to a kernel called with an if constexpr branch causes a diagnostic on the - // kernel9 use due to the change in the results to the stable name. This happens - // even though the use of kernel9 happens in the false branch of a constexpr if - // because both the true and the false branches cause the instantiation of - // kernel_single_task. + // kernel8 and kernel9 - expect no error + // Tests that passing a lambda to the unique stable name builtin and passing + // it to a kernel called with an if constexpr branch does not cause a + // diagnostic on the kernel9 as it does not change the result to the stable + // name. This is interesting even though the use of kernel9 happens in the + // false branch of a constexpr if because both the true and the false branches + // cause the instantiation of kernel_single_task. auto l9 = []() { return 1; }; auto l10 = []() { return 2; }; constexpr const char *l10_output = @@ -134,9 +120,6 @@ if constexpr (1) { kernel_single_task(l9); } else { - // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}} - // expected-note@#USN_l10{{'__builtin_sycl_unique_stable_name' evaluated here}} - // expected-note@+1{{in instantiation of function template specialization}} kernel_single_task(l10); } @@ -151,26 +134,20 @@ __builtin_sycl_unique_stable_name(decltype(l11)); kernel_single_task(l12); - // kernel12 - expect an error + // kernel12 - expect no error // Test that passing a lambda to the unique stable name builtin and then - // passing it to the kernel as a template template parameter causes a + // passing it to the kernel as a template template parameter does not cause a // diagnostic on the kernel use due to template template parameter being // involved in the mangling of the kernel name. auto l13 = []() { return 1; }; constexpr const char *l13_output = __builtin_sycl_unique_stable_name(decltype(l13)); // #USN_l13 - // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}} - // expected-note@#USN_l13{{'__builtin_sycl_unique_stable_name' evaluated here}} - // expected-note@+1{{in instantiation of function template specialization}} kernel_single_task(S{}); - // kernel13 - expect an error + // kernel13 - expect no error // Test that passing a lambda to the unique stable name builtin within a macro - // and then calling the macro within the kernel causes an error on the kernel - // and diagnoses in all the expected places despite the use of a macro. - // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}} - // expected-note@#USN_MACRO{{'__builtin_sycl_unique_stable_name' evaluated here}} - // expected-note@+1{{in instantiation of function template specialization}} + // and then calling the macro within the kernel does not cause an error on the + // kernel. kernel_single_task( []() { MACRO(); // #USN_MACRO @@ -213,3 +190,15 @@ // expected-note@+1{{in instantiation of}} f2(); } + +// A previous implementation resulted in this being an example of the +// kernel-ordering and lexical lambda ordering issue. +void out_of_order_use() { + auto x = [](){}; + auto y = [](){}; + + kernel_single_task(y); + constexpr auto USN =__builtin_sycl_unique_stable_name(decltype(y)); + (void)USN; + kernel_single_task(x); +}