File: unique_stable_name.cpp

package info (click to toggle)
llvm-toolchain-13 1%3A13.0.1-11
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,418,840 kB
  • sloc: cpp: 5,290,826; ansic: 996,570; asm: 544,593; python: 188,212; objc: 72,027; lisp: 30,291; f90: 25,395; sh: 24,898; javascript: 9,780; pascal: 9,398; perl: 7,484; ml: 5,432; awk: 3,523; makefile: 2,913; xml: 953; cs: 573; fortran: 539
file content (215 lines) | stat: -rw-r--r-- 9,889 bytes parent folder | download | duplicates (3)
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
205
206
207
208
209
210
211
212
213
214
215
// 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
  // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
  // expected-note@#kernel1func_call{{in instantiation of function template specialization}}
  // expected-note@#USN_F1{{'__builtin_sycl_unique_stable_name' evaluated here}}
  // expected-note@+1{{in instantiation of function template specialization}}
  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
  // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
  // expected-note@#kernel2func_call{{in instantiation of function template specialization}}
  // expected-note@#USN_F2{{'__builtin_sycl_unique_stable_name' evaluated here}}
  // expected-note@+1{{in instantiation of function template specialization}}
  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 error
  // Test that passing the lambda to the unique stable name builtin and then
  // using the same lambda in the naming of a kernel causes 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
  // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
  // expected-note@#USN_l6{{'__builtin_sycl_unique_stable_name' evaluated here}}
  // expected-note@+1{{in instantiation of function template specialization}}
  kernel_single_task<class kernel6>(l6); // Used in the kernel name after builtin

  // kernel7 - expect 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 throws an error because the first
  // lambda is included in the signature of the second lambda, hence it changes
  // 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
  // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
  // expected-note@#USN_l7{{'__builtin_sycl_unique_stable_name' evaluated here}}
  // expected-note@+1{{in instantiation of function template specialization}}
  kernel_single_task<class kernel7>(l8);

  // kernel8 and kernel9 - expect error
  // Tests that passing a lambda to the unique stable name builtin and passing it
  // to a kernel called with an if constexpr branch causes a diagnostic on the
  // kernel9 use due to the change in the results to the stable name. This happens
  // 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 {
    // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
    // expected-note@#USN_l10{{'__builtin_sycl_unique_stable_name' evaluated here}}
    // expected-note@+1{{in instantiation of function template specialization}}
    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 an error
  // Test that passing a lambda to the unique stable name builtin and then
  // passing it to the kernel as a template template parameter causes 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
  // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
  // expected-note@#USN_l13{{'__builtin_sycl_unique_stable_name' evaluated here}}
  // expected-note@+1{{in instantiation of function template specialization}}
  kernel_single_task<class kernel12>(S<Tangerine, decltype(l13)>{});

  // kernel13 - expect an error
  // Test that passing a lambda to the unique stable name builtin within a macro
  // and then calling the macro within the kernel causes an error on the kernel
  // and diagnoses in all the expected places despite the use of a macro.
  // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
  // expected-note@#USN_MACRO{{'__builtin_sycl_unique_stable_name' evaluated here}}
  // expected-note@+1{{in instantiation of function template specialization}}
  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>();
}