Skip to content

Commit 0b57d81

Browse files
committed
Address code review feedback from Erich Keane.
1 parent 870a49e commit 0b57d81

File tree

3 files changed

+139
-29
lines changed

3 files changed

+139
-29
lines changed

clang/include/clang/AST/SYCLKernelInfo.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ class SYCLKernelInfo {
2626
: KernelNameType(KernelNameType),
2727
KernelEntryPointDecl(KernelEntryPointDecl) {}
2828

29-
CanQualType GetKernelNameType() const { return KernelNameType; }
29+
CanQualType getKernelNameType() const { return KernelNameType; }
3030

31-
const FunctionDecl *GetKernelEntryPointDecl() const {
31+
const FunctionDecl *getKernelEntryPointDecl() const {
3232
return KernelEntryPointDecl;
3333
}
3434

clang/include/clang/Basic/AttrDocs.td

Lines changed: 134 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -458,34 +458,33 @@ The SYCL kernel in the previous code sample meets these expectations.
458458
def SYCLKernelEntryPointDocs : Documentation {
459459
let Category = DocCatFunction;
460460
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.
461+
The ``sycl_kernel_entry_point`` attribute facilitates the generation of an
462+
offload kernel entry point, sometimes called a SYCL kernel caller function,
463+
suitable for invoking a SYCL kernel on an offload device. The attribute is
464+
intended for use in the implementation of SYCL kernel invocation functions
465+
like the ``single_task`` and ``parallel_for`` member functions of the
466+
``sycl::handler`` class specified in section 4.9.4, "Command group ``handler``
467+
class", of the SYCL 2020 specification.
467468

468469
The attribute requires a single type argument that specifies a class type that
469470
meets the requirements for a SYCL kernel name as described in section 5.2,
470471
"Naming of kernels", of the SYCL 2020 specification. A unique kernel name type
471472
is required for each function declared with the attribute. The attribute may
472473
not first appear on a declaration that follows a definition of the function.
473474

474-
The attribute appertains only to non-member functions and static member
475-
functions that meet the following requirements:
475+
The attribute only appertains to functions and only those that meet the
476+
following requirements.
476477

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.
478+
* Has a ``void`` return type.
479+
* Is not a non-static member function, constructor, or destructor.
480+
* Is not a C variadic function.
481+
* Is not a coroutine.
482+
* Is not defined as deleted or as defaulted.
483+
* Is not declared with the ``constexpr`` or ``consteval`` specifiers.
484+
* Is not declared with the ``[[noreturn]]`` attribute.
483485

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.
486+
Use in the implementation of a SYCL kernel invocation function might look as
487+
follows.
489488

490489
.. code-block:: c++
491490

@@ -500,16 +499,127 @@ SYCL 2020 specification. Such use might look something like the following.
500499
public:
501500
template<typename KernelNameType, typename KernelType>
502501
void single_task(KernelType kernel) {
502+
// Call kernel_entry_point() to trigger generation of an offload
503+
// kernel entry point.
503504
kernel_entry_point<KernelNameType>(kernel);
505+
// Call functions appropriate for the desired offload backend
506+
// (OpenCL, CUDA, HIP, Level Zero, etc...).
504507
}
505508
};
506509
} // namespace sycl
507510

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.
511+
A SYCL kernel is a callable object of class type that is constructed on a host,
512+
often via a lambda expression, and then passed to a SYCL kernel invocation
513+
function to be executed on an offload device. A SYCL kernel invocation function
514+
is responsible for copying the provided SYCL kernel object to an offload
515+
device and initiating a call to it. The SYCL kernel object and its data members
516+
constitute the parameters of an offload kernel.
517+
518+
A SYCL kernel type is required to satisfy the device copyability requirements
519+
specified in section 3.13.1, "Device copyable", of the SYCL 2020 specification.
520+
Additionally, any data members of the kernel object type are required to satisfy
521+
section 4.12.4, "Rules for parameter passing to kernels". For most types, these
522+
rules require that the type is trivially copyable. However, the SYCL
523+
specification mandates that certain special SYCL types, such as
524+
``sycl::accessor`` and ``sycl::stream`` be device copyable even if they are not
525+
trivially copyable. These types require special handling because they cannot
526+
be copied to device memory as if by ``memcpy()``. Additionally, some offload
527+
backends, OpenCL for example, require objects of some of these types to be
528+
passed as individual arguments to the offload kernel.
529+
530+
An offload kernel consists of an entry point function that declares the
531+
parameters of the offload kernel and the set of all functions and variables that
532+
are directly or indirectly used by the entry point function.
533+
534+
A SYCL kernel invocation function invokes a SYCL kernel on a device by
535+
performing the following tasks (likely with the help of an offload backend
536+
like OpenCL):
537+
538+
#. Identifying the offload kernel entry point to be used for the SYCL kernel.
539+
540+
#. Deconstructing the SYCL kernel object, if necessary, to produce the set of
541+
offload kernel arguments required by the offload kernel entry point.
542+
543+
#. Copying the offload kernel arguments to device memory.
544+
545+
#. Initiating execution of the offload kernel entry point.
546+
547+
The offload kernel entry point for a SYCL kernel performs the following tasks:
548+
549+
#. Reconstituting the SYCL kernel object, if necessary, using the offload
550+
kernel parameters.
551+
552+
#. Calling the ``operator()`` member function of the (reconstituted) SYCL kernel
553+
object.
554+
555+
The ``sycl_kernel_entry_point`` attribute automates generation of an offload
556+
kernel entry point that performs those latter tasks. The parameters and body of
557+
a function declared with the ``sycl_kernel_entry_point`` attribute specify a
558+
pattern from which the parameters and body of the entry point function are
559+
derived. Consider the following call to a SYCL kernel invocation function.
560+
561+
.. code-block:: c++
562+
563+
struct S { int i; };
564+
void f(sycl::handler &handler, sycl::stream &sout, S s) {
565+
handler.single_task<struct KN>([=] {
566+
sout << "The value of s.i is " << s.i << "\n";
567+
});
568+
}
569+
570+
The SYCL kernel object is the result of the lambda expression. It has two
571+
data members corresponding to the captures of ``sout`` and ``s``. Since one
572+
of these data members corresponds to a special SYCL type that must be passed
573+
individually as an offload kernel parameter, it is necessary to decompose the
574+
SYCL kernel object into its constituent parts; the offload kernel will have
575+
two kernel parameters. Given a SYCL implementation that uses a
576+
``sycl_kernel_entry_point`` attributed function like the one shown above, an
577+
offload kernel entry point function will be generated that looks approximately
578+
as follows.
579+
580+
.. code-block:: c++
581+
582+
void sycl-kernel-caller-for-KN(sycl::stream sout, S s) {
583+
kernel-type kernel = { sout, s );
584+
kernel();
585+
}
586+
587+
There are a few items worthy of note:
588+
589+
#. The name of the generated function incorporates the SYCL kernel name,
590+
``KN``, that was passed as the ``KernelNameType`` template parameter to
591+
``kernel_entry_point()`` and provided as the argument to the
592+
``sycl_kernel_entry_point`` attribute. There is a one-to-one correspondence
593+
between SYCL kernel names and offload kernel entry points.
594+
595+
#. The SYCL kernel is a lambda closure type and therefore has no name;
596+
``kernel-type`` is substituted above and corresponds to the ``KernelType``
597+
template parameter deduced in the call to ``kernel_entry_point()``.
598+
Lambda types cannot be declared and initialized using the aggregate
599+
initialization syntax used above, but the intended behavior should be clear.
600+
601+
#. ``S`` is a device copyable type that does not directly or indirectly contain
602+
a data member of a SYCL special type. It therefore does not need to be
603+
decomposed into its constituent members to be passed as a kernel argument.
604+
605+
#. The call to ``kernel_entry_point()`` has no effect other than to trigger
606+
emission of the entry point function. The statments that make up the body
607+
of the function are not executed when the function is called; they are
608+
only used in the generation of the entry point function.
609+
610+
It is not necessary for a function declared with the ``sycl_kernel_entry_point``
611+
attribute to be called for the offload kernel entry point to be emitted. For
612+
inline functions and function templates, any ODR-use will suffice. For other
613+
functions, an ODR-use is not required; the offload kernel entry point will be
614+
emitted if the function is defined.
615+
616+
Functions declared with the ``sycl_kernel_entry_point`` attribute are not
617+
limited to the simple example shown above. They may have additional template
618+
parameters, declare additional function parameters, and have complex control
619+
flow in the function body. Function parameter decomposition and reconstitution
620+
is performed for all function parameters. The function must abide by the
621+
language feature restrictions described in section 5.4, "Language restrictions
622+
for device functions" in the SYCL 2020 specification.
513623
}];
514624
}
515625

clang/lib/AST/ASTContext.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14312,11 +14312,11 @@ void ASTContext::registerSYCLEntryPointFunction(FunctionDecl *FD) {
1431214312
CanQualType KernelNameType = getCanonicalType(SKEPAttr->getKernelName());
1431314313
auto IT = SYCLKernels.find(KernelNameType);
1431414314
if (IT != SYCLKernels.end()) {
14315-
if (!declaresSameEntity(FD, IT->second.GetKernelEntryPointDecl()))
14315+
if (!declaresSameEntity(FD, IT->second.getKernelEntryPointDecl()))
1431614316
llvm::report_fatal_error("SYCL kernel name conflict");
1431714317
} else {
14318-
SYCLKernels.insert_or_assign(
14319-
KernelNameType, BuildSYCLKernelInfo(*this, KernelNameType, FD));
14318+
SYCLKernels.insert(std::make_pair(
14319+
KernelNameType, BuildSYCLKernelInfo(*this, KernelNameType, FD)));
1432014320
}
1432114321
}
1432214322

0 commit comments

Comments
 (0)