From d3edab452e0576eea3c8f84799b198fd449441cc Mon Sep 17 00:00:00 2001 From: Premanand M Rao Date: Wed, 20 Nov 2024 13:19:27 -0800 Subject: [PATCH 01/14] Prototype for registered_kernels --- clang/include/clang/Basic/Attr.td | 9 ++ .../clang/Basic/DiagnosticSemaKinds.td | 8 ++ clang/lib/Sema/SemaDeclAttr.cpp | 117 ++++++++++++++++++ 3 files changed, 134 insertions(+) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index fe8175fb249b4..1a10d040a1a97 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2141,6 +2141,15 @@ def SYCLAddIRAnnotationsMember : InheritableAttr { let Documentation = [SYCLAddIRAnnotationsMemberDocs]; } +def SYCLRegisteredKernels : InheritableAttr { + let Spellings = [CXX11<"__sycl_detail__", "__registered_kernels__">]; + let Args = [VariadicExprArgument<"Args">]; + let LangOpts = [SYCLIsDevice, SilentlyIgnoreSYCLIsHost]; + let Subjects = SubjectList<[Empty], ErrorDiag, "Translation Unit Scope">; + let AdditionalMembers = SYCLAddIRAttrCommonMembers.MemberCode; + let Documentation = [SYCLAddIRAnnotationsMemberDocs]; +} + def C11NoReturn : InheritableAttr { let Spellings = [CustomKeyword<"_Noreturn">]; let Subjects = SubjectList<[Function], ErrorDiag>; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 56226fa5bf4c7..43f930be11ab2 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12514,6 +12514,14 @@ def err_sycl_special_type_num_init_method : Error< def warn_launch_bounds_is_cuda_specific : Warning< "%0 attribute ignored, only applicable when targeting Nvidia devices">, InGroup; +def err_registered_kernels_num_of_args : Error< + "'__registered_kernels__' atribute must have at least one argument">; +def err_registered_kernels_init_list : Error< + "argument to the '__registered_kernels__' atribute must be an " + "initializer list expression">; +def err_registered_kernels_init_list_pair_values : Error< + "each initializer list argument to the '__registered_kernels__' atribute " + "must contain a pair of values">; def warn_cuda_maxclusterrank_sm_90 : Warning< "'maxclusterrank' requires sm_90 or higher, CUDA arch provided: %0, ignoring " diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 534d8e4e33a64..3c13e2780ac83 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5537,6 +5537,120 @@ static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D, PatchableFunctionEntryAttr(S.Context, AL, Count, Offset)); } +extern void ConstructFreeFunctionKernel(SemaSYCL &SemaSYCLRef, FunctionDecl *FD); + +static void handleSYCLRegisteredKernels(Sema &S, Decl *D, const ParsedAttr &A) { + unsigned NumArgs = A.getNumArgs(); + if (NumArgs == 0) { + S.Diag(A.getLoc(), diag::err_registered_kernels_num_of_args); + return; + } + + for (unsigned I = 0; I < NumArgs; I++) { + assert(A.isArgExpr(I) && "Expected expression argument"); + Expr *ArgExpr = A.getArgAsExpr(I); + if (!isa(ArgExpr)) { + S.Diag(ArgExpr->getExprLoc(), diag::err_registered_kernels_init_list); + return; + } + + const auto *ArgListE = cast(ArgExpr); + unsigned NumInits = ArgListE->getNumInits(); + if (NumInits != 2) { + S.Diag(ArgExpr->getExprLoc(), + diag::err_registered_kernels_init_list_pair_values); + return; + } + + const Expr *FirstE = ArgListE->getInit(0); + QualType Ty = FirstE->getType(); + StringRef CurStr; + SourceLocation Loc = FirstE->getExprLoc(); + if (!S.checkStringLiteralArgumentAttr(A, FirstE, CurStr, &Loc)) + return; + else + printf("Found %s\n", CurStr.str().c_str()); + + auto *SecondE = const_cast(ArgListE->getInit(1)); +printf("Dumping\n"); +SecondE->dump(); + if (auto *ULE = dyn_cast(SecondE)) { + FunctionDecl *FD = S.ResolveSingleFunctionTemplateSpecialization( + ULE, true); + if (FD) { + if (FD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) +printf("Case 1 TKNT\n"); + if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplateSpecialization) +printf("Case 2 FTS\n"); + } else { + printf("Null FD\n"); + ULE->dump(); + } + S.InstantiateFunctionDefinition(A.getLoc(), FD); + } else { + FunctionDecl *FD = nullptr; + DeclRefExpr *DRE = nullptr; + if (isa(SecondE)) { +// SecondE->dump(); + Expr *E = cast(SecondE)->getSubExprAsWritten(); + if (E->getType()->isFunctionType()) { + printf("FT\n"); + DRE = dyn_cast(E); + } + } else { + DRE = dyn_cast(SecondE); + } + if (DRE && isa(DRE->getDecl())) { + printf("FD\n"); + FD = cast(DRE->getDecl()); + } + if (FD) { + FD->dump(); + //ConstructFreeFunctionKernel(S.SYCL(), FD); + + if (FD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) + printf("Case TKNT\n"); + } else { + SecondE->dump(); + printf("failed\n"); + } + } + +#if 0 + for (Expr *FilterElemE : cast(ArgExpr)->inits()) { + printf("Processing elem %u\n", I); + auto *ULE = dyn_cast(FilterElemE); + if (ULE) { + FunctionDecl *FD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true); + S.InstantiateFunctionDefinition(A.getLoc(), FD); +// FD->dump(); + } else if (isa(FilterElemE)) { + Expr *E = dyn_cast(FilterElemE)->getSubExprAsWritten(); + //FilterElemE->dump(); + FunctionDecl *FD = nullptr; + DeclRefExpr *DRE = nullptr; + if (E->getType()->isFunctionType()) { + printf("FT\n"); + DRE = dyn_cast(E); + } + if (DRE && isa(DRE->getDecl())) { + printf("FD\n"); + FD = dyn_cast(DRE->getDecl()); + } + if (FD) + FD->dump(); + else { + FilterElemE->dump(); + printf("failed\n"); + } + } + +// FilterElemE->dump(); + } +#endif + } +} + static bool SYCLAliasValid(ASTContext &Context, unsigned BuiltinID) { constexpr llvm::StringLiteral Prefix = "__builtin_intel_sycl"; return Context.BuiltinInfo.getName(BuiltinID).starts_with(Prefix); @@ -7424,6 +7538,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_SYCLAddIRAnnotationsMember: S.SYCL().handleSYCLAddIRAnnotationsMemberAttr(D, AL); break; + case ParsedAttr::AT_SYCLRegisteredKernels: + handleSYCLRegisteredKernels(S, D, AL); + break; // Swift attributes. case ParsedAttr::AT_SwiftAsyncName: From 70caead80f82560feab37fd31e0aa758b231d6e0 Mon Sep 17 00:00:00 2001 From: Premanand M Rao Date: Thu, 26 Dec 2024 21:10:41 -0800 Subject: [PATCH 02/14] [SYCL] Add support for __registered_kernels__ This change adds support for a new attribute __sycl_detail::__registered_kernels__, which appears at translation unit scope. The parameter for this attribute is a list of pairs like: `` [[__sycl_detail__::__registered_kernels__( {"foo", foo}, {"(void(*)(int, int*))iota", (void(*)(int, int*))iota}, {"kernel", kernel} )]]; `` The first element in each pair is a string, and the second element is a constant expressiton for a pointer to a SYCL free function kernel. The change creates the kernel's wrapper function and generates module-level metadata of the form: `` !sycl_registered_kernels = !{!0, !1} !0 = !{!"foo", !"mangled-name-of-wrapper-for-foo"} !1 = !{!"kernel", !"mangled-name-of-wrapper-for-kernel"} `` wherre the first element in the pair of strings, is the first element of the pair in __registered_kernels__ and the second element is the mangled named of the wrapper corresponding to the free function. --- clang/include/clang/Basic/Attr.td | 7 + .../clang/Basic/DiagnosticSemaKinds.td | 6 + clang/include/clang/Sema/SemaSYCL.h | 11 +- clang/lib/CodeGen/CodeGenFunction.cpp | 6 + clang/lib/CodeGen/CodeGenModule.cpp | 12 ++ clang/lib/CodeGen/CodeGenModule.h | 9 ++ clang/lib/Sema/SemaDeclAttr.cpp | 131 +++++++----------- clang/lib/Sema/SemaSYCL.cpp | 62 +++++++-- .../CodeGenSYCL/registered-kernel-names.cpp | 72 ++++++++++ .../test/SemaSYCL/registered-kernel-names.cpp | 71 ++++++++++ 10 files changed, 294 insertions(+), 93 deletions(-) create mode 100644 clang/test/CodeGenSYCL/registered-kernel-names.cpp create mode 100644 clang/test/SemaSYCL/registered-kernel-names.cpp diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 1a10d040a1a97..b4014a122155c 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2150,6 +2150,13 @@ def SYCLRegisteredKernels : InheritableAttr { let Documentation = [SYCLAddIRAnnotationsMemberDocs]; } +def SYCLRegisteredKernelName : InheritableAttr { + let Spellings = []; + let Subjects = SubjectList<[Function]>; + let Args = [StringArgument<"RegName">]; + let Documentation = [InternalOnly]; +} + def C11NoReturn : InheritableAttr { let Spellings = [CustomKeyword<"_Noreturn">]; let Subjects = SubjectList<[Function], ErrorDiag>; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 43f930be11ab2..d93883d3b1b17 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12522,6 +12522,12 @@ def err_registered_kernels_init_list : Error< def err_registered_kernels_init_list_pair_values : Error< "each initializer list argument to the '__registered_kernels__' atribute " "must contain a pair of values">; +def err_registered_kernels_resolve_function : Error< + "unable to resolve free function kernel '%0'">; +def err_registered_kernels_name_already_registered : Error< + "free function kernel has already been registered with '%0'; cannot register with '%1'">; +def err_not_sycl_free_function : Error< + "attempting to register a function that is not a SYCL free function as '%0'">; def warn_cuda_maxclusterrank_sm_90 : Warning< "'maxclusterrank' requires sm_90 or higher, CUDA arch provided: %0, ignoring " diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index 63880d7438522..954eeae5a716c 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -252,8 +252,9 @@ class SemaSYCL : public SemaBase { // We need to store the list of the sycl_kernel functions and their associated // generated OpenCL Kernels so we can go back and re-name these after the // fact. - llvm::SmallVector> - SyclKernelsToOpenCLKernels; + using KernelFDPairs = llvm::SmallVector< + std::pair>; + KernelFDPairs SyclKernelsToOpenCLKernels; // Used to suppress diagnostics during kernel construction, since these were // already emitted earlier. Diagnosing during Kernel emissions also skips the @@ -296,11 +297,17 @@ class SemaSYCL : public SemaBase { llvm::DenseSet Visited, ValueDecl *DeclToCheck); + const KernelFDPairs &getKernelFDPairs() { + return SyclKernelsToOpenCLKernels; + } + void addSyclOpenCLKernel(const FunctionDecl *SyclKernel, FunctionDecl *OpenCLKernel) { SyclKernelsToOpenCLKernels.emplace_back(SyclKernel, OpenCLKernel); } + void constructFreeFunctionKernel(FunctionDecl *FD, StringRef NameStr = ""); + void addSyclDeviceDecl(Decl *d) { SyclDeviceDecls.insert(d); } llvm::SetVector &syclDeviceDecls() { return SyclDeviceDecls; } diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 40a6b1b8b3395..1dc61da430e3f 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -641,6 +641,12 @@ void CodeGenFunction::EmitKernelMetadata(const FunctionDecl *FD, llvm::LLVMContext &Context = getLLVMContext(); + if (getLangOpts().SYCLIsDevice) + if (FD->hasAttr()) + CGM.SYCLAddRegKernelNamePairs( + FD->getAttr()->getRegName(), + FD->getNameAsString()); + if (FD->hasAttr() || FD->hasAttr()) CGM.GenKernelArgMetadata(Fn, FD, this); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 4d18be3ebb55b..009c6b93bbdf4 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1427,6 +1427,18 @@ void CodeGenModule::Release() { AspectEnumValsMD->addOperand( getAspectEnumValueMD(Context, TheModule.getContext(), ECD)); } + + if (!SYCLRegKernelNames.empty()) { + std::vector Nodes; + for (auto MDKernelNames: SYCLRegKernelNames) { + llvm::Metadata *Vals[] = {MDKernelNames.first, MDKernelNames.second}; + Nodes.push_back(llvm::MDTuple::get(TheModule.getContext(), Vals)); + } + + getModule().addModuleFlag( + llvm::Module::Append, "sycl_registered_kernels", + llvm::MDTuple::get(TheModule.getContext(), Nodes)); + } } // HLSL related end of code gen work items. diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index f0646394e62af..851cc39371955 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -456,6 +456,9 @@ class CodeGenModule : public CodeGenTypeCache { /// handled differently than regular annotations so they cannot share map. llvm::DenseMap SYCLAnnotationArgs; + typedef std::pair MetadataPair; + SmallVector SYCLRegKernelNames; + llvm::StringMap CFConstantStringMap; llvm::DenseMap ConstantStringMap; @@ -1483,6 +1486,12 @@ class CodeGenModule : public CodeGenTypeCache { llvm::Constant *EmitSYCLAnnotationArgs( SmallVectorImpl> &Pairs); + void SYCLAddRegKernelNamePairs(StringRef First, StringRef Second) { + SYCLRegKernelNames.push_back(std::make_pair( + llvm::MDString::get(getLLVMContext(), First), + llvm::MDString::get(getLLVMContext(), Second))); + } + /// Add attributes from add_ir_attributes_global_variable on TND to GV. void AddGlobalSYCLIRAttributes(llvm::GlobalVariable *GV, const RecordDecl *RD); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 3c13e2780ac83..30919f0c51b3d 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5537,117 +5537,84 @@ static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D, PatchableFunctionEntryAttr(S.Context, AL, Count, Offset)); } -extern void ConstructFreeFunctionKernel(SemaSYCL &SemaSYCLRef, FunctionDecl *FD); +static bool isFreeFunctionKernel(Sema &S, FunctionDecl *FD) { + /* If it does not have the attribute, return false. */ + if (!FD->hasAttr()) + return false; + /* If it does, traverse through the pairs and return true, if + it is one of the two free function types. */ + auto *SAIRAttr = FD->getAttr(); + SmallVector, 4> NameValuePairs = + SAIRAttr->getFilteredAttributeNameValuePairs(S.Context); + for (const auto &NVPair : NameValuePairs) { + if (!NVPair.first.compare("sycl-single-task-kernel") || + !NVPair.first.compare("sycl-nd-range-kernel")) + return true; + } + /* If it does not have free function attributes, return false. */ + return false; +} static void handleSYCLRegisteredKernels(Sema &S, Decl *D, const ParsedAttr &A) { unsigned NumArgs = A.getNumArgs(); + /* When declared, we expect at least one item in the list. */ if (NumArgs == 0) { S.Diag(A.getLoc(), diag::err_registered_kernels_num_of_args); return; } + /* Traverse through the items in the list. */ for (unsigned I = 0; I < NumArgs; I++) { assert(A.isArgExpr(I) && "Expected expression argument"); + /* Each item in the list must be an initializer list expression. */ Expr *ArgExpr = A.getArgAsExpr(I); if (!isa(ArgExpr)) { S.Diag(ArgExpr->getExprLoc(), diag::err_registered_kernels_init_list); return; } - + const auto *ArgListE = cast(ArgExpr); unsigned NumInits = ArgListE->getNumInits(); + /* Each init-list expression must have a pair of values. */ if (NumInits != 2) { S.Diag(ArgExpr->getExprLoc(), diag::err_registered_kernels_init_list_pair_values); return; } - const Expr *FirstE = ArgListE->getInit(0); - QualType Ty = FirstE->getType(); + /* The first value of the pair muse be a string. */ + const Expr *FirstExpr = ArgListE->getInit(0); StringRef CurStr; - SourceLocation Loc = FirstE->getExprLoc(); - if (!S.checkStringLiteralArgumentAttr(A, FirstE, CurStr, &Loc)) + SourceLocation Loc = FirstExpr->getExprLoc(); + if (!S.checkStringLiteralArgumentAttr(A, FirstExpr, CurStr, &Loc)) return; - else - printf("Found %s\n", CurStr.str().c_str()); + /* Resolve the FunctionDecl from the second value of the pair. */ auto *SecondE = const_cast(ArgListE->getInit(1)); -printf("Dumping\n"); -SecondE->dump(); + FunctionDecl *FD = nullptr; if (auto *ULE = dyn_cast(SecondE)) { - FunctionDecl *FD = S.ResolveSingleFunctionTemplateSpecialization( - ULE, true); - if (FD) { - if (FD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) -printf("Case 1 TKNT\n"); - if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplateSpecialization) -printf("Case 2 FTS\n"); - } else { - printf("Null FD\n"); - ULE->dump(); - } - S.InstantiateFunctionDefinition(A.getLoc(), FD); - } else { - FunctionDecl *FD = nullptr; - DeclRefExpr *DRE = nullptr; - if (isa(SecondE)) { -// SecondE->dump(); - Expr *E = cast(SecondE)->getSubExprAsWritten(); - if (E->getType()->isFunctionType()) { - printf("FT\n"); - DRE = dyn_cast(E); - } - } else { - DRE = dyn_cast(SecondE); - } - if (DRE && isa(DRE->getDecl())) { - printf("FD\n"); - FD = cast(DRE->getDecl()); - } - if (FD) { - FD->dump(); - //ConstructFreeFunctionKernel(S.SYCL(), FD); - - if (FD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) - printf("Case TKNT\n"); - } else { - SecondE->dump(); - printf("failed\n"); - } - } - -#if 0 - for (Expr *FilterElemE : cast(ArgExpr)->inits()) { - printf("Processing elem %u\n", I); - auto *ULE = dyn_cast(FilterElemE); - if (ULE) { - FunctionDecl *FD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true); - S.InstantiateFunctionDefinition(A.getLoc(), FD); -// FD->dump(); - } else if (isa(FilterElemE)) { - Expr *E = dyn_cast(FilterElemE)->getSubExprAsWritten(); - //FilterElemE->dump(); - FunctionDecl *FD = nullptr; - DeclRefExpr *DRE = nullptr; - if (E->getType()->isFunctionType()) { - printf("FT\n"); - DRE = dyn_cast(E); - } - if (DRE && isa(DRE->getDecl())) { - printf("FD\n"); - FD = dyn_cast(DRE->getDecl()); - } - if (FD) - FD->dump(); - else { - FilterElemE->dump(); - printf("failed\n"); - } - } - -// FilterElemE->dump(); + FD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true); + Loc = ULE->getExprLoc(); + } else { + while (isa(SecondE)) + SecondE = cast(SecondE)->getSubExpr(); + auto *DRE = dyn_cast(SecondE); + if (DRE) + FD = dyn_cast(DRE->getDecl()); + Loc = SecondE->getExprLoc(); + } + /* Issue a diagnostic if we are unable to resolve the FunctionDecl. */ + if (!FD) { + S.Diag(Loc, diag::err_registered_kernels_resolve_function) << CurStr; + return; } -#endif + /* Issue a diagnostic is the FunctionDecl is not a SYCL free function. */ + if (!isFreeFunctionKernel(S, FD)) { + S.Diag(FD->getLocation(), diag::err_not_sycl_free_function) << CurStr; + return; + } + /* Construct a free function kernel. */ + S.SYCL().constructFreeFunctionKernel(FD, CurStr); } } diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 1853a744ab2fa..18f05c3710822 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -5414,24 +5414,68 @@ void SemaSYCL::ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, } } -void ConstructFreeFunctionKernel(SemaSYCL &SemaSYCLRef, FunctionDecl *FD) { - SyclKernelArgsSizeChecker argsSizeChecker(SemaSYCLRef, FD->getLocation(), +static void addRegisteredKernelName(SemaSYCL &S, StringRef Str, + FunctionDecl *FD, SourceLocation Loc) { + if (!Str.empty()) { + FD->addAttr(SYCLRegisteredKernelNameAttr::CreateImplicit( + S.getASTContext(), Str, Loc)); + } +} + +static bool checkAndAddRegisteredKernelName(SemaSYCL &S, FunctionDecl *FD, + StringRef Str) { + using KernelPair = std::pair; + for (const KernelPair &Pair : S.getKernelFDPairs()) + if (Pair.first == FD) { + // If the current list of free function entries already contain this + // free function, apply the name Str as an attribute. But if it already + // has an attribute name, issue a diagnostic instead. + if (!Str.empty()) { + if (!Pair.second->hasAttr()) + addRegisteredKernelName(S, Str, Pair.second, FD->getLocation()); + else + S.Diag(FD->getLocation(), + diag::err_registered_kernels_name_already_registered) + << Pair.second->getAttr()-> + getRegName() + << Str; + } + // An empty name string implies a regular free kernel construction + // call, so simply return. + return false; + } + return true; +} + +void SemaSYCL::constructFreeFunctionKernel(FunctionDecl *FD, + StringRef NameStr) { + if (!checkAndAddRegisteredKernelName(*this, FD, NameStr)) + return; + + SyclKernelArgsSizeChecker argsSizeChecker(*this, FD->getLocation(), false /*IsSIMDKernel*/); - SyclKernelDeclCreator kernel_decl(SemaSYCLRef, FD->getLocation(), + SyclKernelDeclCreator kernel_decl(*this, FD->getLocation(), FD->isInlined(), false /*IsSIMDKernel */, FD); - FreeFunctionKernelBodyCreator kernel_body(SemaSYCLRef, kernel_decl, FD); + FreeFunctionKernelBodyCreator kernel_body(*this, kernel_decl, FD); SyclKernelIntHeaderCreator int_header( - SemaSYCLRef, SemaSYCLRef.getSyclIntegrationHeader(), FD->getType(), FD); + *this, getSyclIntegrationHeader(), FD->getType(), FD); - SyclKernelIntFooterCreator int_footer(SemaSYCLRef, - SemaSYCLRef.getSyclIntegrationFooter()); - KernelObjVisitor Visitor{SemaSYCLRef}; + SyclKernelIntFooterCreator int_footer(*this, + getSyclIntegrationFooter()); + KernelObjVisitor Visitor{*this}; Visitor.VisitFunctionParameters(FD, argsSizeChecker, kernel_decl, kernel_body, int_header, int_footer); + + assert(getKernelFDPairs().back().first == FD && + "OpenCL Kernel not found for free function entry"); + // Register the kernel name with the OpenCL kernel generated for the + // free function. + addRegisteredKernelName(*this, NameStr, getKernelFDPairs().back().second, + FD->getLocation()); } // Figure out the sub-group for the this function. First we check the @@ -5736,7 +5780,7 @@ void SemaSYCL::ProcessFreeFunction(FunctionDecl *FD) { if (!FieldChecker.isValid() || !UnionChecker.isValid()) return; - ConstructFreeFunctionKernel(*this, FD); + constructFreeFunctionKernel(FD); } } diff --git a/clang/test/CodeGenSYCL/registered-kernel-names.cpp b/clang/test/CodeGenSYCL/registered-kernel-names.cpp new file mode 100644 index 0000000000000..37a3577c7fe39 --- /dev/null +++ b/clang/test/CodeGenSYCL/registered-kernel-names.cpp @@ -0,0 +1,72 @@ +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -o - %s | FileCheck %s + +// This test checks if the sycl_registered_kernels module flag and +// associated entries are generated for registered kernel names. + +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void foo() { +} + +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-nd-range-kernel", 0)]] +void ff_4() { +} + +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void iota(int, int *) { +} + +template +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void tempfoo(T pt); + +template +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void tempfoo2(T pt) { + T t; +} + +template void tempfoo2(int); + +template <> +void tempfoo2(float f); + +template <> +void tempfoo2(short) { } + +template +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void tempfoo3() { + (void)N; +} + +namespace N { +[[__sycl_detail__::__registered_kernels__( + {"foo", foo}, + {"iota", (void(*)(int, int *))iota}, + {"decl temp", tempfoo}, + {"inst temp", tempfoo2}, + {"decl spec", tempfoo2}, + {"def spec", tempfoo2}, + {"foo3", ff_4}, + {"nontype", tempfoo3<5>} +)]]; +} + +// Check for the presence of sycl-device module flag in device +// compilations and its absence in host compilations. +// CHECK: !{{[0-9]+}} = !{i32 5, !"sycl_registered_kernels", ![[LIST:[0-9]+]]} +// CHECK: ![[LIST]] = !{![[ENT1:[0-9]+]], ![[ENT2:[0-9]+]], ![[ENT3:[0-9]+]], ![[ENT4:[0-9]+]], ![[ENT5:[0-9]+]], ![[ENT6:[0-9]+]], ![[ENT7:[0-9]+]], ![[ENT8:[0-9]+]]} +// CHECK: ![[ENT1]] = !{!"foo", !"{{.*}}sycl_kernel{{.*}}foo{{.*}}"} +// CHECK: ![[ENT2]] = !{!"foo3", !"{{.*}}sycl_kernel{{.*}}ff_4{{.*}}"} +// CHECK: ![[ENT3]] = !{!"iota", !"{{.*}}sycl_kernel{{.*}}iota{{.*}}"} +// CHECK: ![[ENT4]] = !{!"inst temp", !"{{.*}}sycl_kernel{{.*}}tempfoo2{{.*}}"} +// CHECK: ![[ENT5]] = !{!"def spec", !"{{.*}}sycl_kernel{{.*}}tempfoo2{{.*}}"} +// CHECK: ![[ENT6]] = !{!"decl temp", !"{{.*}}sycl_kernel{{.*}}tempfoo{{.*}}"} +// CHECK: ![[ENT7]] = !{!"decl spec", !"{{.*}}sycl_kernel{{.*}}tempfoo2{{.*}}"} +// CHECK: ![[ENT8]] = !{!"nontype", !"{{.*}}sycl_kernel{{.*}}tempfoo3{{.*}}"} diff --git a/clang/test/SemaSYCL/registered-kernel-names.cpp b/clang/test/SemaSYCL/registered-kernel-names.cpp new file mode 100644 index 0000000000000..0e0d5ed358214 --- /dev/null +++ b/clang/test/SemaSYCL/registered-kernel-names.cpp @@ -0,0 +1,71 @@ +// RUN: %clang_cc1 -fsycl-is-device -fsyntax-only -verify -pedantic %s + +// The test checks issuing diagnostics for registered kernel names. + +// expected-error@+1 {{attempting to register a function that is not a SYCL free function as 'kernelnamefoo'}} +void foo(); + +constexpr const char *str = "foo"; + +// expected-error@+1 {{'__registered_kernels__' atribute must have at least one argument}} +[[__sycl_detail__::__registered_kernels__( +)]]; + +// expected-error@+2 {{argument to the '__registered_kernels__' atribute must be an initializer list expression}} +[[__sycl_detail__::__registered_kernels__( + 1 +)]]; + +// expected-error@+2 {{each initializer list argument to the '__registered_kernels__' atribute must contain a pair of values}} +[[__sycl_detail__::__registered_kernels__( + {} +)]]; + +// expected-error@+2 {{each initializer list argument to the '__registered_kernels__' atribute must contain a pair of values}} +[[__sycl_detail__::__registered_kernels__( + { "foo" } +)]]; + +// expected-error@+2 {{unable to resolve free function kernel 'foo'}} +[[__sycl_detail__::__registered_kernels__( + { "foo", "foo" } +)]]; + +// expected-error@+2 {{'__registered_kernels__' attribute requires a string}} +[[__sycl_detail__::__registered_kernels__( + { str, 1 } +)]]; + +// expected-error@+2 {{each initializer list argument to the '__registered_kernels__' atribute must contain a pair of values}} +[[__sycl_detail__::__registered_kernels__( + { "foo", 1, foo } +)]]; + +template +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void func(); + +namespace N { +[[__sycl_detail__::__registered_kernels__( + {"kernelnamefoo", foo} +)]]; +} + +// expected-error@+3 {{unable to resolve free function kernel 'func'}} +namespace { +[[__sycl_detail__::__registered_kernels__( + {"func", func} +)]]; +} + +// expected-error@+3 {{free function kernel has already been registered with 'reg1'; cannot register with 'reg2'}} +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void good() { +} + +[[__sycl_detail__::__registered_kernels__( + {"reg1", good}, + {"reg2", good} +)]]; From f447b828a818b7705b7af8b14c98b4cd1368c142 Mon Sep 17 00:00:00 2001 From: Premanand M Rao Date: Thu, 26 Dec 2024 21:49:23 -0800 Subject: [PATCH 03/14] Resolve merge conflicts --- clang/include/clang/Sema/SemaSYCL.h | 1 + clang/lib/Sema/SemaDeclAttr.cpp | 83 +----------------- clang/lib/Sema/SemaSYCLDeclAttr.cpp | 85 +++++++++++++++++++ .../CodeGenSYCL/registered-kernel-names.cpp | 2 +- 4 files changed, 88 insertions(+), 83 deletions(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index 954eeae5a716c..627542355175b 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -487,6 +487,7 @@ class SemaSYCL : public SemaBase { void handleSYCLIntelMaxWorkGroupsPerMultiprocessor(Decl *D, const ParsedAttr &AL); void handleSYCLScopeAttr(Decl *D, const ParsedAttr &AL); + void handleSYCLRegisteredKernels(Decl *D, const ParsedAttr &AL); void checkSYCLAddIRAttributesFunctionAttrConflicts(Decl *D); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 30919f0c51b3d..dfb8f90461d7f 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5537,87 +5537,6 @@ static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D, PatchableFunctionEntryAttr(S.Context, AL, Count, Offset)); } -static bool isFreeFunctionKernel(Sema &S, FunctionDecl *FD) { - /* If it does not have the attribute, return false. */ - if (!FD->hasAttr()) - return false; - /* If it does, traverse through the pairs and return true, if - it is one of the two free function types. */ - auto *SAIRAttr = FD->getAttr(); - SmallVector, 4> NameValuePairs = - SAIRAttr->getFilteredAttributeNameValuePairs(S.Context); - for (const auto &NVPair : NameValuePairs) { - if (!NVPair.first.compare("sycl-single-task-kernel") || - !NVPair.first.compare("sycl-nd-range-kernel")) - return true; - } - /* If it does not have free function attributes, return false. */ - return false; -} - -static void handleSYCLRegisteredKernels(Sema &S, Decl *D, const ParsedAttr &A) { - unsigned NumArgs = A.getNumArgs(); - /* When declared, we expect at least one item in the list. */ - if (NumArgs == 0) { - S.Diag(A.getLoc(), diag::err_registered_kernels_num_of_args); - return; - } - - /* Traverse through the items in the list. */ - for (unsigned I = 0; I < NumArgs; I++) { - assert(A.isArgExpr(I) && "Expected expression argument"); - /* Each item in the list must be an initializer list expression. */ - Expr *ArgExpr = A.getArgAsExpr(I); - if (!isa(ArgExpr)) { - S.Diag(ArgExpr->getExprLoc(), diag::err_registered_kernels_init_list); - return; - } - - const auto *ArgListE = cast(ArgExpr); - unsigned NumInits = ArgListE->getNumInits(); - /* Each init-list expression must have a pair of values. */ - if (NumInits != 2) { - S.Diag(ArgExpr->getExprLoc(), - diag::err_registered_kernels_init_list_pair_values); - return; - } - - /* The first value of the pair muse be a string. */ - const Expr *FirstExpr = ArgListE->getInit(0); - StringRef CurStr; - SourceLocation Loc = FirstExpr->getExprLoc(); - if (!S.checkStringLiteralArgumentAttr(A, FirstExpr, CurStr, &Loc)) - return; - - /* Resolve the FunctionDecl from the second value of the pair. */ - auto *SecondE = const_cast(ArgListE->getInit(1)); - FunctionDecl *FD = nullptr; - if (auto *ULE = dyn_cast(SecondE)) { - FD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true); - Loc = ULE->getExprLoc(); - } else { - while (isa(SecondE)) - SecondE = cast(SecondE)->getSubExpr(); - auto *DRE = dyn_cast(SecondE); - if (DRE) - FD = dyn_cast(DRE->getDecl()); - Loc = SecondE->getExprLoc(); - } - /* Issue a diagnostic if we are unable to resolve the FunctionDecl. */ - if (!FD) { - S.Diag(Loc, diag::err_registered_kernels_resolve_function) << CurStr; - return; - } - /* Issue a diagnostic is the FunctionDecl is not a SYCL free function. */ - if (!isFreeFunctionKernel(S, FD)) { - S.Diag(FD->getLocation(), diag::err_not_sycl_free_function) << CurStr; - return; - } - /* Construct a free function kernel. */ - S.SYCL().constructFreeFunctionKernel(FD, CurStr); - } -} - static bool SYCLAliasValid(ASTContext &Context, unsigned BuiltinID) { constexpr llvm::StringLiteral Prefix = "__builtin_intel_sycl"; return Context.BuiltinInfo.getName(BuiltinID).starts_with(Prefix); @@ -7506,7 +7425,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, S.SYCL().handleSYCLAddIRAnnotationsMemberAttr(D, AL); break; case ParsedAttr::AT_SYCLRegisteredKernels: - handleSYCLRegisteredKernels(S, D, AL); + S.SYCL().handleSYCLRegisteredKernels(D, AL); break; // Swift attributes. diff --git a/clang/lib/Sema/SemaSYCLDeclAttr.cpp b/clang/lib/Sema/SemaSYCLDeclAttr.cpp index c2268d9f35b14..c4b63fc085bcc 100644 --- a/clang/lib/Sema/SemaSYCLDeclAttr.cpp +++ b/clang/lib/Sema/SemaSYCLDeclAttr.cpp @@ -3162,3 +3162,88 @@ void SemaSYCL::checkSYCLAddIRAttributesFunctionAttrConflicts(Decl *D) { Diag(Attr->getLoc(), diag::warn_sycl_old_and_new_kernel_attributes) << Attr; } + +static bool isFreeFunctionKernel(SemaSYCL &S, FunctionDecl *FD) { + /* If it does not have the attribute, return false. */ + if (!FD->hasAttr()) + return false; + /* If it does, traverse through the pairs and return true, if + it is one of the two free function types. */ + auto *SAIRAttr = FD->getAttr(); + SmallVector, 4> NameValuePairs = + SAIRAttr->getFilteredAttributeNameValuePairs(S.getASTContext()); + for (const auto &NVPair : NameValuePairs) { + if (!NVPair.first.compare("sycl-single-task-kernel") || + !NVPair.first.compare("sycl-nd-range-kernel")) + return true; + } + /* If it does not have free function attributes, return false. */ + return false; +} + +void SemaSYCL::handleSYCLRegisteredKernels(Decl *D, const ParsedAttr &A) { + // Check for SYCL device compilation context. + if (!getLangOpts().SYCLIsDevice) + return; + + unsigned NumArgs = A.getNumArgs(); + /* When declared, we expect at least one item in the list. */ + if (NumArgs == 0) { + Diag(A.getLoc(), diag::err_registered_kernels_num_of_args); + return; + } + + /* Traverse through the items in the list. */ + for (unsigned I = 0; I < NumArgs; I++) { + assert(A.isArgExpr(I) && "Expected expression argument"); + /* Each item in the list must be an initializer list expression. */ + Expr *ArgExpr = A.getArgAsExpr(I); + if (!isa(ArgExpr)) { + Diag(ArgExpr->getExprLoc(), diag::err_registered_kernels_init_list); + return; + } + + const auto *ArgListE = cast(ArgExpr); + unsigned NumInits = ArgListE->getNumInits(); + /* Each init-list expression must have a pair of values. */ + if (NumInits != 2) { + Diag(ArgExpr->getExprLoc(), + diag::err_registered_kernels_init_list_pair_values); + return; + } + + /* The first value of the pair muse be a string. */ + const Expr *FirstExpr = ArgListE->getInit(0); + StringRef CurStr; + SourceLocation Loc = FirstExpr->getExprLoc(); + if (!SemaRef.checkStringLiteralArgumentAttr(A, FirstExpr, CurStr, &Loc)) + return; + + /* Resolve the FunctionDecl from the second value of the pair. */ + auto *SecondE = const_cast(ArgListE->getInit(1)); + FunctionDecl *FD = nullptr; + if (auto *ULE = dyn_cast(SecondE)) { + FD = SemaRef.ResolveSingleFunctionTemplateSpecialization(ULE, true); + Loc = ULE->getExprLoc(); + } else { + while (isa(SecondE)) + SecondE = cast(SecondE)->getSubExpr(); + auto *DRE = dyn_cast(SecondE); + if (DRE) + FD = dyn_cast(DRE->getDecl()); + Loc = SecondE->getExprLoc(); + } + /* Issue a diagnostic if we are unable to resolve the FunctionDecl. */ + if (!FD) { + Diag(Loc, diag::err_registered_kernels_resolve_function) << CurStr; + return; + } + /* Issue a diagnostic is the FunctionDecl is not a SYCL free function. */ + if (!isFreeFunctionKernel(*this, FD)) { + Diag(FD->getLocation(), diag::err_not_sycl_free_function) << CurStr; + return; + } + /* Construct a free function kernel. */ + constructFreeFunctionKernel(FD, CurStr); + } +} diff --git a/clang/test/CodeGenSYCL/registered-kernel-names.cpp b/clang/test/CodeGenSYCL/registered-kernel-names.cpp index 37a3577c7fe39..54adc545feca9 100644 --- a/clang/test/CodeGenSYCL/registered-kernel-names.cpp +++ b/clang/test/CodeGenSYCL/registered-kernel-names.cpp @@ -27,7 +27,7 @@ template __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] void tempfoo2(T pt) { - T t; + T t; } template void tempfoo2(int); From d81e489e25925558978a51cd28508ccf1e2825af Mon Sep 17 00:00:00 2001 From: Premanand M Rao Date: Thu, 26 Dec 2024 22:21:17 -0800 Subject: [PATCH 04/14] Fix clang-format issues --- clang/include/clang/Sema/SemaSYCL.h | 8 +++----- clang/lib/CodeGen/CodeGenModule.cpp | 2 +- clang/lib/CodeGen/CodeGenModule.h | 6 +++--- clang/lib/Sema/SemaSYCL.cpp | 24 +++++++++++------------- clang/lib/Sema/SemaSYCLDeclAttr.cpp | 2 +- 5 files changed, 19 insertions(+), 23 deletions(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index 627542355175b..340500a78e514 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -252,8 +252,8 @@ class SemaSYCL : public SemaBase { // We need to store the list of the sycl_kernel functions and their associated // generated OpenCL Kernels so we can go back and re-name these after the // fact. - using KernelFDPairs = llvm::SmallVector< - std::pair>; + using KernelFDPairs = + llvm::SmallVector>; KernelFDPairs SyclKernelsToOpenCLKernels; // Used to suppress diagnostics during kernel construction, since these were @@ -297,9 +297,7 @@ class SemaSYCL : public SemaBase { llvm::DenseSet Visited, ValueDecl *DeclToCheck); - const KernelFDPairs &getKernelFDPairs() { - return SyclKernelsToOpenCLKernels; - } + const KernelFDPairs &getKernelFDPairs() { return SyclKernelsToOpenCLKernels; } void addSyclOpenCLKernel(const FunctionDecl *SyclKernel, FunctionDecl *OpenCLKernel) { diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 009c6b93bbdf4..5f27b5e41082e 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1430,7 +1430,7 @@ void CodeGenModule::Release() { if (!SYCLRegKernelNames.empty()) { std::vector Nodes; - for (auto MDKernelNames: SYCLRegKernelNames) { + for (auto MDKernelNames : SYCLRegKernelNames) { llvm::Metadata *Vals[] = {MDKernelNames.first, MDKernelNames.second}; Nodes.push_back(llvm::MDTuple::get(TheModule.getContext(), Vals)); } diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 851cc39371955..2bdc62ae0b052 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1487,9 +1487,9 @@ class CodeGenModule : public CodeGenTypeCache { SmallVectorImpl> &Pairs); void SYCLAddRegKernelNamePairs(StringRef First, StringRef Second) { - SYCLRegKernelNames.push_back(std::make_pair( - llvm::MDString::get(getLLVMContext(), First), - llvm::MDString::get(getLLVMContext(), Second))); + SYCLRegKernelNames.push_back( + std::make_pair(llvm::MDString::get(getLLVMContext(), First), + llvm::MDString::get(getLLVMContext(), Second))); } /// Add attributes from add_ir_attributes_global_variable on TND to GV. diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 18f05c3710822..d890e890990a7 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -5417,8 +5417,8 @@ void SemaSYCL::ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, static void addRegisteredKernelName(SemaSYCL &S, StringRef Str, FunctionDecl *FD, SourceLocation Loc) { if (!Str.empty()) { - FD->addAttr(SYCLRegisteredKernelNameAttr::CreateImplicit( - S.getASTContext(), Str, Loc)); + FD->addAttr(SYCLRegisteredKernelNameAttr::CreateImplicit(S.getASTContext(), + Str, Loc)); } } @@ -5435,9 +5435,9 @@ static bool checkAndAddRegisteredKernelName(SemaSYCL &S, FunctionDecl *FD, addRegisteredKernelName(S, Str, Pair.second, FD->getLocation()); else S.Diag(FD->getLocation(), - diag::err_registered_kernels_name_already_registered) - << Pair.second->getAttr()-> - getRegName() + diag::err_registered_kernels_name_already_registered) + << Pair.second->getAttr() + ->getRegName() << Str; } // An empty name string implies a regular free kernel construction @@ -5450,21 +5450,19 @@ static bool checkAndAddRegisteredKernelName(SemaSYCL &S, FunctionDecl *FD, void SemaSYCL::constructFreeFunctionKernel(FunctionDecl *FD, StringRef NameStr) { if (!checkAndAddRegisteredKernelName(*this, FD, NameStr)) - return; + return; SyclKernelArgsSizeChecker argsSizeChecker(*this, FD->getLocation(), false /*IsSIMDKernel*/); - SyclKernelDeclCreator kernel_decl(*this, FD->getLocation(), - FD->isInlined(), false /*IsSIMDKernel */, - FD); + SyclKernelDeclCreator kernel_decl(*this, FD->getLocation(), FD->isInlined(), + false /*IsSIMDKernel */, FD); FreeFunctionKernelBodyCreator kernel_body(*this, kernel_decl, FD); - SyclKernelIntHeaderCreator int_header( - *this, getSyclIntegrationHeader(), FD->getType(), FD); + SyclKernelIntHeaderCreator int_header(*this, getSyclIntegrationHeader(), + FD->getType(), FD); - SyclKernelIntFooterCreator int_footer(*this, - getSyclIntegrationFooter()); + SyclKernelIntFooterCreator int_footer(*this, getSyclIntegrationFooter()); KernelObjVisitor Visitor{*this}; Visitor.VisitFunctionParameters(FD, argsSizeChecker, kernel_decl, kernel_body, diff --git a/clang/lib/Sema/SemaSYCLDeclAttr.cpp b/clang/lib/Sema/SemaSYCLDeclAttr.cpp index c4b63fc085bcc..4083c5c52b79b 100644 --- a/clang/lib/Sema/SemaSYCLDeclAttr.cpp +++ b/clang/lib/Sema/SemaSYCLDeclAttr.cpp @@ -3208,7 +3208,7 @@ void SemaSYCL::handleSYCLRegisteredKernels(Decl *D, const ParsedAttr &A) { /* Each init-list expression must have a pair of values. */ if (NumInits != 2) { Diag(ArgExpr->getExprLoc(), - diag::err_registered_kernels_init_list_pair_values); + diag::err_registered_kernels_init_list_pair_values); return; } From 255805a6b4c848dbac2f0e0a1c141b38789e242e Mon Sep 17 00:00:00 2001 From: Premanand M Rao Date: Fri, 27 Dec 2024 05:06:48 -0800 Subject: [PATCH 05/14] Modify tests slightly to work on Windows --- clang/test/CodeGenSYCL/registered-kernel-names.cpp | 2 +- clang/test/SemaSYCL/registered-kernel-names.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/test/CodeGenSYCL/registered-kernel-names.cpp b/clang/test/CodeGenSYCL/registered-kernel-names.cpp index 54adc545feca9..8cdc27b2e2daa 100644 --- a/clang/test/CodeGenSYCL/registered-kernel-names.cpp +++ b/clang/test/CodeGenSYCL/registered-kernel-names.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -triple spir64 -o - %s | FileCheck %s // This test checks if the sycl_registered_kernels module flag and // associated entries are generated for registered kernel names. diff --git a/clang/test/SemaSYCL/registered-kernel-names.cpp b/clang/test/SemaSYCL/registered-kernel-names.cpp index 0e0d5ed358214..9bc6305d3df4a 100644 --- a/clang/test/SemaSYCL/registered-kernel-names.cpp +++ b/clang/test/SemaSYCL/registered-kernel-names.cpp @@ -44,7 +44,7 @@ constexpr const char *str = "foo"; template __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] -void func(); +void func1(); namespace N { [[__sycl_detail__::__registered_kernels__( @@ -55,17 +55,17 @@ namespace N { // expected-error@+3 {{unable to resolve free function kernel 'func'}} namespace { [[__sycl_detail__::__registered_kernels__( - {"func", func} + {"func", func1} )]]; } // expected-error@+3 {{free function kernel has already been registered with 'reg1'; cannot register with 'reg2'}} __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] -void good() { +void good1() { } [[__sycl_detail__::__registered_kernels__( - {"reg1", good}, - {"reg2", good} + {"reg1", good1}, + {"reg2", good1} )]]; From bee576ab82b254ea0fe20faf44000974abff35dc Mon Sep 17 00:00:00 2001 From: Premanand M Rao Date: Mon, 6 Jan 2025 23:52:10 -0800 Subject: [PATCH 06/14] Use named metadata instead of a module flag --- clang/lib/CodeGen/CodeGenModule.cpp | 9 +++++---- clang/test/CodeGenSYCL/registered-kernel-names.cpp | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 5f27b5e41082e..7a5cc9e6fb7b6 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1430,14 +1430,15 @@ void CodeGenModule::Release() { if (!SYCLRegKernelNames.empty()) { std::vector Nodes; + llvm::LLVMContext &Ctx = TheModule.getContext(); for (auto MDKernelNames : SYCLRegKernelNames) { llvm::Metadata *Vals[] = {MDKernelNames.first, MDKernelNames.second}; - Nodes.push_back(llvm::MDTuple::get(TheModule.getContext(), Vals)); + Nodes.push_back(llvm::MDTuple::get(Ctx, Vals)); } - getModule().addModuleFlag( - llvm::Module::Append, "sycl_registered_kernels", - llvm::MDTuple::get(TheModule.getContext(), Nodes)); + llvm::NamedMDNode *SYCLRegKernelsMD = + TheModule.getOrInsertNamedMetadata("sycl_registered_kernels"); + SYCLRegKernelsMD->addOperand(llvm::MDNode::get(Ctx, Nodes)); } } diff --git a/clang/test/CodeGenSYCL/registered-kernel-names.cpp b/clang/test/CodeGenSYCL/registered-kernel-names.cpp index 8cdc27b2e2daa..95d19a2b152bb 100644 --- a/clang/test/CodeGenSYCL/registered-kernel-names.cpp +++ b/clang/test/CodeGenSYCL/registered-kernel-names.cpp @@ -60,7 +60,7 @@ namespace N { // Check for the presence of sycl-device module flag in device // compilations and its absence in host compilations. -// CHECK: !{{[0-9]+}} = !{i32 5, !"sycl_registered_kernels", ![[LIST:[0-9]+]]} +// CHECK: !sycl_registered_kernels = !{![[LIST:[0-9]+]]} // CHECK: ![[LIST]] = !{![[ENT1:[0-9]+]], ![[ENT2:[0-9]+]], ![[ENT3:[0-9]+]], ![[ENT4:[0-9]+]], ![[ENT5:[0-9]+]], ![[ENT6:[0-9]+]], ![[ENT7:[0-9]+]], ![[ENT8:[0-9]+]]} // CHECK: ![[ENT1]] = !{!"foo", !"{{.*}}sycl_kernel{{.*}}foo{{.*}}"} // CHECK: ![[ENT2]] = !{!"foo3", !"{{.*}}sycl_kernel{{.*}}ff_4{{.*}}"} From c13f1f08728a0a65da56d71e896e2d91f132ec5a Mon Sep 17 00:00:00 2001 From: Premanand M Rao Date: Tue, 7 Jan 2025 04:06:44 -0800 Subject: [PATCH 07/14] Fix comments in test --- clang/test/CodeGenSYCL/registered-kernel-names.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clang/test/CodeGenSYCL/registered-kernel-names.cpp b/clang/test/CodeGenSYCL/registered-kernel-names.cpp index 95d19a2b152bb..355ec75901e8b 100644 --- a/clang/test/CodeGenSYCL/registered-kernel-names.cpp +++ b/clang/test/CodeGenSYCL/registered-kernel-names.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fsycl-is-device -emit-llvm -triple spir64 -o - %s | FileCheck %s -// This test checks if the sycl_registered_kernels module flag and +// This test checks if the sycl_registered_kernels named metadata and // associated entries are generated for registered kernel names. __attribute__((sycl_device)) @@ -58,8 +58,7 @@ namespace N { )]]; } -// Check for the presence of sycl-device module flag in device -// compilations and its absence in host compilations. +// Check for the presence of sycl_registered_kernels named metadata. // CHECK: !sycl_registered_kernels = !{![[LIST:[0-9]+]]} // CHECK: ![[LIST]] = !{![[ENT1:[0-9]+]], ![[ENT2:[0-9]+]], ![[ENT3:[0-9]+]], ![[ENT4:[0-9]+]], ![[ENT5:[0-9]+]], ![[ENT6:[0-9]+]], ![[ENT7:[0-9]+]], ![[ENT8:[0-9]+]]} // CHECK: ![[ENT1]] = !{!"foo", !"{{.*}}sycl_kernel{{.*}}foo{{.*}}"} From fbb73e0e592ee5392f111d02acb7cecb1d8f00a5 Mon Sep 17 00:00:00 2001 From: Premanand M Rao Date: Tue, 7 Jan 2025 21:57:44 -0800 Subject: [PATCH 08/14] Address code review comments - typos --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 7 ++++--- clang/lib/Sema/SemaSYCLDeclAttr.cpp | 2 +- clang/test/SemaSYCL/registered-kernel-names.cpp | 10 +++++----- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index d93883d3b1b17..9ece2d3049422 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2402,6 +2402,7 @@ def err_reference_bind_to_vector_element : Error< "%select{non-const|volatile}0 reference cannot bind to vector element">; def err_reference_bind_to_matrix_element : Error< "%select{non-const|volatile}0 reference cannot bind to matrix element">; +// compilations and its absence in host compilations. def err_reference_var_requires_init : Error< "declaration of reference variable %0 requires an initializer">; def err_reference_without_init : Error< @@ -12515,12 +12516,12 @@ def warn_launch_bounds_is_cuda_specific : Warning< "%0 attribute ignored, only applicable when targeting Nvidia devices">, InGroup; def err_registered_kernels_num_of_args : Error< - "'__registered_kernels__' atribute must have at least one argument">; + "'__registered_kernels__' attribute must have at least one argument">; def err_registered_kernels_init_list : Error< - "argument to the '__registered_kernels__' atribute must be an " + "argument to the '__registered_kernels__' attribute must be an " "initializer list expression">; def err_registered_kernels_init_list_pair_values : Error< - "each initializer list argument to the '__registered_kernels__' atribute " + "each initializer list argument to the '__registered_kernels__' attribute " "must contain a pair of values">; def err_registered_kernels_resolve_function : Error< "unable to resolve free function kernel '%0'">; diff --git a/clang/lib/Sema/SemaSYCLDeclAttr.cpp b/clang/lib/Sema/SemaSYCLDeclAttr.cpp index 4083c5c52b79b..e54ba73a5562c 100644 --- a/clang/lib/Sema/SemaSYCLDeclAttr.cpp +++ b/clang/lib/Sema/SemaSYCLDeclAttr.cpp @@ -3212,7 +3212,7 @@ void SemaSYCL::handleSYCLRegisteredKernels(Decl *D, const ParsedAttr &A) { return; } - /* The first value of the pair muse be a string. */ + /* The first value of the pair must be a string. */ const Expr *FirstExpr = ArgListE->getInit(0); StringRef CurStr; SourceLocation Loc = FirstExpr->getExprLoc(); diff --git a/clang/test/SemaSYCL/registered-kernel-names.cpp b/clang/test/SemaSYCL/registered-kernel-names.cpp index 9bc6305d3df4a..762de5899b433 100644 --- a/clang/test/SemaSYCL/registered-kernel-names.cpp +++ b/clang/test/SemaSYCL/registered-kernel-names.cpp @@ -7,21 +7,21 @@ void foo(); constexpr const char *str = "foo"; -// expected-error@+1 {{'__registered_kernels__' atribute must have at least one argument}} +// expected-error@+1 {{'__registered_kernels__' attribute must have at least one argument}} [[__sycl_detail__::__registered_kernels__( )]]; -// expected-error@+2 {{argument to the '__registered_kernels__' atribute must be an initializer list expression}} +// expected-error@+2 {{argument to the '__registered_kernels__' attribute must be an initializer list expression}} [[__sycl_detail__::__registered_kernels__( 1 )]]; -// expected-error@+2 {{each initializer list argument to the '__registered_kernels__' atribute must contain a pair of values}} +// expected-error@+2 {{each initializer list argument to the '__registered_kernels__' attribute must contain a pair of values}} [[__sycl_detail__::__registered_kernels__( {} )]]; -// expected-error@+2 {{each initializer list argument to the '__registered_kernels__' atribute must contain a pair of values}} +// expected-error@+2 {{each initializer list argument to the '__registered_kernels__' attribute must contain a pair of values}} [[__sycl_detail__::__registered_kernels__( { "foo" } )]]; @@ -36,7 +36,7 @@ constexpr const char *str = "foo"; { str, 1 } )]]; -// expected-error@+2 {{each initializer list argument to the '__registered_kernels__' atribute must contain a pair of values}} +// expected-error@+2 {{each initializer list argument to the '__registered_kernels__' attribute must contain a pair of values}} [[__sycl_detail__::__registered_kernels__( { "foo", 1, foo } )]]; From 2fabb2f03ae5c291233549693a43a9fa389b88bf Mon Sep 17 00:00:00 2001 From: Premanand M Rao Date: Tue, 7 Jan 2025 21:59:51 -0800 Subject: [PATCH 09/14] Remove accidental line addition --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 9ece2d3049422..0460fd24a013a 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2402,7 +2402,6 @@ def err_reference_bind_to_vector_element : Error< "%select{non-const|volatile}0 reference cannot bind to vector element">; def err_reference_bind_to_matrix_element : Error< "%select{non-const|volatile}0 reference cannot bind to matrix element">; -// compilations and its absence in host compilations. def err_reference_var_requires_init : Error< "declaration of reference variable %0 requires an initializer">; def err_reference_without_init : Error< From 415b89f32374703f46834bfe9a018d601a2c3eb1 Mon Sep 17 00:00:00 2001 From: Premanand M Rao Date: Thu, 9 Jan 2025 09:19:01 -0800 Subject: [PATCH 10/14] Address code-review comments --- clang/include/clang/Sema/SemaSYCL.h | 4 ++ clang/lib/Sema/SemaSYCL.cpp | 18 ++++---- clang/lib/Sema/SemaSYCLDeclAttr.cpp | 42 ++++++------------- .../CodeGenSYCL/registered-kernel-names.cpp | 10 ++++- .../test/SemaSYCL/registered-kernel-names.cpp | 13 ++++++ 5 files changed, 46 insertions(+), 41 deletions(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index 340500a78e514..46333033a228e 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -661,6 +661,10 @@ class SemaSYCL : public SemaBase { void addIntelReqdSubGroupSizeAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E); void handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL); + + // Used to check whether the function represented by FD is a SYCL + // free function kernel or not. + bool isFreeFunction(const FunctionDecl *FD); }; } // namespace clang diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index d890e890990a7..b2c44f4755d09 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1148,10 +1148,10 @@ static target getAccessTarget(QualType FieldTy, // FIXME: Free functions must have void return type and be declared at file // scope, outside any namespaces. -static bool isFreeFunction(SemaSYCL &SemaSYCLRef, const FunctionDecl *FD) { +bool SemaSYCL::isFreeFunction(const FunctionDecl *FD) { for (auto *IRAttr : FD->specific_attrs()) { SmallVector, 4> NameValuePairs = - IRAttr->getAttributeNameValuePairs(SemaSYCLRef.getASTContext()); + IRAttr->getAttributeNameValuePairs(getASTContext()); for (const auto &NameValuePair : NameValuePairs) { if (NameValuePair.first == "sycl-nd-range-kernel" || NameValuePair.first == "sycl-single-task-kernel") { @@ -5291,7 +5291,7 @@ void SemaSYCL::SetSYCLKernelNames() { SyclKernelsToOpenCLKernels) { std::string CalculatedName, StableName; StringRef KernelName; - if (isFreeFunction(*this, Pair.first)) { + if (isFreeFunction(Pair.first)) { std::tie(CalculatedName, StableName) = constructFreeFunctionKernelName(*this, Pair.first, *MangleCtx); KernelName = CalculatedName; @@ -5416,16 +5416,15 @@ void SemaSYCL::ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, static void addRegisteredKernelName(SemaSYCL &S, StringRef Str, FunctionDecl *FD, SourceLocation Loc) { - if (!Str.empty()) { + if (!Str.empty()) FD->addAttr(SYCLRegisteredKernelNameAttr::CreateImplicit(S.getASTContext(), Str, Loc)); - } } static bool checkAndAddRegisteredKernelName(SemaSYCL &S, FunctionDecl *FD, StringRef Str) { using KernelPair = std::pair; - for (const KernelPair &Pair : S.getKernelFDPairs()) + for (const KernelPair &Pair : S.getKernelFDPairs()) { if (Pair.first == FD) { // If the current list of free function entries already contain this // free function, apply the name Str as an attribute. But if it already @@ -5444,6 +5443,7 @@ static bool checkAndAddRegisteredKernelName(SemaSYCL &S, FunctionDecl *FD, // call, so simply return. return false; } + } return true; } @@ -5759,7 +5759,7 @@ void SemaSYCL::MarkDevices() { } void SemaSYCL::ProcessFreeFunction(FunctionDecl *FD) { - if (isFreeFunction(*this, FD)) { + if (isFreeFunction(FD)) { SyclKernelDecompMarker DecompMarker(*this); SyclKernelFieldChecker FieldChecker(*this); SyclKernelUnionChecker UnionChecker(*this); @@ -6663,7 +6663,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { unsigned ShimCounter = 1; int FreeFunctionCount = 0; for (const KernelDesc &K : KernelDescs) { - if (!isFreeFunction(S, K.SyclKernel)) + if (!S.isFreeFunction(K.SyclKernel)) continue; ++FreeFunctionCount; // Generate forward declaration for free function. @@ -6781,7 +6781,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { } ShimCounter = 1; for (const KernelDesc &K : KernelDescs) { - if (!isFreeFunction(S, K.SyclKernel)) + if (!S.isFreeFunction(K.SyclKernel)) continue; O << "\n// Definition of kernel_id of " << K.Name << "\n"; diff --git a/clang/lib/Sema/SemaSYCLDeclAttr.cpp b/clang/lib/Sema/SemaSYCLDeclAttr.cpp index e54ba73a5562c..df740cd781671 100644 --- a/clang/lib/Sema/SemaSYCLDeclAttr.cpp +++ b/clang/lib/Sema/SemaSYCLDeclAttr.cpp @@ -3163,40 +3163,22 @@ void SemaSYCL::checkSYCLAddIRAttributesFunctionAttrConflicts(Decl *D) { << Attr; } -static bool isFreeFunctionKernel(SemaSYCL &S, FunctionDecl *FD) { - /* If it does not have the attribute, return false. */ - if (!FD->hasAttr()) - return false; - /* If it does, traverse through the pairs and return true, if - it is one of the two free function types. */ - auto *SAIRAttr = FD->getAttr(); - SmallVector, 4> NameValuePairs = - SAIRAttr->getFilteredAttributeNameValuePairs(S.getASTContext()); - for (const auto &NVPair : NameValuePairs) { - if (!NVPair.first.compare("sycl-single-task-kernel") || - !NVPair.first.compare("sycl-nd-range-kernel")) - return true; - } - /* If it does not have free function attributes, return false. */ - return false; -} - void SemaSYCL::handleSYCLRegisteredKernels(Decl *D, const ParsedAttr &A) { // Check for SYCL device compilation context. if (!getLangOpts().SYCLIsDevice) return; unsigned NumArgs = A.getNumArgs(); - /* When declared, we expect at least one item in the list. */ + // When declared, we expect at least one item in the list. if (NumArgs == 0) { Diag(A.getLoc(), diag::err_registered_kernels_num_of_args); return; } - /* Traverse through the items in the list. */ + // Traverse through the items in the list. for (unsigned I = 0; I < NumArgs; I++) { assert(A.isArgExpr(I) && "Expected expression argument"); - /* Each item in the list must be an initializer list expression. */ + // Each item in the list must be an initializer list expression. Expr *ArgExpr = A.getArgAsExpr(I); if (!isa(ArgExpr)) { Diag(ArgExpr->getExprLoc(), diag::err_registered_kernels_init_list); @@ -3205,45 +3187,45 @@ void SemaSYCL::handleSYCLRegisteredKernels(Decl *D, const ParsedAttr &A) { const auto *ArgListE = cast(ArgExpr); unsigned NumInits = ArgListE->getNumInits(); - /* Each init-list expression must have a pair of values. */ + // Each init-list expression must have a pair of values. if (NumInits != 2) { Diag(ArgExpr->getExprLoc(), diag::err_registered_kernels_init_list_pair_values); return; } - /* The first value of the pair must be a string. */ + // The first value of the pair must be a string. const Expr *FirstExpr = ArgListE->getInit(0); StringRef CurStr; SourceLocation Loc = FirstExpr->getExprLoc(); if (!SemaRef.checkStringLiteralArgumentAttr(A, FirstExpr, CurStr, &Loc)) return; - /* Resolve the FunctionDecl from the second value of the pair. */ + // Resolve the FunctionDecl from the second value of the pair. auto *SecondE = const_cast(ArgListE->getInit(1)); FunctionDecl *FD = nullptr; if (auto *ULE = dyn_cast(SecondE)) { FD = SemaRef.ResolveSingleFunctionTemplateSpecialization(ULE, true); Loc = ULE->getExprLoc(); } else { - while (isa(SecondE)) - SecondE = cast(SecondE)->getSubExpr(); + if (isa(SecondE)) + SecondE = cast(SecondE)->getSubExpr()->IgnoreParenImpCasts(); auto *DRE = dyn_cast(SecondE); if (DRE) FD = dyn_cast(DRE->getDecl()); Loc = SecondE->getExprLoc(); } - /* Issue a diagnostic if we are unable to resolve the FunctionDecl. */ + // Issue a diagnostic if we are unable to resolve the FunctionDecl. if (!FD) { Diag(Loc, diag::err_registered_kernels_resolve_function) << CurStr; return; } - /* Issue a diagnostic is the FunctionDecl is not a SYCL free function. */ - if (!isFreeFunctionKernel(*this, FD)) { + // Issue a diagnostic is the FunctionDecl is not a SYCL free function. + if (!isFreeFunction(FD)) { Diag(FD->getLocation(), diag::err_not_sycl_free_function) << CurStr; return; } - /* Construct a free function kernel. */ + // Construct a free function kernel. constructFreeFunctionKernel(FD, CurStr); } } diff --git a/clang/test/CodeGenSYCL/registered-kernel-names.cpp b/clang/test/CodeGenSYCL/registered-kernel-names.cpp index 355ec75901e8b..2d82a4e9112c7 100644 --- a/clang/test/CodeGenSYCL/registered-kernel-names.cpp +++ b/clang/test/CodeGenSYCL/registered-kernel-names.cpp @@ -8,6 +8,10 @@ __attribute__((sycl_device)) void foo() { } +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void bar(); + __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-nd-range-kernel", 0)]] void ff_4() { @@ -54,13 +58,14 @@ namespace N { {"decl spec", tempfoo2}, {"def spec", tempfoo2}, {"foo3", ff_4}, - {"nontype", tempfoo3<5>} + {"nontype", tempfoo3<5>}, + {"decl non-temp", bar} )]]; } // Check for the presence of sycl_registered_kernels named metadata. // CHECK: !sycl_registered_kernels = !{![[LIST:[0-9]+]]} -// CHECK: ![[LIST]] = !{![[ENT1:[0-9]+]], ![[ENT2:[0-9]+]], ![[ENT3:[0-9]+]], ![[ENT4:[0-9]+]], ![[ENT5:[0-9]+]], ![[ENT6:[0-9]+]], ![[ENT7:[0-9]+]], ![[ENT8:[0-9]+]]} +// CHECK: ![[LIST]] = !{![[ENT1:[0-9]+]], ![[ENT2:[0-9]+]], ![[ENT3:[0-9]+]], ![[ENT4:[0-9]+]], ![[ENT5:[0-9]+]], ![[ENT6:[0-9]+]], ![[ENT7:[0-9]+]], ![[ENT8:[0-9]+]], ![[ENT9:[0-9]+]]} // CHECK: ![[ENT1]] = !{!"foo", !"{{.*}}sycl_kernel{{.*}}foo{{.*}}"} // CHECK: ![[ENT2]] = !{!"foo3", !"{{.*}}sycl_kernel{{.*}}ff_4{{.*}}"} // CHECK: ![[ENT3]] = !{!"iota", !"{{.*}}sycl_kernel{{.*}}iota{{.*}}"} @@ -69,3 +74,4 @@ namespace N { // CHECK: ![[ENT6]] = !{!"decl temp", !"{{.*}}sycl_kernel{{.*}}tempfoo{{.*}}"} // CHECK: ![[ENT7]] = !{!"decl spec", !"{{.*}}sycl_kernel{{.*}}tempfoo2{{.*}}"} // CHECK: ![[ENT8]] = !{!"nontype", !"{{.*}}sycl_kernel{{.*}}tempfoo3{{.*}}"} +// CHECK: ![[ENT9]] = !{!"decl non-temp", !"{{.*}}sycl_kernel{{.*}}bar{{.*}}"} diff --git a/clang/test/SemaSYCL/registered-kernel-names.cpp b/clang/test/SemaSYCL/registered-kernel-names.cpp index 762de5899b433..03728e37033a6 100644 --- a/clang/test/SemaSYCL/registered-kernel-names.cpp +++ b/clang/test/SemaSYCL/registered-kernel-names.cpp @@ -69,3 +69,16 @@ void good1() { {"reg1", good1}, {"reg2", good1} )]]; + +template +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void uses_throw() { + // expected-error@+2 {{cannot use 'throw' with exceptions disabled}} + // expected-error@+1 {{SYCL kernel cannot use exceptions}} + throw 5; +} + +[[__sycl_detail__::__registered_kernels__( + {"throw", uses_throw} +)]]; From 043e527e144bc5d11f0c00b4fdd9af9910479fcf Mon Sep 17 00:00:00 2001 From: Premanand M Rao Date: Thu, 9 Jan 2025 21:15:24 -0800 Subject: [PATCH 11/14] Code review comments - modify test --- clang/test/SemaSYCL/registered-kernel-names.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/clang/test/SemaSYCL/registered-kernel-names.cpp b/clang/test/SemaSYCL/registered-kernel-names.cpp index 03728e37033a6..4e2623f5dc7f6 100644 --- a/clang/test/SemaSYCL/registered-kernel-names.cpp +++ b/clang/test/SemaSYCL/registered-kernel-names.cpp @@ -70,15 +70,18 @@ void good1() { {"reg2", good1} )]]; + +struct S1 { +// expected-error@+1 {{'int &' cannot be used as the type of a kernel parameter}} + int &ri; +}; + template __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] -void uses_throw() { - // expected-error@+2 {{cannot use 'throw' with exceptions disabled}} - // expected-error@+1 {{SYCL kernel cannot use exceptions}} - throw 5; +void func_with_S1_param(T s) { } [[__sycl_detail__::__registered_kernels__( - {"throw", uses_throw} + {"ref field", func_with_S1_param} )]]; From 0bd732548651faceb2354767f2e9ca2f716c7bdd Mon Sep 17 00:00:00 2001 From: Premanand M Rao Date: Fri, 10 Jan 2025 06:40:23 -0800 Subject: [PATCH 12/14] Address code-review comments; improve codegen test --- clang/lib/Sema/SemaSYCL.cpp | 2 +- clang/lib/Sema/SemaSYCLDeclAttr.cpp | 9 ++- .../CodeGenSYCL/registered-kernel-names.cpp | 59 +++++++++++++++++++ 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index b2c44f4755d09..0aaee401a75ee 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -5426,7 +5426,7 @@ static bool checkAndAddRegisteredKernelName(SemaSYCL &S, FunctionDecl *FD, using KernelPair = std::pair; for (const KernelPair &Pair : S.getKernelFDPairs()) { if (Pair.first == FD) { - // If the current list of free function entries already contain this + // If the current list of free function entries already contains this // free function, apply the name Str as an attribute. But if it already // has an attribute name, issue a diagnostic instead. if (!Str.empty()) { diff --git a/clang/lib/Sema/SemaSYCLDeclAttr.cpp b/clang/lib/Sema/SemaSYCLDeclAttr.cpp index df740cd781671..00e3e183a7483 100644 --- a/clang/lib/Sema/SemaSYCLDeclAttr.cpp +++ b/clang/lib/Sema/SemaSYCLDeclAttr.cpp @@ -3185,7 +3185,7 @@ void SemaSYCL::handleSYCLRegisteredKernels(Decl *D, const ParsedAttr &A) { return; } - const auto *ArgListE = cast(ArgExpr); + auto *ArgListE = cast(ArgExpr); unsigned NumInits = ArgListE->getNumInits(); // Each init-list expression must have a pair of values. if (NumInits != 2) { @@ -3195,14 +3195,14 @@ void SemaSYCL::handleSYCLRegisteredKernels(Decl *D, const ParsedAttr &A) { } // The first value of the pair must be a string. - const Expr *FirstExpr = ArgListE->getInit(0); + Expr *FirstExpr = ArgListE->getInit(0); StringRef CurStr; SourceLocation Loc = FirstExpr->getExprLoc(); if (!SemaRef.checkStringLiteralArgumentAttr(A, FirstExpr, CurStr, &Loc)) return; // Resolve the FunctionDecl from the second value of the pair. - auto *SecondE = const_cast(ArgListE->getInit(1)); + Expr *SecondE = ArgListE->getInit(1); FunctionDecl *FD = nullptr; if (auto *ULE = dyn_cast(SecondE)) { FD = SemaRef.ResolveSingleFunctionTemplateSpecialization(ULE, true); @@ -3210,8 +3210,7 @@ void SemaSYCL::handleSYCLRegisteredKernels(Decl *D, const ParsedAttr &A) { } else { if (isa(SecondE)) SecondE = cast(SecondE)->getSubExpr()->IgnoreParenImpCasts(); - auto *DRE = dyn_cast(SecondE); - if (DRE) + if (auto *DRE = dyn_cast(SecondE)) FD = dyn_cast(DRE->getDecl()); Loc = SecondE->getExprLoc(); } diff --git a/clang/test/CodeGenSYCL/registered-kernel-names.cpp b/clang/test/CodeGenSYCL/registered-kernel-names.cpp index 2d82a4e9112c7..fb41b3a8777d5 100644 --- a/clang/test/CodeGenSYCL/registered-kernel-names.cpp +++ b/clang/test/CodeGenSYCL/registered-kernel-names.cpp @@ -63,6 +63,65 @@ namespace N { )]]; } +// Check that the functions registered in the __registered_kernels__ list +// are defined or declared as appropriate, that the kernels are generated +// for these functions and are called from the generated kernels. + +// Check that the definitions for the functions foo, ff_4, iota, +// tempfoo2 explicitly instantiated with int, and tempfoo2 specialized +// with float are generated. +// CHECK: define {{.*}} void @[[FOO:[_A-Za-z0-9]+]]() +// CHECK: define {{.*}} void @[[FF_4:[_A-Za-z0-9]+]]() +// CHECK: define {{.*}} void @[[IOTA:[_A-Za-z0-9]+]](i32 {{.*}} %0, ptr addrspace(4) {{.*}} %1) +// CHECK: define {{.*}} void @[[TEMPFOO2INT:[_A-Za-z0-9]+]](i32 {{.*}} %pt) +// CHECK: define {{.*}} void @[[TEMPFOO2SHORT:[_A-Za-z0-9]+]](i16 {{.*}} %0) + +// Check generation of the SYCL kernel for foo, and the call to foo. +// CHECK: define {{.*}} void @_Z17__sycl_kernel_foov() +// CHECK: call {{.*}} void @[[FOO]]() + +// Check generation of the SYCL kernel for ff_4, and the call to ff_4. +// CHECK: define {{.*}} void @_Z18__sycl_kernel_ff_4v() +// CHECK: call {{.*}} void @[[FF_4]]() + +// Check generation of the SYCL kernel for iota, and the call to iota. +// CHECK: define {{.*}} void @_Z18__sycl_kernel_iotaiPi(i32 {{.*}} %__arg_, ptr addrspace(1) {{.*}} %__arg_1) +// CHECK: call {{.*}} void @[[IOTA]](i32 {{.*}} %0, ptr addrspace(4) {{.*}} %2) + +// Check generation of the SYCL kernel for tempfoo2, and the call to +// tempfoo2. +// CHECK: define {{.*}} void @_Z22__sycl_kernel_tempfoo2IiEvT_(i32 {{.*}} %__arg_pt) +// CHECK: call {{.*}} void @[[TEMPFOO2INT]](i32 {{.*}} %0) + +// Check generation of the SYCL kernel for tempfoo2, and the call to +// tempfoo2. +// CHECK: define {{.*}} void @_Z22__sycl_kernel_tempfoo2IsEvT_(i16 {{.*}} %__arg_) +// CHECK: call {{.*}} void @[[TEMPFOO2SHORT]](i16 {{.*}} %0) + +// Check generation of the SYCL kernel for tempfoo, the call to +// tempfoo, and its declaration. +// CHECK: define {{.*}} void @_Z21__sycl_kernel_tempfooIiEvT_(i32 {{.*}} %__arg_pt) +// CHECK: call {{.*}} void @[[TEMPFOOINT:[_A-Za-z0-9]+]](i32 {{.*}} %0) +// CHECK: declare {{.*}} void @[[TEMPFOOINT]](i32 {{.*}}) + +// Check generation of the SYCL kernel for tempfoo2, the call to +// tempfoo2, and its declaration. +// CHECK: define {{.*}} void @_Z22__sycl_kernel_tempfoo2IfEvT_(float {{.*}} %__arg_f) +// CHECK: call {{.*}} void @[[TEMPFOO2FLOAT:[_A-Za-z0-9]+]](float {{.*}} %0) +// CHECK: declare {{.*}} void @[[TEMPFOO2FLOAT]](float {{.*}}) + +// Check generation of the SYCL kernel for tempfoo3<5>, the call to +// tempfoo3<5>, and its definition. +// CHECK: define {{.*}} void @_Z22__sycl_kernel_tempfoo3ILi5EEvv() +// CHECK: call {{.*}} void @[[TEMPFOO35:[_A-Za-z0-9]+]]() +// CHECK: define {{.*}} void @[[TEMPFOO35]]() + +// Check generation of the SYCL kernel for bar, the call to +// bar, and its declaration. +// CHECK: define {{.*}} void @_Z17__sycl_kernel_barv() +// CHECK: call {{.*}} void @[[BAR:[_A-Za-z0-9]+]]() +// CHECK: declare {{.*}} void @[[BAR]]() + // Check for the presence of sycl_registered_kernels named metadata. // CHECK: !sycl_registered_kernels = !{![[LIST:[0-9]+]]} // CHECK: ![[LIST]] = !{![[ENT1:[0-9]+]], ![[ENT2:[0-9]+]], ![[ENT3:[0-9]+]], ![[ENT4:[0-9]+]], ![[ENT5:[0-9]+]], ![[ENT6:[0-9]+]], ![[ENT7:[0-9]+]], ![[ENT8:[0-9]+]], ![[ENT9:[0-9]+]]} From 12e0921dcc2b0964757d1d35c07920a9b951631a Mon Sep 17 00:00:00 2001 From: Premanand M Rao Date: Mon, 13 Jan 2025 23:21:38 -0800 Subject: [PATCH 13/14] Fix cast logic; modify test for pathological case --- clang/lib/Sema/SemaSYCLDeclAttr.cpp | 3 +-- clang/test/CodeGenSYCL/registered-kernel-names.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/clang/lib/Sema/SemaSYCLDeclAttr.cpp b/clang/lib/Sema/SemaSYCLDeclAttr.cpp index 00e3e183a7483..491ecc04115a6 100644 --- a/clang/lib/Sema/SemaSYCLDeclAttr.cpp +++ b/clang/lib/Sema/SemaSYCLDeclAttr.cpp @@ -3208,8 +3208,7 @@ void SemaSYCL::handleSYCLRegisteredKernels(Decl *D, const ParsedAttr &A) { FD = SemaRef.ResolveSingleFunctionTemplateSpecialization(ULE, true); Loc = ULE->getExprLoc(); } else { - if (isa(SecondE)) - SecondE = cast(SecondE)->getSubExpr()->IgnoreParenImpCasts(); + SecondE = SecondE->IgnoreParenCasts(); if (auto *DRE = dyn_cast(SecondE)) FD = dyn_cast(DRE->getDecl()); Loc = SecondE->getExprLoc(); diff --git a/clang/test/CodeGenSYCL/registered-kernel-names.cpp b/clang/test/CodeGenSYCL/registered-kernel-names.cpp index fb41b3a8777d5..10d5a17fa51e1 100644 --- a/clang/test/CodeGenSYCL/registered-kernel-names.cpp +++ b/clang/test/CodeGenSYCL/registered-kernel-names.cpp @@ -52,7 +52,7 @@ void tempfoo3() { namespace N { [[__sycl_detail__::__registered_kernels__( {"foo", foo}, - {"iota", (void(*)(int, int *))iota}, + {"iota", (((void(*)(int, int *))(void *)(((iota)))))}, {"decl temp", tempfoo}, {"inst temp", tempfoo2}, {"decl spec", tempfoo2}, From 24bd825749eee3d6eb0ca9392256eb516d7ce148 Mon Sep 17 00:00:00 2001 From: Premanand M Rao Date: Tue, 21 Jan 2025 11:01:29 -0800 Subject: [PATCH 14/14] Fix tests based on CR comments --- .../CodeGenSYCL/registered-kernel-names.cpp | 49 ++++++++----------- .../test/SemaSYCL/registered-kernel-names.cpp | 7 +-- 2 files changed, 23 insertions(+), 33 deletions(-) diff --git a/clang/test/CodeGenSYCL/registered-kernel-names.cpp b/clang/test/CodeGenSYCL/registered-kernel-names.cpp index 10d5a17fa51e1..c8746e34b1e11 100644 --- a/clang/test/CodeGenSYCL/registered-kernel-names.cpp +++ b/clang/test/CodeGenSYCL/registered-kernel-names.cpp @@ -3,32 +3,26 @@ // This test checks if the sycl_registered_kernels named metadata and // associated entries are generated for registered kernel names. -__attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] void foo() { } -__attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] void bar(); -__attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-nd-range-kernel", 0)]] void ff_4() { } -__attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] void iota(int, int *) { } template -__attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] void tempfoo(T pt); template -__attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] void tempfoo2(T pt) { T t; @@ -43,7 +37,6 @@ template <> void tempfoo2(short) { } template -__attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] void tempfoo3() { (void)N; @@ -67,36 +60,36 @@ namespace N { // are defined or declared as appropriate, that the kernels are generated // for these functions and are called from the generated kernels. -// Check that the definitions for the functions foo, ff_4, iota, -// tempfoo2 explicitly instantiated with int, and tempfoo2 specialized -// with float are generated. -// CHECK: define {{.*}} void @[[FOO:[_A-Za-z0-9]+]]() -// CHECK: define {{.*}} void @[[FF_4:[_A-Za-z0-9]+]]() -// CHECK: define {{.*}} void @[[IOTA:[_A-Za-z0-9]+]](i32 {{.*}} %0, ptr addrspace(4) {{.*}} %1) -// CHECK: define {{.*}} void @[[TEMPFOO2INT:[_A-Za-z0-9]+]](i32 {{.*}} %pt) -// CHECK: define {{.*}} void @[[TEMPFOO2SHORT:[_A-Za-z0-9]+]](i16 {{.*}} %0) - -// Check generation of the SYCL kernel for foo, and the call to foo. +// Check generation of the SYCL kernel for foo, the call to foo, and definition +// of foo. // CHECK: define {{.*}} void @_Z17__sycl_kernel_foov() -// CHECK: call {{.*}} void @[[FOO]]() +// CHECK: call {{.*}} void @[[FOO:[_A-Za-z0-9]+]]() +// CHECK: define {{.*}} void @[[FOO:[_A-Za-z0-9]+]]() -// Check generation of the SYCL kernel for ff_4, and the call to ff_4. +// Check generation of the SYCL kernel for ff_4, the call to ff_4, and the +// definition of ff_4. // CHECK: define {{.*}} void @_Z18__sycl_kernel_ff_4v() -// CHECK: call {{.*}} void @[[FF_4]]() +// CHECK: call {{.*}} void @[[FF_4:[_A-Za-z0-9]+]]() +// CHECK: define {{.*}} void @[[FF_4]]() -// Check generation of the SYCL kernel for iota, and the call to iota. +// Check generation of the SYCL kernel for iota, the call to iota, and the +// definition of iota. // CHECK: define {{.*}} void @_Z18__sycl_kernel_iotaiPi(i32 {{.*}} %__arg_, ptr addrspace(1) {{.*}} %__arg_1) -// CHECK: call {{.*}} void @[[IOTA]](i32 {{.*}} %0, ptr addrspace(4) {{.*}} %2) +// CHECK: call {{.*}} void @[[IOTA:[_A-Za-z0-9]+]](i32 {{.*}} %0, ptr addrspace(4) {{.*}} %2) +// CHECK: define {{.*}} void @[[IOTA]](i32 {{.*}} %0, ptr addrspace(4) {{.*}} %1) -// Check generation of the SYCL kernel for tempfoo2, and the call to -// tempfoo2. +// Check generation of the SYCL kernel for tempfoo2, the call to +// tempfoo2 and the definition of tempfoo2 explicitly instantiated +// with int. // CHECK: define {{.*}} void @_Z22__sycl_kernel_tempfoo2IiEvT_(i32 {{.*}} %__arg_pt) -// CHECK: call {{.*}} void @[[TEMPFOO2INT]](i32 {{.*}} %0) +// CHECK: call {{.*}} void @[[TEMPFOO2INT:[_A-Za-z0-9]+]](i32 {{.*}} %0) +// CHECK: define {{.*}} void @[[TEMPFOO2INT]](i32 {{.*}} %pt) -// Check generation of the SYCL kernel for tempfoo2, and the call to -// tempfoo2. +// Check generation of the SYCL kernel for tempfoo2, the call to +// tempfoo2 and the definition of tempfoo2 specialized with short. // CHECK: define {{.*}} void @_Z22__sycl_kernel_tempfoo2IsEvT_(i16 {{.*}} %__arg_) -// CHECK: call {{.*}} void @[[TEMPFOO2SHORT]](i16 {{.*}} %0) +// CHECK: call {{.*}} void @[[TEMPFOO2SHORT:[_A-Za-z0-9]+]](i16 {{.*}} %0) +// CHECK: define {{.*}} void @[[TEMPFOO2SHORT]](i16 {{.*}} %0) // Check generation of the SYCL kernel for tempfoo, the call to // tempfoo, and its declaration. diff --git a/clang/test/SemaSYCL/registered-kernel-names.cpp b/clang/test/SemaSYCL/registered-kernel-names.cpp index 4e2623f5dc7f6..65a55d4379981 100644 --- a/clang/test/SemaSYCL/registered-kernel-names.cpp +++ b/clang/test/SemaSYCL/registered-kernel-names.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsycl-is-device -fsyntax-only -verify -pedantic %s +// RUN: %clang_cc1 -fsycl-is-device -fsyntax-only -verify %s // The test checks issuing diagnostics for registered kernel names. @@ -42,7 +42,6 @@ constexpr const char *str = "foo"; )]]; template -__attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] void func1(); @@ -59,8 +58,7 @@ namespace { )]]; } -// expected-error@+3 {{free function kernel has already been registered with 'reg1'; cannot register with 'reg2'}} -__attribute__((sycl_device)) +// expected-error@+2 {{free function kernel has already been registered with 'reg1'; cannot register with 'reg2'}} [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] void good1() { } @@ -77,7 +75,6 @@ struct S1 { }; template -__attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] void func_with_S1_param(T s) { }