1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
// RUN: %clang_cc1 %s -std=c++17 -triple x86_64-pc-windows-msvc -fsycl-is-device -verify -fsyntax-only -Wno-unused
// RUN: %clang_cc1 %s -std=c++17 -triple x86_64-linux-gnu -fsycl-is-device -verify -fsyntax-only -Wno-unused
template <typename KernelName, typename KernelType>
[[clang::sycl_kernel]] void kernel_single_task(KernelType kernelFunc) { // #kernelSingleTask
kernelFunc();
}
// kernel1 - expect error
// The current function is named with a lambda (i.e., takes a lambda as a
// template parameter. Call the builtin on the current function then it is
// passed to a kernel. Test that passing the given function to the unique
// stable name builtin and then to the kernel throws an error because the
// latter causes its name mangling to change.
template <typename Func>
void kernel1func(const Func &F1) {
constexpr const char *F1_output = __builtin_sycl_unique_stable_name(Func); // #USN_F1
kernel_single_task<class kernel1>(F1); // #kernel1_call
}
void callkernel1() {
kernel1func([]() {}); // #kernel1func_call
}
// kernel2 - expect error
// The current function is named with a lambda (i.e., takes a lambda as a
// template parameter). Call the builtin on the given function,
// then an empty lambda is passed to kernel.
// Test that passing the given function to the unique stable name builtin and
// then passing a different lambda to the kernel still throws an error because
// the calling context is part of naming the kernel. Even though the given
// function (F2) is not passed to the kernel, its mangling changes due to
// kernel call with the unrelated lambda.
template <typename Func>
void kernel2func(const Func &F2) {
constexpr const char *F2_output = __builtin_sycl_unique_stable_name(Func); // #USN_F2
kernel_single_task<class kernel2>([]() {});
}
void callkernel2() {
kernel2func([]() {}); // #kernel2func_call
}
template <template <typename> typename Outer, typename Inner>
struct S {
void operator()() const;
};
template <typename Ty>
struct Tangerine {};
template <typename Func>
void kernel3_4func(const Func &F) {
// Test that passing the same lambda to two kernels does not cause an error
// because the kernel uses do not interfere with each other or invalidate
// the stable name in any way.
kernel_single_task<class kernel3>(F);
kernel_single_task<class kernel4>(F);
// Using the same functor twice should be fine
}
// kernel3 and kernel4 - expect no errors
void callkernel3_4() {
kernel3_4func([]() {});
}
template <typename T>
static constexpr const char *output1 = __builtin_sycl_unique_stable_name(T);
#define MACRO() \
auto l14 = []() { return 1; }; \
constexpr const char *l14_output = \
__builtin_sycl_unique_stable_name(decltype(l14));
int main() {
// kernel5 - expect no error
// Test that passing the lambda to the unique stable name builtin and then
// using the lambda in a way that does not contribute to the kernel name
// does not cause an error because the stable name is not invalidated in
// this situation.
auto l5 = []() {};
constexpr const char *l5_output =
__builtin_sycl_unique_stable_name(decltype(l5));
kernel_single_task<class kernel5>(
[=]() { l5(); }); // Used in the kernel, but not the kernel name itself
// kernel6 - expect no error
// Test that passing the lambda to the unique stable name builtin and then
// using the same lambda in the naming of a kernel does not cause a diagnostic
// on the kernel use due to the change in results to the stable name.
auto l6 = []() { return 1; };
constexpr const char *l6_output =
__builtin_sycl_unique_stable_name(decltype(l6)); // #USN_l6
kernel_single_task<class kernel6>(l6); // Used in the kernel name after builtin
// kernel7 - expect no error
// Same as kernel11 (below) except make the lambda part of naming the kernel.
// Test that passing a lambda to the unique stable name builtin and then
// passing a second lambda to the kernel does not throw an error because the
// first lambda is included in the signature of the second lambda, but does
// not change the mangling of the kernel.
auto l7 = []() { return 1; };
auto l8 = [](decltype(l7) *derp = nullptr) { return 2; };
constexpr const char *l7_output =
__builtin_sycl_unique_stable_name(decltype(l7)); // #USN_l7
kernel_single_task<class kernel7>(l8);
// kernel8 and kernel9 - expect no error
// Tests that passing a lambda to the unique stable name builtin and passing
// it to a kernel called with an if constexpr branch does not cause a
// diagnostic on the kernel9 as it does not change the result to the stable
// name. This is interesting even though the use of kernel9 happens in the
// false branch of a constexpr if because both the true and the false branches
// cause the instantiation of kernel_single_task.
auto l9 = []() { return 1; };
auto l10 = []() { return 2; };
constexpr const char *l10_output =
__builtin_sycl_unique_stable_name(decltype(l10)); // #USN_l10
if constexpr (1) {
kernel_single_task<class kernel8>(l9);
} else {
kernel_single_task<class kernel9>(l10);
}
// kernel11 - expect no error
// Test that passing a lambda to the unique stable name builtin and then
// passing a second lambda capturing the first one to the kernel does not
// throw an error because the first lambda is not involved in naming the
// kernel i.e., the mangling does not change.
auto l11 = []() { return 1; };
auto l12 = [l11]() { return 2; };
constexpr const char *l11_output =
__builtin_sycl_unique_stable_name(decltype(l11));
kernel_single_task<class kernel11>(l12);
// kernel12 - expect no error
// Test that passing a lambda to the unique stable name builtin and then
// passing it to the kernel as a template template parameter does not cause a
// diagnostic on the kernel use due to template template parameter being
// involved in the mangling of the kernel name.
auto l13 = []() { return 1; };
constexpr const char *l13_output =
__builtin_sycl_unique_stable_name(decltype(l13)); // #USN_l13
kernel_single_task<class kernel12>(S<Tangerine, decltype(l13)>{});
// kernel13 - expect no error
// Test that passing a lambda to the unique stable name builtin within a macro
// and then calling the macro within the kernel does not cause an error on the
// kernel.
kernel_single_task<class kernel13>(
[]() {
MACRO(); // #USN_MACRO
});
}
namespace NS {}
void f() {
// expected-error@+1{{unknown type name 'bad_var'}}
__builtin_sycl_unique_stable_name(bad_var);
// expected-error@+1{{use of undeclared identifier 'bad'}}
__builtin_sycl_unique_stable_name(bad::type);
// expected-error@+1{{no type named 'still_bad' in namespace 'NS'}}
__builtin_sycl_unique_stable_name(NS::still_bad);
// FIXME: warning about side-effects in an unevaluated context expected, but
// none currently emitted.
int i = 0;
__builtin_sycl_unique_stable_name(decltype(i++));
// Tests that use within a VLA does not diagnose as a side-effecting use in
// an unevaluated context because the use within a VLA extent forces
// evaluation.
int j = 55;
__builtin_sycl_unique_stable_name(int[++j]); // no warning expected
}
template <typename T>
void f2() {
// expected-error@+1{{no type named 'bad_val' in 'St'}}
__builtin_sycl_unique_stable_name(typename T::bad_val);
// expected-error@+1{{no type named 'bad_type' in 'St'}}
__builtin_sycl_unique_stable_name(typename T::bad_type);
}
struct St {};
void use() {
// expected-note@+1{{in instantiation of}}
f2<St>();
}
// A previous implementation resulted in this being an example of the
// kernel-ordering and lexical lambda ordering issue.
void out_of_order_use() {
auto x = [](){};
auto y = [](){};
kernel_single_task<decltype(y)>(y);
constexpr auto USN =__builtin_sycl_unique_stable_name(decltype(y));
(void)USN;
kernel_single_task<decltype(x)>(x);
}
|