Files
clang-p2996/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp
Tom Honermann 8ea8e7f529 [SYCL] Basic diagnostics for the sycl_kernel_entry_point attribute. (#120327)
The `sycl_kernel_entry_point` attribute is used to declare a function that
defines a pattern for an offload kernel entry point. The attribute requires
a single type argument that specifies a class type that 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 function is
required to have a non-deduced `void` return type. The function must not be
a non-static member function, be deleted or defaulted, be declared with the
`constexpr` or `consteval` specifiers, be declared with the `[[noreturn]]`
attribute, be a coroutine, or accept variadic arguments.

Diagnostics are not yet provided for the following:
- Use of a type as a kernel name that does not satisfy the forward
  declarability requirements specified in section 5.2, "Naming of kernels",
  of the SYCL 2020 specification.
- Use of a type as a parameter of the attributed function that does not
  satisfy the kernel parameter requirements specified in section 4.12.4,
  "Rules for parameter passing to kernels", of the SYCL 2020 specification
  (each such function parameter constitutes a kernel parameter).
- Use of language features that are not permitted in device functions as
  specified in section 5.4, "Language restrictions for device functions",
  of the SYCL 2020 specification.

There are several issues noted by various FIXME comments.
- The diagnostic generated for kernel name conflicts needs additional work
  to better detail the relevant source locations; such as the location of
  each declaration as well as the original source of each kernel name.
- A number of the tests illustrate spurious errors being produced due to
  attributes that appertain to function templates being instantiated too
  early (during overload resolution as opposed to after an overload is
  selected).

Included changes allow the `SYCLKernelEntryPointAttr` attribute to be
marked as invalid if a `sycl_kernel_entry_point` attribute is used incorrectly.
This is intended to prevent trying to emit an offload kernel entry point
without having to mark the associated function as invalid since doing so
would affect overload resolution; which this attribute should not do.
Unfortunately, Clang eagerly instantiates attributes that appertain to
functions with the result that errors might be issued for function
declarations that are never selected by overload resolution. Tests have
been added to demonstrate this. Further work will be needed to address
these issues (for this and other attributes).
2025-01-09 15:42:29 -05:00

160 lines
6.6 KiB
C++

// Tests without serialization:
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-device \
// RUN: -ast-dump %s \
// RUN: | FileCheck --match-full-lines %s
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-host \
// RUN: -ast-dump %s \
// RUN: | FileCheck --match-full-lines %s
//
// Tests with serialization:
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-device \
// RUN: -emit-pch -o %t %s
// RUN: %clang_cc1 -x c++ -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-device \
// RUN: -include-pch %t -ast-dump-all /dev/null \
// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \
// RUN: | FileCheck --match-full-lines %s
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-host \
// RUN: -emit-pch -o %t %s
// RUN: %clang_cc1 -x c++ -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-host \
// RUN: -include-pch %t -ast-dump-all /dev/null \
// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \
// RUN: | FileCheck --match-full-lines %s
// These tests validate the AST produced for functions declared with the
// sycl_kernel_entry_point attribute.
// CHECK: TranslationUnitDecl {{.*}}
// A unique kernel name type is required for each declared kernel entry point.
template<int, int=0> struct KN;
__attribute__((sycl_kernel_entry_point(KN<1>)))
void skep1() {
}
// CHECK: |-FunctionDecl {{.*}} skep1 'void ()'
// CHECK: | `-SYCLKernelEntryPointAttr {{.*}} KN<1>
using KN2 = KN<2>;
__attribute__((sycl_kernel_entry_point(KN2)))
void skep2() {
}
// CHECK: |-FunctionDecl {{.*}} skep2 'void ()'
// CHECK: | `-SYCLKernelEntryPointAttr {{.*}} KN2
template<int I> using KNT = KN<I>;
__attribute__((sycl_kernel_entry_point(KNT<3>)))
void skep3() {
}
// CHECK: |-FunctionDecl {{.*}} skep3 'void ()'
// CHECK: | `-SYCLKernelEntryPointAttr {{.*}} KNT<3>
template<typename KNT, typename F>
[[clang::sycl_kernel_entry_point(KNT)]]
void skep4(F f) {
f();
}
// CHECK: |-FunctionTemplateDecl {{.*}} skep4
// CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} KNT
// CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} F
// CHECK-NEXT: | |-FunctionDecl {{.*}} skep4 'void (F)'
// CHECK: | | `-SYCLKernelEntryPointAttr {{.*}} KNT
void test_skep4() {
skep4<KNT<4>>([]{});
}
// CHECK: | `-FunctionDecl {{.*}} used skep4 'void ((lambda at {{.*}}))' implicit_instantiation
// CHECK-NEXT: | |-TemplateArgument type 'KN<4>'
// CHECK: | |-TemplateArgument type '(lambda at {{.*}})'
// CHECK: | `-SYCLKernelEntryPointAttr {{.*}} struct KN<4>
// CHECK-NEXT: |-FunctionDecl {{.*}} test_skep4 'void ()'
template<typename KNT, typename T>
[[clang::sycl_kernel_entry_point(KNT)]]
void skep5(T) {
}
// CHECK: |-FunctionTemplateDecl {{.*}} skep5
// CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} KNT
// CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} T
// CHECK-NEXT: | |-FunctionDecl {{.*}} skep5 'void (T)'
// CHECK: | | `-SYCLKernelEntryPointAttr {{.*}} KNT
// Checks for the explicit template instantiation declaration below.
// CHECK: | `-FunctionDecl {{.*}} skep5 'void (int)' explicit_instantiation_definition
// CHECK-NEXT: | |-TemplateArgument type 'KN<5, 4>'
// CHECK: | |-TemplateArgument type 'int'
// CHECK: | `-SYCLKernelEntryPointAttr {{.*}} KN<5, 4>
// FIXME: C++23 [temp.expl.spec]p12 states:
// FIXME: ... Similarly, attributes appearing in the declaration of a template
// FIXME: have no effect on an explicit specialization of that template.
// FIXME: Clang currently instantiates and propagates attributes from a function
// FIXME: template to its explicit specializations resulting in the following
// FIXME: explicit specialization having an attribute incorrectly attached.
template<>
void skep5<KN<5,1>>(short) {
}
// CHECK: |-FunctionDecl {{.*}} prev {{.*}} skep5 'void (short)' explicit_specialization
// CHECK-NEXT: | |-TemplateArgument type 'KN<5, 1>'
// CHECK: | |-TemplateArgument type 'short'
// CHECK: | `-SYCLKernelEntryPointAttr {{.*}} Inherited struct KN<5, 1>
template<>
[[clang::sycl_kernel_entry_point(KN<5,2>)]]
void skep5<KN<5,2>>(long) {
}
// CHECK: |-FunctionDecl {{.*}} prev {{.*}} skep5 'void (long)' explicit_specialization
// CHECK-NEXT: | |-TemplateArgument type 'KN<5, 2>'
// CHECK: | |-TemplateArgument type 'long'
// CHECK: | `-SYCLKernelEntryPointAttr {{.*}} KN<5, 2>
// FIXME: C++23 [temp.expl.spec]p12 states:
// FIXME: ... Similarly, attributes appearing in the declaration of a template
// FIXME: have no effect on an explicit specialization of that template.
// FIXME: Clang currently instantiates a function template specialization from
// FIXME: the function template declaration and links it as a previous
// FIXME: declaration of an explicit specialization. The instantiated
// FIXME: declaration includes attributes instantiated from the function
// FIXME: template declaration. When the instantiated declaration and the
// FIXME: explicit specialization both specify a sycl_kernel_entry_point
// FIXME: attribute with different kernel name types, a spurious diagnostic
// FIXME: is issued. The following test case is incorrectly diagnosed as
// FIXME: having conflicting kernel name types (KN<5,3> vs the incorrectly
// FIXME: inherited KN<5,-1>).
#if 0
template<>
[[clang::sycl_kernel_entry_point(KN<5,3>)]]
void skep5<KN<5,-1>>(long long) {
}
// FIXME-CHECK: |-FunctionDecl {{.*}} prev {{.*}} skep5 'void (long long)' explicit_specialization
// FIXME-CHECK-NEXT: | |-TemplateArgument type 'KN<5, -1>'
// FIXME-CHECK: | |-TemplateArgument type 'long long'
// FIXME-CHECK: | `-SYCLKernelEntryPointAttr {{.*}} KN<5, 3>
#endif
template void skep5<KN<5,4>>(int);
// Checks are located with the primary template declaration above.
// Ensure that matching attributes from multiple declarations are ok.
[[clang::sycl_kernel_entry_point(KN<6>)]]
void skep6();
[[clang::sycl_kernel_entry_point(KN<6>)]]
void skep6() {
}
// CHECK: |-FunctionDecl {{.*}} skep6 'void ()'
// CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<6>
// CHECK-NEXT: |-FunctionDecl {{.*}} prev {{.*}} skep6 'void ()'
// CHECK-NEXT: | |-CompoundStmt {{.*}}
// CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<6>
// Ensure that matching attributes from the same declaration are ok.
[[clang::sycl_kernel_entry_point(KN<7>), clang::sycl_kernel_entry_point(KN<7>)]]
void skep7() {
}
// CHECK: |-FunctionDecl {{.*}} skep7 'void ()'
// CHECK-NEXT: | |-CompoundStmt {{.*}}
// CHECK-NEXT: | |-SYCLKernelEntryPointAttr {{.*}} KN<7>
// CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<7>
void the_end() {}
// CHECK: `-FunctionDecl {{.*}} the_end 'void ()'