Skip to content

Commit dd7fec8

Browse files
authored
[SYCL] Support or diagnose use of namespace std types as kernel type names (#1963)
When std::nullptr_t is used as a kernel type, the generated integration header uses 'nullptr_t'. This causes lookup errors. Use 'std::nullptr_t' instead. std::max_align_t is defined (in one implementation) as a typedef of an anonymous struct. This causes errors when attempting to forward declare the type in the integration header. Diagnose such cases earlier. Signed-off-by: Premanand M Rao <[email protected]>
1 parent dc8a059 commit dd7fec8

27 files changed

+616
-421
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10982,6 +10982,7 @@ def err_sycl_kernel_incorrectly_named : Error<
1098210982
"kernel %select{name is missing"
1098310983
"|needs to have a globally-visible name"
1098410984
"|name is invalid. Unscoped enum requires fixed underlying type"
10985+
"|name cannot be a type in the \"std\" namespace"
1098510986
"}0">;
1098610987
def err_sycl_kernel_not_function_object
1098710988
: Error<"kernel parameter must be a lambda or function object">;

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2908,6 +2908,13 @@ void SYCLIntegrationHeader::emitFwdDecl(raw_ostream &O, const Decl *D,
29082908
}
29092909
break;
29102910
}
2911+
2912+
if (NS->isStdNamespace()) {
2913+
Diag.Report(KernelLocation, diag::err_sycl_kernel_incorrectly_named)
2914+
<< /* name cannot be a type in the std namespace */ 3;
2915+
return;
2916+
}
2917+
29112918
++NamespaceCnt;
29122919
const StringRef NSInlinePrefix = NS->isInline() ? "inline " : "";
29132920
NSStr.insert(
@@ -2990,8 +2997,13 @@ void SYCLIntegrationHeader::emitForwardClassDecls(
29902997
;
29912998
const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
29922999

2993-
if (!RD)
3000+
if (!RD) {
3001+
if (T->isNullPtrType())
3002+
Diag.Report(KernelLocation, diag::err_sycl_kernel_incorrectly_named)
3003+
<< /* name cannot be a type in the std namespace */ 3;
3004+
29943005
return;
3006+
}
29953007

29963008
// see if this is a template specialization ...
29973009
if (const auto *TSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// RUN: %clang_cc1 -fsycl -fsycl-is-device -fsycl-int-header=%t.h -DCHECK_ERROR -verify %s
2+
// RUN: %clang_cc1 -fsycl -fsycl-is-device -triple spir64-unknown-unknown-sycldevice -fsycl-int-header=%t.h %s
3+
// RUN: FileCheck -input-file=%t.h %s
4+
//
5+
// CHECK: #include <CL/sycl/detail/defines.hpp>
6+
// CHECK-NEXT: #include <CL/sycl/detail/kernel_desc.hpp>
7+
//
8+
// CHECK: static constexpr
9+
// CHECK-NEXT: const char* const kernel_names[] = {
10+
// CHECK-NEXT: "_ZTSm",
11+
// CHECK-NEXT: "_ZTSl"
12+
// CHECK-NEXT: };
13+
//
14+
// CHECK: static constexpr
15+
// CHECK-NEXT: const kernel_param_desc_t kernel_signatures[] = {
16+
// CHECK-NEXT: //--- _ZTSm
17+
// CHECK-EMPTY:
18+
// CHECK-NEXT: //--- _ZTSl
19+
// CHECK-EMPTY:
20+
// CHECK-NEXT: };
21+
//
22+
// CHECK: static constexpr
23+
// CHECK-NEXT: const unsigned kernel_signature_start[] = {
24+
// CHECK-NEXT: 0, // _ZTSm
25+
// CHECK-NEXT: 1 // _ZTSl
26+
// CHECK-NEXT: };
27+
28+
// CHECK: template <> struct KernelInfo<unsigned long> {
29+
// CHECK: template <> struct KernelInfo<long> {
30+
31+
void usage() {
32+
}
33+
34+
namespace std {
35+
typedef long unsigned int size_t;
36+
typedef long int ptrdiff_t;
37+
typedef decltype(nullptr) nullptr_t;
38+
class T;
39+
class U;
40+
} // namespace std
41+
42+
template <typename T>
43+
struct Templated_kernel_name;
44+
45+
template <typename name, typename Func>
46+
__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) {
47+
kernelFunc();
48+
}
49+
50+
int main() {
51+
#ifdef CHECK_ERROR
52+
kernel_single_task<std::nullptr_t>([=]() {}); // expected-error {{kernel name cannot be a type in the "std" namespace}}
53+
kernel_single_task<std::T>([=]() {}); // expected-error {{kernel name cannot be a type in the "std" namespace}}
54+
kernel_single_task<Templated_kernel_name<std::nullptr_t>>([=]() {}); // expected-error {{kernel name cannot be a type in the "std" namespace}}
55+
kernel_single_task<Templated_kernel_name<std::U>>([=]() {}); // expected-error {{kernel name cannot be a type in the "std" namespace}}
56+
#endif
57+
58+
// Although in the std namespace, these resolve to builtins such as `int` that are allowed in kernel names
59+
kernel_single_task<std::size_t>([=]() {});
60+
kernel_single_task<std::ptrdiff_t>([=]() {});
61+
62+
return 0;
63+
}

clang/test/SemaSYCL/unnamed-kernel.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ template <typename T>
1111
class KernelName;
1212
}
1313

14+
namespace std {
15+
typedef struct {
16+
} max_align_t;
17+
} // namespace std
18+
1419
struct MyWrapper {
1520
private:
1621
class InvalidKernelName0 {};
@@ -41,15 +46,15 @@ struct MyWrapper {
4146

4247
#ifndef __SYCL_UNNAMED_LAMBDA__
4348
// expected-error@+4 {{kernel needs to have a globally-visible name}}
44-
// expected-note@16 {{InvalidKernelName0 declared here}}
49+
// expected-note@21 {{InvalidKernelName0 declared here}}
4550
#endif
4651
q.submit([&](cl::sycl::handler &h) {
4752
h.single_task<InvalidKernelName0>([] {});
4853
});
4954

5055
#ifndef __SYCL_UNNAMED_LAMBDA__
5156
// expected-error@+4 {{kernel needs to have a globally-visible name}}
52-
// expected-note@17 {{InvalidKernelName3 declared here}}
57+
// expected-note@22 {{InvalidKernelName3 declared here}}
5358
#endif
5459
q.submit([&](cl::sycl::handler &h) {
5560
h.single_task<namespace1::KernelName<InvalidKernelName3>>([] {});
@@ -60,10 +65,17 @@ struct MyWrapper {
6065
h.single_task<ValidAlias>([] {});
6166
});
6267

68+
#ifndef __SYCL_UNNAMED_LAMBDA__
69+
// expected-error@+3 {{kernel name cannot be a type in the "std" namespace}}
70+
#endif
71+
q.submit([&](cl::sycl::handler &h) {
72+
h.single_task<std::max_align_t>([] {});
73+
});
74+
6375
using InvalidAlias = InvalidKernelName4;
6476
#ifndef __SYCL_UNNAMED_LAMBDA__
6577
// expected-error@+4 {{kernel needs to have a globally-visible name}}
66-
// expected-note@18 {{InvalidKernelName4 declared here}}
78+
// expected-note@23 {{InvalidKernelName4 declared here}}
6779
#endif
6880
q.submit([&](cl::sycl::handler &h) {
6981
h.single_task<InvalidAlias>([] {});
@@ -72,7 +84,7 @@ struct MyWrapper {
7284
using InvalidAlias1 = InvalidKernelName5;
7385
#ifndef __SYCL_UNNAMED_LAMBDA__
7486
// expected-error@+4 {{kernel needs to have a globally-visible name}}
75-
// expected-note@19 {{InvalidKernelName5 declared here}}
87+
// expected-note@24 {{InvalidKernelName5 declared here}}
7688
#endif
7789
q.submit([&](cl::sycl::handler &h) {
7890
h.single_task<namespace1::KernelName<InvalidAlias1>>([] {});

sycl/test/group-algorithm/broadcast.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,11 @@
1515
using namespace sycl;
1616
using namespace sycl::ONEAPI;
1717

18-
template <typename InputContainer, typename OutputContainer>
19-
class broadcast_kernel;
20-
21-
template <typename InputContainer, typename OutputContainer>
18+
template <typename kernel_name, typename InputContainer,
19+
typename OutputContainer>
2220
void test(queue q, InputContainer input, OutputContainer output) {
2321
typedef typename InputContainer::value_type InputT;
2422
typedef typename OutputContainer::value_type OutputT;
25-
typedef class broadcast_kernel<InputContainer, OutputContainer> kernel_name;
2623
size_t N = input.size();
2724
size_t G = 4;
2825
range<2> R(G, G);
@@ -63,7 +60,7 @@ int main() {
6360
std::array<int, 3> output;
6461
std::iota(input.begin(), input.end(), 1);
6562
std::fill(output.begin(), output.end(), false);
66-
test(q, input, output);
63+
test<class KernelName_EFL>(q, input, output);
6764
}
6865

6966
// Test pointer type
@@ -74,7 +71,7 @@ int main() {
7471
input[i] = static_cast<int *>(0x0) + i;
7572
}
7673
std::fill(output.begin(), output.end(), static_cast<int *>(0x0));
77-
test(q, input, output);
74+
test<class KernelName_NrqELzFQToOSPsRNMi>(q, input, output);
7875
}
7976

8077
// Test user-defined type
@@ -88,7 +85,7 @@ int main() {
8885
std::complex<float>(0, 1) + (float)i * std::complex<float>(2, 2);
8986
}
9087
std::fill(output.begin(), output.end(), std::complex<float>(0, 0));
91-
test(q, input, output);
88+
test<class KernelName_rCblcml>(q, input, output);
9289
}
9390
{
9491
std::array<std::complex<double>, N> input;
@@ -98,7 +95,7 @@ int main() {
9895
std::complex<double>(0, 1) + (double)i * std::complex<double>(2, 2);
9996
}
10097
std::fill(output.begin(), output.end(), std::complex<float>(0, 0));
101-
test(q, input, output);
98+
test<class KernelName_NCWhjnQ>(q, input, output);
10299
}
103100
std::cout << "Test passed." << std::endl;
104101
}

sycl/test/group-algorithm/exclusive_scan.cpp

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
using namespace sycl;
2525
using namespace sycl::ONEAPI;
2626

27-
template <class BinaryOperation, int TestNumber>
27+
template <class SpecializationKernelName, int TestNumber>
2828
class exclusive_scan_kernel;
2929

3030
// std::exclusive_scan isn't implemented yet, so use serial implementation
@@ -44,17 +44,17 @@ OutputIterator exclusive_scan(InputIterator first, InputIterator last,
4444
}
4545
} // namespace emu
4646

47-
template <typename InputContainer, typename OutputContainer,
48-
class BinaryOperation>
47+
template <typename SpecializationKernelName, typename InputContainer,
48+
typename OutputContainer, class BinaryOperation>
4949
void test(queue q, InputContainer input, OutputContainer output,
5050
BinaryOperation binary_op,
5151
typename OutputContainer::value_type identity) {
5252
typedef typename InputContainer::value_type InputT;
5353
typedef typename OutputContainer::value_type OutputT;
54-
typedef class exclusive_scan_kernel<BinaryOperation, 0> kernel_name0;
55-
typedef class exclusive_scan_kernel<BinaryOperation, 1> kernel_name1;
56-
typedef class exclusive_scan_kernel<BinaryOperation, 2> kernel_name2;
57-
typedef class exclusive_scan_kernel<BinaryOperation, 3> kernel_name3;
54+
typedef class exclusive_scan_kernel<SpecializationKernelName, 0> kernel_name0;
55+
typedef class exclusive_scan_kernel<SpecializationKernelName, 1> kernel_name1;
56+
typedef class exclusive_scan_kernel<SpecializationKernelName, 2> kernel_name2;
57+
typedef class exclusive_scan_kernel<SpecializationKernelName, 3> kernel_name3;
5858
OutputT init = 42;
5959
size_t N = input.size();
6060
size_t G = 16;
@@ -159,19 +159,24 @@ int main() {
159159
std::iota(input.begin(), input.end(), 0);
160160
std::fill(output.begin(), output.end(), 0);
161161

162-
test(q, input, output, plus<>(), 0);
163-
test(q, input, output, minimum<>(), std::numeric_limits<int>::max());
164-
test(q, input, output, maximum<>(), std::numeric_limits<int>::lowest());
162+
test<class KernelNamePlusV>(q, input, output, plus<>(), 0);
163+
test<class KernelNameMinimumV>(q, input, output, minimum<>(),
164+
std::numeric_limits<int>::max());
165+
test<class KernelNameMaximumV>(q, input, output, maximum<>(),
166+
std::numeric_limits<int>::lowest());
165167

166-
test(q, input, output, plus<int>(), 0);
167-
test(q, input, output, minimum<int>(), std::numeric_limits<int>::max());
168-
test(q, input, output, maximum<int>(), std::numeric_limits<int>::lowest());
168+
test<class KernelNamePlusI>(q, input, output, plus<int>(), 0);
169+
test<class KernelNameMinimumI>(q, input, output, minimum<int>(),
170+
std::numeric_limits<int>::max());
171+
test<class KernelNameMaximumI>(q, input, output, maximum<int>(),
172+
std::numeric_limits<int>::lowest());
169173

170174
#ifdef SPIRV_1_3
171-
test(q, input, output, multiplies<int>(), 1);
172-
test(q, input, output, bit_or<int>(), 0);
173-
test(q, input, output, bit_xor<int>(), 0);
174-
test(q, input, output, bit_and<int>(), ~0);
175+
test<class KernelName_VzAPutpBRRJrQPB>(q, input, output, multiplies<int>(),
176+
1);
177+
test<class KernelName_UXdGbr>(q, input, output, bit_or<int>(), 0);
178+
test<class KernelName_saYaodNyJknrPW>(q, input, output, bit_xor<int>(), 0);
179+
test<class KernelName_GPcuAlvAOjrDyP>(q, input, output, bit_and<int>(), ~0);
175180
#endif // SPIRV_1_3
176181

177182
std::cout << "Test passed." << std::endl;

sycl/test/group-algorithm/inclusive_scan.cpp

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
using namespace sycl;
2525
using namespace sycl::ONEAPI;
2626

27-
template <class BinaryOperation, int TestNumber>
27+
template <class SpecializationKernelName, int TestNumber>
2828
class inclusive_scan_kernel;
2929

3030
// std::inclusive_scan isn't implemented yet, so use serial implementation
@@ -44,17 +44,17 @@ OutputIterator inclusive_scan(InputIterator first, InputIterator last,
4444
}
4545
} // namespace emu
4646

47-
template <typename InputContainer, typename OutputContainer,
48-
class BinaryOperation>
47+
template <typename SpecializationKernelName, typename InputContainer,
48+
typename OutputContainer, class BinaryOperation>
4949
void test(queue q, InputContainer input, OutputContainer output,
5050
BinaryOperation binary_op,
5151
typename OutputContainer::value_type identity) {
5252
typedef typename InputContainer::value_type InputT;
5353
typedef typename OutputContainer::value_type OutputT;
54-
typedef class inclusive_scan_kernel<BinaryOperation, 0> kernel_name0;
55-
typedef class inclusive_scan_kernel<BinaryOperation, 1> kernel_name1;
56-
typedef class inclusive_scan_kernel<BinaryOperation, 2> kernel_name2;
57-
typedef class inclusive_scan_kernel<BinaryOperation, 3> kernel_name3;
54+
typedef class inclusive_scan_kernel<SpecializationKernelName, 0> kernel_name0;
55+
typedef class inclusive_scan_kernel<SpecializationKernelName, 1> kernel_name1;
56+
typedef class inclusive_scan_kernel<SpecializationKernelName, 2> kernel_name2;
57+
typedef class inclusive_scan_kernel<SpecializationKernelName, 3> kernel_name3;
5858
OutputT init = 42;
5959
size_t N = input.size();
6060
size_t G = 16;
@@ -159,19 +159,25 @@ int main() {
159159
std::iota(input.begin(), input.end(), 0);
160160
std::fill(output.begin(), output.end(), 0);
161161

162-
test(q, input, output, plus<>(), 0);
163-
test(q, input, output, minimum<>(), std::numeric_limits<int>::max());
164-
test(q, input, output, maximum<>(), std::numeric_limits<int>::lowest());
162+
test<class KernelNamePlusV>(q, input, output, plus<>(), 0);
163+
test<class KernelNameMinimumV>(q, input, output, minimum<>(),
164+
std::numeric_limits<int>::max());
165+
test<class KernelNameMaximumV>(q, input, output, maximum<>(),
166+
std::numeric_limits<int>::lowest());
165167

166-
test(q, input, output, plus<int>(), 0);
167-
test(q, input, output, minimum<int>(), std::numeric_limits<int>::max());
168-
test(q, input, output, maximum<int>(), std::numeric_limits<int>::lowest());
168+
test<class KernelNamePlusI>(q, input, output, plus<int>(), 0);
169+
test<class KernelNameMinimumI>(q, input, output, minimum<int>(),
170+
std::numeric_limits<int>::max());
171+
test<class KernelNameMaximumI>(q, input, output, maximum<int>(),
172+
std::numeric_limits<int>::lowest());
169173

170174
#ifdef SPIRV_1_3
171-
test(q, input, output, multiplies<int>(), 1);
172-
test(q, input, output, bit_or<int>(), 0);
173-
test(q, input, output, bit_xor<int>(), 0);
174-
test(q, input, output, bit_and<int>(), ~0);
175+
test<class KernelName_zMyjxUrBgeUGoxmDwhvJ>(q, input, output,
176+
multiplies<int>(), 1);
177+
test<class KernelName_SljjtroxNRaAXoVnT>(q, input, output, bit_or<int>(), 0);
178+
test<class KernelName_yXIZfjwjxQGiPeQAnc>(q, input, output, bit_xor<int>(),
179+
0);
180+
test<class KernelName_xGnAnMYHvqekCk>(q, input, output, bit_and<int>(), ~0);
175181
#endif // SPIRV_1_3
176182

177183
std::cout << "Test passed." << std::endl;

0 commit comments

Comments
 (0)