Skip to content

Commit 3c4a2b8

Browse files
committed
[SYCL] The sycl_kernel_entry_point attribute.
The `sycl_kernel_entry_point` attribute is used to declare a function that defines a pattern for an offload kernel to be emitted. The attribute requires a single type argument that specifies the type used as a SYCL kernel name as described in section 5.2, "Naming of kernels", of the SYCL 2020 specification. Properties of the offload kernel are collected when a function declared with the `sycl_kernel_entry_point` attribute is parsed or instantiated. These properties, such as the kernel name type, are stored in the AST context where they are (or will be) used for diagnostic purposes and to facilitate reflection to a SYCL run-time library. These properties are not serialized with the AST but are recreated upon deserialization. The `sycl_kernel_entry_point` attribute is intended to replace the existing `sycl_kernel` attribute which is intended to be deprecated in a future change and removed following an appropriate deprecation period. The new attribute differs in that it is enabled for both SYCL host and device compilation, may be used with non-template functions, explicitly indicates the type used as the kernel name type, and will impact AST generation. This change adds the basic infrastructure for the new attribute. Future changes will add diagnostics and new AST support that will be used to drive generation of the corresponding offload kernel.
1 parent 4b4ea6d commit 3c4a2b8

14 files changed

+480
-3
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "clang/AST/ExternalASTSource.h"
2424
#include "clang/AST/PrettyPrinter.h"
2525
#include "clang/AST/RawCommentList.h"
26+
#include "clang/AST/SYCLKernelInfo.h"
2627
#include "clang/AST/TemplateName.h"
2728
#include "clang/Basic/LLVM.h"
2829
#include "clang/Basic/PartialDiagnostic.h"
@@ -1222,6 +1223,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
12221223
/// in device compilation.
12231224
llvm::DenseSet<const FunctionDecl *> CUDAImplicitHostDeviceFunUsedByDevice;
12241225

1226+
/// Map of SYCL kernels indexed by the unique type used to name the kernel.
1227+
/// Entries are not serialized but are recreated on deserialization of a
1228+
/// sycl_kernel_entry_point attributed function declaration.
1229+
llvm::DenseMap<CanQualType, SYCLKernelInfo> SYCLKernels;
1230+
12251231
/// For capturing lambdas with an explicit object parameter whose type is
12261232
/// derived from the lambda type, we need to perform derived-to-base
12271233
/// conversion so we can access the captures; the cast paths for that
@@ -3301,6 +3307,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
33013307
void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
33023308
GlobalDecl GD) const;
33033309

3310+
/// Generates and stores SYCL kernel metadata for the provided
3311+
/// SYCL kernel entry point function. The provided function must have
3312+
/// an attached sycl_kernel_entry_point attribute that specifies a unique
3313+
/// type for the name of a SYCL kernel.
3314+
void registerSYCLEntryPointFunction(FunctionDecl *FD);
3315+
33043316
//===--------------------------------------------------------------------===//
33053317
// Statistics
33063318
//===--------------------------------------------------------------------===//
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//===--- SYCLKernelInfo.h --- Information about SYCL kernels --------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
/// \file
9+
/// This file declares types used to describe SYCL kernels.
10+
///
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_CLANG_AST_SYCLKERNELINFO_H
14+
#define LLVM_CLANG_AST_SYCLKERNELINFO_H
15+
16+
#include <string>
17+
#include "clang/AST/Decl.h"
18+
#include "clang/AST/Type.h"
19+
20+
namespace clang {
21+
22+
class SYCLKernelInfo {
23+
public:
24+
SYCLKernelInfo(
25+
CanQualType KernelNameType,
26+
const FunctionDecl *KernelEntryPointDecl)
27+
:
28+
KernelNameType(KernelNameType),
29+
KernelEntryPointDecl(KernelEntryPointDecl)
30+
{}
31+
32+
CanQualType GetKernelNameType() const {
33+
return KernelNameType;
34+
}
35+
36+
const FunctionDecl* GetKernelEntryPointDecl() const {
37+
return KernelEntryPointDecl;
38+
}
39+
40+
private:
41+
CanQualType KernelNameType;
42+
const FunctionDecl *KernelEntryPointDecl;
43+
};
44+
45+
} // namespace clang
46+
47+
#endif // LLVM_CLANG_AST_SYCLKERNELINFO_H

clang/include/clang/Basic/Attr.td

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,8 @@ def MicrosoftExt : LangOpt<"MicrosoftExt">;
407407
def Borland : LangOpt<"Borland">;
408408
def CUDA : LangOpt<"CUDA">;
409409
def HIP : LangOpt<"HIP">;
410-
def SYCL : LangOpt<"SYCLIsDevice">;
410+
def SYCLHost : LangOpt<"SYCLIsHost">;
411+
def SYCLDevice : LangOpt<"SYCLIsDevice">;
411412
def COnly : LangOpt<"", "!LangOpts.CPlusPlus">;
412413
def CPlusPlus : LangOpt<"CPlusPlus">;
413414
def OpenCL : LangOpt<"OpenCL">;
@@ -1489,14 +1490,23 @@ def : MutualExclusions<[CUDAConstant, CUDAShared, HIPManaged]>;
14891490
def SYCLKernel : InheritableAttr {
14901491
let Spellings = [Clang<"sycl_kernel">];
14911492
let Subjects = SubjectList<[FunctionTmpl]>;
1492-
let LangOpts = [SYCL];
1493+
let LangOpts = [SYCLDevice];
14931494
let Documentation = [SYCLKernelDocs];
14941495
}
14951496

1497+
def SYCLKernelEntryPoint : InheritableAttr {
1498+
let Spellings = [Clang<"sycl_kernel_entry_point">];
1499+
let Args = [TypeArgument<"KernelName">];
1500+
let Subjects = SubjectList<[Function], ErrorDiag>;
1501+
let TemplateDependent = 1;
1502+
let LangOpts = [SYCLHost, SYCLDevice];
1503+
let Documentation = [SYCLKernelEntryPointDocs];
1504+
}
1505+
14961506
def SYCLSpecialClass: InheritableAttr {
14971507
let Spellings = [Clang<"sycl_special_class">];
14981508
let Subjects = SubjectList<[CXXRecord]>;
1499-
let LangOpts = [SYCL];
1509+
let LangOpts = [SYCLDevice];
15001510
let Documentation = [SYCLSpecialClassDocs];
15011511
}
15021512

clang/include/clang/Basic/AttrDocs.td

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,64 @@ The SYCL kernel in the previous code sample meets these expectations.
455455
}];
456456
}
457457

458+
def SYCLKernelEntryPointDocs : Documentation {
459+
let Category = DocCatFunction;
460+
let Content = [{
461+
The ``sycl_kernel_entry_point`` attribute specifies that a function definition
462+
defines a pattern for an offload kernel entry point function to be emitted when
463+
the source code is compiled with ``-fsycl`` for a device target. Such functions
464+
serve as the execution entry point for a SYCL run-time library to invoke a SYCL
465+
kernel on a device. The function's parameters define the parameters to the
466+
offload kernel.
467+
468+
The attribute requires a single type argument that specifies a class type that
469+
meets the requirements for a SYCL kernel name as described in section 5.2,
470+
"Naming of kernels", of the SYCL 2020 specification. A unique kernel name type
471+
is required for each function declared with the attribute. The attribute may
472+
not first appear on a declaration that follows a definition of the function.
473+
474+
The attribute appertains only to non-member functions and static member
475+
functions that meet the following requirements:
476+
477+
- Has a ``void`` return type.
478+
- Is not a variadic function.
479+
- Is not a coroutine.
480+
- Is not defined as deleted or as defaulted.
481+
- Is not declared with the ``constexpr`` or ``consteval`` specifiers.
482+
- Is not declared with the ``[[noreturn]]`` attribute.
483+
484+
This attribute is intended for use in the implementation of SYCL run-time
485+
libraries that implement SYCL kernel invocation functions like the
486+
``single_task`` and ``parallel_for`` member functions of the ``sycl::handler``
487+
class specified in section 4.9.4, "Command group ``handler`` class" of the
488+
SYCL 2020 specification. Such use might look something like the following.
489+
490+
.. code-block:: c++
491+
492+
namespace sycl {
493+
class handler {
494+
template<typename KernelNameType, typename KernelType>
495+
[[ clang::sycl_kernel_entry_point(KernelNameType) ]]
496+
static void kernel_entry_point(KernelType kernel) {
497+
kernel();
498+
}
499+
500+
public:
501+
template<typename KernelNameType, typename KernelType>
502+
void single_task(KernelType kernel) {
503+
kernel_entry_point<KernelNameType>(kernel);
504+
}
505+
};
506+
} // namespace sycl
507+
508+
It is not necessary for a SYCL kernel entry point function to be called for
509+
the offload kernel entry point to be emitted. For inline functions and function
510+
templates, any ODR-use will suffice. For other functions, an ODR-use is not
511+
required; the offload kernel entry point will be emitted if the function is
512+
defined.
513+
}];
514+
}
515+
458516
def SYCLSpecialClassDocs : Documentation {
459517
let Category = DocCatStmt;
460518
let Content = [{

clang/include/clang/Sema/SemaSYCL.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class SemaSYCL : public SemaBase {
6262
ParsedType ParsedTy);
6363

6464
void handleKernelAttr(Decl *D, const ParsedAttr &AL);
65+
void handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL);
6566
};
6667

6768
} // namespace clang

clang/lib/AST/ASTContext.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14296,6 +14296,31 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
1429614296
}
1429714297
}
1429814298

14299+
static SYCLKernelInfo BuildSYCLKernelInfo(ASTContext &Context,
14300+
CanQualType KernelNameType,
14301+
const FunctionDecl *FD) {
14302+
return { KernelNameType, FD };
14303+
}
14304+
14305+
void ASTContext::registerSYCLEntryPointFunction(FunctionDecl *FD) {
14306+
assert(!FD->isInvalidDecl());
14307+
assert(!FD->isDependentContext());
14308+
14309+
const auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>();
14310+
assert(SKEPAttr && "Missing sycl_kernel_entry_point attribute");
14311+
14312+
CanQualType KernelNameType = getCanonicalType(SKEPAttr->getKernelName());
14313+
auto IT = SYCLKernels.find(KernelNameType);
14314+
if (IT != SYCLKernels.end()) {
14315+
if (!declaresSameEntity(FD, IT->second.GetKernelEntryPointDecl()))
14316+
llvm::report_fatal_error("SYCL kernel name conflict");
14317+
} else {
14318+
SYCLKernels.insert_or_assign(
14319+
KernelNameType,
14320+
BuildSYCLKernelInfo(*this, KernelNameType, FD));
14321+
}
14322+
}
14323+
1429914324
OMPTraitInfo &ASTContext::getNewOMPTraitInfo() {
1430014325
OMPTraitInfoVector.emplace_back(new OMPTraitInfo());
1430114326
return *OMPTraitInfoVector.back();

clang/lib/Sema/SemaDecl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12053,6 +12053,10 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
1205312053
if (LangOpts.OpenMP)
1205412054
OpenMP().ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(NewFD);
1205512055

12056+
if (LangOpts.isSYCL() && NewFD->hasAttr<SYCLKernelEntryPointAttr>() &&
12057+
!NewFD->isInvalidDecl() && !NewFD->isDependentContext())
12058+
getASTContext().registerSYCLEntryPointFunction(NewFD);
12059+
1205612060
// Semantic checking for this function declaration (in isolation).
1205712061

1205812062
if (getLangOpts().CPlusPlus) {

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6606,6 +6606,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
66066606
case ParsedAttr::AT_SYCLKernel:
66076607
S.SYCL().handleKernelAttr(D, AL);
66086608
break;
6609+
case ParsedAttr::AT_SYCLKernelEntryPoint:
6610+
S.SYCL().handleKernelEntryPointAttr(D, AL);
6611+
break;
66096612
case ParsedAttr::AT_SYCLSpecialClass:
66106613
handleSimpleAttribute<SYCLSpecialClassAttr>(S, D, AL);
66116614
break;

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,12 @@ void SemaSYCL::handleKernelAttr(Decl *D, const ParsedAttr &AL) {
198198

199199
handleSimpleAttribute<SYCLKernelAttr>(*this, D, AL);
200200
}
201+
202+
void SemaSYCL::handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL) {
203+
ParsedType PT = AL.getTypeArg();
204+
TypeSourceInfo *TSI = nullptr;
205+
(void)SemaRef.GetTypeFromParser(PT, &TSI);
206+
assert(TSI && "no type source info for attribute argument");
207+
D->addAttr(::new (SemaRef.Context) SYCLKernelEntryPointAttr(SemaRef.Context,
208+
AL, TSI));
209+
}

clang/lib/Serialization/ASTReaderDecl.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,6 +1155,15 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
11551155
for (unsigned I = 0; I != NumParams; ++I)
11561156
Params.push_back(readDeclAs<ParmVarDecl>());
11571157
FD->setParams(Reader.getContext(), Params);
1158+
1159+
// If the declaration is a SYCL kernel entry point function as indicated by
1160+
// the presence of a sycl_kernel_entry_point attribute, register it so that
1161+
// associated metadata is recreated.
1162+
if (!FD->isInvalidDecl() && !FD->isDependentContext() &&
1163+
FD->hasAttr<SYCLKernelEntryPointAttr>()) {
1164+
ASTContext &C = Reader.getContext();
1165+
C.registerSYCLEntryPointFunction(FD);
1166+
}
11581167
}
11591168

11601169
void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {

0 commit comments

Comments
 (0)