[clang] [SYCL] SYCL host kernel launch support for the sycl_kernel_entry_point attribute. (PR #152403)
Tom Honermann via cfe-commits
cfe-commits at lists.llvm.org
Wed Dec 10 09:31:43 PST 2025
================
@@ -0,0 +1,541 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-device -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-device -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -fsyntax-only -fsycl-is-device -verify %s
+
+// Test overload resolution for implicit calls to sycl_kernel_launch<KN>(...)
+// synthesized for functions declared with the sycl_kernel_entry_point
+// attribute.
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Valid declarations.
+////////////////////////////////////////////////////////////////////////////////
+
+// A unique kernel name type is required for each declared kernel entry point.
+template<int, int = 0> struct KN;
+
+// A generic kernel object type.
+template<int, int = 0>
+struct KT {
+ void operator()() const;
+};
+
+
+// sycl_kernel_launch as function template at namespace scope.
+namespace ok1 {
+ template<typename KN, typename... Ts>
+ void sycl_kernel_launch(const char *, Ts...);
+ [[clang::sycl_kernel_entry_point(KN<1>)]]
+ void skep(KT<1> k) {
+ k();
+ }
+}
+
+// sycl_kernel_launch as function template at namespace scope with default
+// template arguments and default function arguments..
+namespace ok2 {
+ template<typename KN, typename T = int>
+ void sycl_kernel_launch(const char *, KT<2>, T = 2);
+ [[clang::sycl_kernel_entry_point(KN<2>)]]
+ void skep(KT<2> k) {
+ k();
+ }
+}
+
+// sycl_kernel_launch as overload set.
+namespace ok3 {
+ template<typename KN>
+ void sycl_kernel_launch(const char *);
+ template<typename KN, typename... Ts>
+ void sycl_kernel_launch(const char *, Ts...);
+ [[clang::sycl_kernel_entry_point(KN<3>)]]
+ void skep(KT<3> k) {
+ k();
+ }
+}
+
+// sycl_kernel_launch as static member function template.
+namespace ok4 {
+ struct handler {
+ private:
+ template<typename KN, typename... Ts>
+ static void sycl_kernel_launch(const char *, Ts...);
+ public:
+ [[clang::sycl_kernel_entry_point(KN<4,0>)]]
+ static void skep(KT<4,0> k) {
+ k();
+ }
+ [[clang::sycl_kernel_entry_point(KN<4,1>)]]
+ void skep(KT<4,1> k) {
+ k();
+ }
+ };
+}
+
+// sycl_kernel_launch as non-static member function template.
+namespace ok5 {
+ struct handler {
+ private:
+ template<typename KN, typename... Ts>
+ void sycl_kernel_launch(const char *, Ts...);
+ public:
+ [[clang::sycl_kernel_entry_point(KN<5>)]]
+ void skep(KT<5> k) {
+ k();
+ }
+ };
+}
+
+#if __cplusplus >= 202302L
+// sycl_kernel_launch as non-static member function template with explicit
+// object parameter.
+namespace ok6 {
+ struct handler {
+ private:
+ template<typename KN, typename... Ts>
+ void sycl_kernel_launch(this handler self, const char *, Ts...);
+ public:
+ [[clang::sycl_kernel_entry_point(KN<6>)]]
+ void skep(KT<6> k) {
+ k();
+ }
+ };
+}
+#endif
+
+// sycl_kernel_launch as variable template.
+namespace ok7 {
+ template<typename KN>
+ struct launcher {
+ template<typename... Ts>
+ void operator()(const char *, Ts...);
+ };
+ template<typename KN>
+ launcher<KN> sycl_kernel_launch;
+ [[clang::sycl_kernel_entry_point(KN<7>)]]
+ void skep(KT<7> k) {
+ k();
+ }
+}
+
+#if __cplusplus >= 202302L
+// sycl_kernel_launch as variable template with static call operator template.
+namespace ok8 {
+ template<typename KN>
+ struct launcher {
+ template<typename... Ts>
+ static void operator()(const char *, Ts...);
+ };
+ template<typename KN>
+ launcher<KN> sycl_kernel_launch;
+ [[clang::sycl_kernel_entry_point(KN<8>)]]
+ void skep(KT<8> k) {
+ k();
+ }
+}
+#endif
+
+#if __cplusplus >= 202302L
+// sycl_kernel_launch as variable template with call operator template with
+// explicit object parameter.
+namespace ok9 {
+ template<typename KN>
+ struct launcher {
+ template<typename... Ts>
+ void operator()(this launcher self, const char *, Ts...);
+ };
+ template<typename KN>
+ launcher<KN> sycl_kernel_launch;
+ [[clang::sycl_kernel_entry_point(KN<9>)]]
+ void skep(KT<9> k) {
+ k();
+ }
+}
+#endif
+
+// sycl_kernel_launch as base class non-static member function template.
+namespace ok10 {
+ template<typename Derived>
+ struct base_handler {
+ protected:
+ template<typename KN, typename... Ts>
+ void sycl_kernel_launch(const char *, Ts...);
+ };
+ struct handler : protected base_handler<handler> {
+ public:
+ [[clang::sycl_kernel_entry_point(KN<10>)]]
+ void skep(KT<10> k) {
+ k();
+ }
+ };
+}
+
+// sycl_kernel_launch with non-reference parameters.
+namespace ok11 {
+ template<typename KN, typename... Ts>
+ void sycl_kernel_launch(const char *, Ts...);
+ struct move_only {
+ move_only(move_only&&) = default;
+ };
+ [[clang::sycl_kernel_entry_point(KN<11>)]]
+ void skep(KT<11> k, move_only) {
+ k();
+ }
+}
+
+// sycl_kernel_launch with forward reference parameters.
+namespace ok12 {
+ template<typename KN, typename... Ts>
+ void sycl_kernel_launch(const char *, Ts &&...);
+ struct non_copyable {
+ non_copyable(const non_copyable&) = delete;
+ };
+ struct non_moveable {
+ non_moveable(non_moveable&&) = delete;
+ };
+ struct move_only {
+ move_only(move_only&&) = default;
+ };
+ [[clang::sycl_kernel_entry_point(KN<12>)]]
+ void skep(KT<12> k, non_copyable, non_moveable, move_only) {
+ k();
+ }
+}
+
+// ADL for sycl_kernel_launch.
+namespace ok13 {
+ template<typename KN, typename KT, typename T>
+ [[clang::sycl_kernel_entry_point(KN)]]
+ void skep(KT k, T t) {
+ k();
+ }
+ namespace nested {
+ template<typename KN, typename... Ts>
+ void sycl_kernel_launch(const char *, Ts...);
+ struct S13 {};
+ }
+ template void skep<KN<13>>(KT<13>, nested::S13);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Invalid declarations.
+////////////////////////////////////////////////////////////////////////////////
+
+// A unique kernel name type is required for each declared kernel entry point.
+template<int, int = 0> struct BADKN;
+
+// A generic kernel object type.
+template<int, int = 0>
+struct BADKT {
+ void operator()() const;
+};
+
+
+// Undeclared sycl_kernel_launch identifier from non-template function.
+namespace bad1 {
+ // expected-error at +3 {{use of undeclared identifier 'sycl_kernel_launch'}}
+ // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<1>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<1>') required here}}
+ [[clang::sycl_kernel_entry_point(BADKN<1>)]]
+ void skep(BADKT<1> k) {
+ k();
+ }
+}
+
+// Undeclared sycl_kernel_launch identifier from function template.
+namespace bad2 {
+ // expected-error at +4 {{use of undeclared identifier 'sycl_kernel_launch'}}
+ // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<2>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<2>') required here}}
+ template<typename KN, typename KT>
+ [[clang::sycl_kernel_entry_point(KN)]]
+ void skep(KT k) {
+ k();
+ }
+ // expected-note at +1 {{in instantiation of function template specialization 'bad2::skep<BADKN<2>, BADKT<2>>' requested here}}
+ template void skep<BADKN<2>>(BADKT<2>);
+}
+
+// No matching function for call to sycl_kernel_launch; not a template.
+namespace bad3 {
+ // expected-note at +1 {{declared as a non-template here}}
+ void sycl_kernel_launch(const char *, BADKT<3>);
+ // expected-error at +3 {{'sycl_kernel_launch' does not refer to a template}}
+ // expected-note at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<3>' required here}}
+ [[clang::sycl_kernel_entry_point(BADKN<3>)]]
+ void skep(BADKT<3> k) {
+ k();
+ }
+}
+
+// No matching function for call to sycl_kernel_launch; not enough arguments.
+namespace bad4 {
+ // expected-note at +2 {{candidate function template not viable: requires 2 arguments, but 1 was provided}}
+ template<typename KN, typename KT>
+ void sycl_kernel_launch(const char *, KT);
+ // expected-error at +4 {{no matching function for call to 'sycl_kernel_launch'}}
+ // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<4>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]') required here}}
+ template<typename KN>
+ [[clang::sycl_kernel_entry_point(KN)]]
+ void skep() {}
+ // expected-note at +1 {{in instantiation of function template specialization 'bad4::skep<BADKN<4>>' requested here}}
+ template void skep<BADKN<4>>();
+}
+
+// No matching function for call to sycl_kernel_launch; too many arguments.
+namespace bad5 {
+ // expected-note at +2 {{candidate function template not viable: requires 2 arguments, but 3 were provided}}
+ template<typename KN, typename KT>
+ void sycl_kernel_launch(const char *, KT);
+ // expected-error at +4 {{no matching function for call to 'sycl_kernel_launch'}}
+ // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<5>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<5>', xvalue of type 'int') required here}}
----------------
tahonermann wrote:
I recognize that this is novel and I welcome suggestions for how to do better.
The reason I went with this approach is because there is no source line to refer to, so a diagnostic can't reference a line of code for the (SYCL RT) programmer to refer to in order to understand how arguments are passed. Debugging an overload resolution failure requires knowing the number of arguments, their types, and their value categories. The diagnostic notes for candidates don't necessarily suffice on their own to understand what is going wrong without this additional information.
https://github.com/llvm/llvm-project/pull/152403
More information about the cfe-commits
mailing list