Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SYCL] The sycl_kernel_entry_point attribute. #111389

Merged
merged 9 commits into from
Nov 5, 2024
12 changes: 12 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/RawCommentList.h"
#include "clang/AST/SYCLKernelInfo.h"
#include "clang/AST/TemplateName.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/PartialDiagnostic.h"
Expand Down Expand Up @@ -1222,6 +1223,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// in device compilation.
llvm::DenseSet<const FunctionDecl *> CUDAImplicitHostDeviceFunUsedByDevice;

/// Map of SYCL kernels indexed by the unique type used to name the kernel.
/// Entries are not serialized but are recreated on deserialization of a
/// sycl_kernel_entry_point attributed function declaration.
llvm::DenseMap<CanQualType, SYCLKernelInfo> SYCLKernels;

/// For capturing lambdas with an explicit object parameter whose type is
/// derived from the lambda type, we need to perform derived-to-base
/// conversion so we can access the captures; the cast paths for that
Expand Down Expand Up @@ -3301,6 +3307,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
GlobalDecl GD) const;

/// Generates and stores SYCL kernel metadata for the provided
/// SYCL kernel entry point function. The provided function must have
/// an attached sycl_kernel_entry_point attribute that specifies a unique
/// type for the name of a SYCL kernel.
void registerSYCLEntryPointFunction(FunctionDecl *FD);

//===--------------------------------------------------------------------===//
// Statistics
//===--------------------------------------------------------------------===//
Expand Down
47 changes: 47 additions & 0 deletions clang/include/clang/AST/SYCLKernelInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//===--- SYCLKernelInfo.h --- Information about SYCL kernels --------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
/// This file declares types used to describe SYCL kernels.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_AST_SYCLKERNELINFO_H
#define LLVM_CLANG_AST_SYCLKERNELINFO_H

#include <string>
#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"

namespace clang {

class SYCLKernelInfo {
public:
SYCLKernelInfo(
CanQualType KernelNameType,
const FunctionDecl *KernelEntryPointDecl)
:
KernelNameType(KernelNameType),
KernelEntryPointDecl(KernelEntryPointDecl)
{}

CanQualType GetKernelNameType() const {
tahonermann marked this conversation as resolved.
Show resolved Hide resolved
return KernelNameType;
}

const FunctionDecl* GetKernelEntryPointDecl() const {
tahonermann marked this conversation as resolved.
Show resolved Hide resolved
return KernelEntryPointDecl;
}

private:
CanQualType KernelNameType;
const FunctionDecl *KernelEntryPointDecl;
};

} // namespace clang

#endif // LLVM_CLANG_AST_SYCLKERNELINFO_H
16 changes: 13 additions & 3 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,8 @@ def MicrosoftExt : LangOpt<"MicrosoftExt">;
def Borland : LangOpt<"Borland">;
def CUDA : LangOpt<"CUDA">;
def HIP : LangOpt<"HIP">;
def SYCL : LangOpt<"SYCLIsDevice">;
def SYCLHost : LangOpt<"SYCLIsHost">;
erichkeane marked this conversation as resolved.
Show resolved Hide resolved
def SYCLDevice : LangOpt<"SYCLIsDevice">;
def COnly : LangOpt<"", "!LangOpts.CPlusPlus">;
def CPlusPlus : LangOpt<"CPlusPlus">;
def OpenCL : LangOpt<"OpenCL">;
Expand Down Expand Up @@ -1489,14 +1490,23 @@ def : MutualExclusions<[CUDAConstant, CUDAShared, HIPManaged]>;
def SYCLKernel : InheritableAttr {
let Spellings = [Clang<"sycl_kernel">];
let Subjects = SubjectList<[FunctionTmpl]>;
let LangOpts = [SYCL];
let LangOpts = [SYCLDevice];
let Documentation = [SYCLKernelDocs];
}

def SYCLKernelEntryPoint : InheritableAttr {
let Spellings = [Clang<"sycl_kernel_entry_point">];
let Args = [TypeArgument<"KernelName">];
let Subjects = SubjectList<[Function], ErrorDiag>;
let TemplateDependent = 1;
let LangOpts = [SYCLHost, SYCLDevice];
let Documentation = [SYCLKernelEntryPointDocs];
}

def SYCLSpecialClass: InheritableAttr {
let Spellings = [Clang<"sycl_special_class">];
let Subjects = SubjectList<[CXXRecord]>;
let LangOpts = [SYCL];
let LangOpts = [SYCLDevice];
let Documentation = [SYCLSpecialClassDocs];
}

Expand Down
58 changes: 58 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,64 @@ The SYCL kernel in the previous code sample meets these expectations.
}];
}

def SYCLKernelEntryPointDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
The ``sycl_kernel_entry_point`` attribute specifies that a function definition
tahonermann marked this conversation as resolved.
Show resolved Hide resolved
defines a pattern for an offload kernel entry point function to be emitted when
the source code is compiled with ``-fsycl`` for a device target. Such functions
serve as the execution entry point for a SYCL run-time library to invoke a SYCL
kernel on a device. The function's parameters define the parameters to the
offload kernel.

The attribute requires a single type argument that specifies a class type that
tahonermann marked this conversation as resolved.
Show resolved Hide resolved
meets the requirements for a SYCL kernel name as described in section 5.2,
"Naming of kernels", of the SYCL 2020 specification. A unique kernel name type
is required for each function declared with the attribute. The attribute may
not first appear on a declaration that follows a definition of the function.

The attribute appertains only to non-member functions and static member
tahonermann marked this conversation as resolved.
Show resolved Hide resolved
functions that meet the following requirements:

- Has a ``void`` return type.
- Is not a variadic function.
tahonermann marked this conversation as resolved.
Show resolved Hide resolved
- Is not a coroutine.
- Is not defined as deleted or as defaulted.
tahonermann marked this conversation as resolved.
Show resolved Hide resolved
- Is not declared with the ``constexpr`` or ``consteval`` specifiers.
tahonermann marked this conversation as resolved.
Show resolved Hide resolved
- Is not declared with the ``[[noreturn]]`` attribute.

This attribute is intended for use in the implementation of SYCL run-time
tahonermann marked this conversation as resolved.
Show resolved Hide resolved
libraries that implement SYCL kernel invocation functions like the
``single_task`` and ``parallel_for`` member functions of the ``sycl::handler``
class specified in section 4.9.4, "Command group ``handler`` class" of the
SYCL 2020 specification. Such use might look something like the following.

.. code-block:: c++

namespace sycl {
class handler {
template<typename KernelNameType, typename KernelType>
[[ clang::sycl_kernel_entry_point(KernelNameType) ]]
static void kernel_entry_point(KernelType kernel) {
kernel();
}

public:
template<typename KernelNameType, typename KernelType>
void single_task(KernelType kernel) {
kernel_entry_point<KernelNameType>(kernel);
}
};
} // namespace sycl

It is not necessary for a SYCL kernel entry point function to be called for
the offload kernel entry point to be emitted. For inline functions and function
templates, any ODR-use will suffice. For other functions, an ODR-use is not
required; the offload kernel entry point will be emitted if the function is
defined.
}];
}

def SYCLSpecialClassDocs : Documentation {
let Category = DocCatStmt;
let Content = [{
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Sema/SemaSYCL.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class SemaSYCL : public SemaBase {
ParsedType ParsedTy);

void handleKernelAttr(Decl *D, const ParsedAttr &AL);
void handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL);
};

} // namespace clang
Expand Down
25 changes: 25 additions & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14296,6 +14296,31 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
}
}

static SYCLKernelInfo BuildSYCLKernelInfo(ASTContext &Context,
tahonermann marked this conversation as resolved.
Show resolved Hide resolved
CanQualType KernelNameType,
const FunctionDecl *FD) {
return { KernelNameType, FD };
}

void ASTContext::registerSYCLEntryPointFunction(FunctionDecl *FD) {
assert(!FD->isInvalidDecl());
assert(!FD->isDependentContext());
tahonermann marked this conversation as resolved.
Show resolved Hide resolved

const auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>();
assert(SKEPAttr && "Missing sycl_kernel_entry_point attribute");

CanQualType KernelNameType = getCanonicalType(SKEPAttr->getKernelName());
auto IT = SYCLKernels.find(KernelNameType);
if (IT != SYCLKernels.end()) {
if (!declaresSameEntity(FD, IT->second.GetKernelEntryPointDecl()))
llvm::report_fatal_error("SYCL kernel name conflict");
tahonermann marked this conversation as resolved.
Show resolved Hide resolved
} else {
SYCLKernels.insert_or_assign(
tahonermann marked this conversation as resolved.
Show resolved Hide resolved
KernelNameType,
BuildSYCLKernelInfo(*this, KernelNameType, FD));
}
}

OMPTraitInfo &ASTContext::getNewOMPTraitInfo() {
OMPTraitInfoVector.emplace_back(new OMPTraitInfo());
return *OMPTraitInfoVector.back();
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12053,6 +12053,10 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (LangOpts.OpenMP)
OpenMP().ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(NewFD);

if (LangOpts.isSYCL() && NewFD->hasAttr<SYCLKernelEntryPointAttr>() &&
!NewFD->isInvalidDecl() && !NewFD->isDependentContext())
tahonermann marked this conversation as resolved.
Show resolved Hide resolved
getASTContext().registerSYCLEntryPointFunction(NewFD);

// Semantic checking for this function declaration (in isolation).

if (getLangOpts().CPlusPlus) {
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6606,6 +6606,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_SYCLKernel:
S.SYCL().handleKernelAttr(D, AL);
break;
case ParsedAttr::AT_SYCLKernelEntryPoint:
S.SYCL().handleKernelEntryPointAttr(D, AL);
break;
case ParsedAttr::AT_SYCLSpecialClass:
handleSimpleAttribute<SYCLSpecialClassAttr>(S, D, AL);
break;
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Sema/SemaSYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,12 @@ void SemaSYCL::handleKernelAttr(Decl *D, const ParsedAttr &AL) {

handleSimpleAttribute<SYCLKernelAttr>(*this, D, AL);
}

void SemaSYCL::handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL) {
ParsedType PT = AL.getTypeArg();
TypeSourceInfo *TSI = nullptr;
(void)SemaRef.GetTypeFromParser(PT, &TSI);
assert(TSI && "no type source info for attribute argument");
tahonermann marked this conversation as resolved.
Show resolved Hide resolved
D->addAttr(::new (SemaRef.Context) SYCLKernelEntryPointAttr(SemaRef.Context,
AL, TSI));
}
9 changes: 9 additions & 0 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1155,6 +1155,15 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
for (unsigned I = 0; I != NumParams; ++I)
Params.push_back(readDeclAs<ParmVarDecl>());
FD->setParams(Reader.getContext(), Params);

// If the declaration is a SYCL kernel entry point function as indicated by
// the presence of a sycl_kernel_entry_point attribute, register it so that
// associated metadata is recreated.
if (!FD->isInvalidDecl() && !FD->isDependentContext() &&
tahonermann marked this conversation as resolved.
Show resolved Hide resolved
FD->hasAttr<SYCLKernelEntryPointAttr>()) {
ASTContext &C = Reader.getContext();
C.registerSYCLEntryPointFunction(FD);
}
}

void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
Expand Down
Loading
Loading