Skip to content

Commit 5c4a84b

Browse files
rolandschulzbader
authored andcommitted
[SYCL] Support unnamed lambda kernels
Add support for kernels without kernel name. Requires compiling with -DUNNAMED_LAMBDA_EXT. Uses new __unique_stable_name compiler built-in. Signed-off-by: Roland Schulz <roland.schulz@intel.com> Signed-off-by: Alexey Bader <alexey.bader@intel.com>
1 parent 9127dce commit 5c4a84b

File tree

9 files changed

+118
-15
lines changed

9 files changed

+118
-15
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

+1-1
Original file line numberDiff line numberDiff line change
@@ -9768,7 +9768,7 @@ def err_builtin_launder_invalid_arg : Error<
97689768
// SYCL-specific diagnostics
97699769
def err_sycl_attribute_address_space_invalid : Error<
97709770
"address space is outside the valid range of values">;
9771-
def err_sycl_kernel_name_class_not_top_level : Error<
9771+
def warn_sycl_kernel_name_class_not_top_level : Warning<
97729772
"kernel name class and its template argument classes' declarations can only "
97739773
"nest in a namespace: %0">;
97749774
def err_sycl_restrict : Error<

clang/include/clang/Sema/Sema.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,8 @@ class SYCLIntegrationHeader {
317317

318318
/// Signals that subsequent parameter descriptor additions will go to
319319
/// the kernel with given name. Starts new kernel invocation descriptor.
320-
void startKernel(StringRef KernelName, QualType KernelNameType);
320+
void startKernel(StringRef KernelName, QualType KernelNameType,
321+
StringRef KernelStableName);
321322

322323
/// Adds a kernel parameter descriptor to current kernel invocation
323324
/// descriptor.
@@ -352,6 +353,9 @@ class SYCLIntegrationHeader {
352353
/// Kernel name type.
353354
QualType NameType;
354355

356+
/// Kernel name with stable lamba name mangling
357+
std::string StableName;
358+
355359
/// Descriptor of kernel actual parameters.
356360
SmallVector<KernelParamDesc, 8> Params;
357361

clang/lib/Sema/SemaSYCL.cpp

+17-9
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,9 @@ static void populateIntHeader(SYCLIntegrationHeader &H, const StringRef Name,
797797

798798
ASTContext &Ctx = KernelObjTy->getASTContext();
799799
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(KernelObjTy);
800-
H.startKernel(Name, NameType);
800+
const std::string StableName = PredefinedExpr::ComputeName(
801+
Ctx, PredefinedExpr::UniqueStableNameExpr, NameType);
802+
H.startKernel(Name, NameType, StableName);
801803

802804
auto populateHeaderForAccessor = [&](const QualType &ArgTy, uint64_t Offset) {
803805
// The parameter is a SYCL accessor object.
@@ -1112,7 +1114,7 @@ void SYCLIntegrationHeader::emitFwdDecl(raw_ostream &O, const Decl *D) {
11121114
// defined class constituting the kernel name is not globally
11131115
// accessible - contradicts the spec
11141116
Diag.Report(D->getSourceRange().getBegin(),
1115-
diag::err_sycl_kernel_name_class_not_top_level);
1117+
diag::warn_sycl_kernel_name_class_not_top_level);
11161118
}
11171119
}
11181120
break;
@@ -1238,12 +1240,14 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) {
12381240
O << "#include <CL/sycl/detail/kernel_desc.hpp>\n";
12391241

12401242
O << "\n";
1243+
O << "#ifndef UNNAMED_LAMBDA_EXT\n";
12411244
O << "// Forward declarations of templated kernel function types:\n";
12421245

12431246
llvm::SmallPtrSet<const void *, 4> Printed;
12441247
for (const KernelDesc &K : KernelDescs) {
12451248
emitForwardClassDecls(O, K.NameType, Printed);
12461249
}
1250+
O << "#endif\n";
12471251
O << "\n";
12481252

12491253
O << "namespace cl {\n";
@@ -1305,19 +1309,21 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) {
13051309
}
13061310
O << "};\n\n";
13071311

1308-
O << "// Specializations of this template class encompasses information\n";
1309-
O << "// about a kernel. The kernel is identified by the template\n";
1310-
O << "// parameter type.\n";
1311-
O << "template <class KernelNameType> struct KernelInfo;\n";
1312-
O << "\n";
1313-
13141312
O << "// Specializations of KernelInfo for kernel function types:\n";
13151313
CurStart = 0;
13161314

13171315
for (const KernelDesc &K : KernelDescs) {
13181316
const size_t N = K.Params.size();
1317+
O << "#ifdef UNNAMED_LAMBDA_EXT\n";
1318+
O << "template <> struct KernelInfoData<";
1319+
O << "'" << K.StableName.front();
1320+
for (char c : StringRef(K.StableName).substr(1))
1321+
O << "', '" << c;
1322+
O << "'> {\n";
1323+
O << "#else\n";
13191324
O << "template <> struct KernelInfo<"
13201325
<< eraseAnonNamespace(K.NameType.getAsString()) << "> {\n";
1326+
O << "#endif\n";
13211327
O << " DLL_LOCAL\n";
13221328
O << " static constexpr const char* getName() { return \"" << K.Name
13231329
<< "\"; }\n";
@@ -1355,10 +1361,12 @@ bool SYCLIntegrationHeader::emit(const StringRef &IntHeaderName) {
13551361
}
13561362

13571363
void SYCLIntegrationHeader::startKernel(StringRef KernelName,
1358-
QualType KernelNameType) {
1364+
QualType KernelNameType,
1365+
StringRef KernelStableName) {
13591366
KernelDescs.resize(KernelDescs.size() + 1);
13601367
KernelDescs.back().Name = KernelName;
13611368
KernelDescs.back().NameType = KernelNameType;
1369+
KernelDescs.back().StableName = KernelStableName;
13621370
}
13631371

13641372
void SYCLIntegrationHeader::addParamDesc(kernel_param_kind_t Kind, int Info,

clang/test/CodeGenSYCL/integration_header.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
// CHECK-EMPTY:
4848
// CHECK-NEXT: };
4949
//
50-
// CHECK: template <class KernelNameType> struct KernelInfo;
5150
// CHECK: template <> struct KernelInfo<class first_kernel> {
5251
// CHECK: template <> struct KernelInfo<::second_namespace::second_kernel<char>> {
5352
// CHECK: template <> struct KernelInfo<::third_kernel<1, int, ::point<X> >> {

clang/test/CodeGenSYCL/wrapped-accessor.cpp

-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@
2727
// CHECK-NEXT: 0 // _ZTSZ4mainE14wrapped_access
2828
// CHECK-NEXT: };
2929

30-
// CHECK: template <class KernelNameType> struct KernelInfo;
31-
3230
// CHECK: template <> struct KernelInfo<class wrapped_access> {
3331

3432
#include <sycl.hpp>

clang/test/Misc/warning-flags.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ This test serves two purposes:
1818

1919
The list of warnings below should NEVER grow. It should gradually shrink to 0.
2020

21-
CHECK: Warnings without flags (74):
21+
CHECK: Warnings without flags (75):
2222
CHECK-NEXT: ext_excess_initializers
2323
CHECK-NEXT: ext_excess_initializers_in_char_array_initializer
2424
CHECK-NEXT: ext_expected_semi_decl_list
@@ -84,6 +84,7 @@ CHECK-NEXT: warn_property_getter_owning_mismatch
8484
CHECK-NEXT: warn_register_objc_catch_parm
8585
CHECK-NEXT: warn_related_result_type_compatibility_class
8686
CHECK-NEXT: warn_related_result_type_compatibility_protocol
87+
CHECK-NEXT: warn_sycl_kernel_name_class_not_top_level
8788
CHECK-NEXT: warn_template_export_unsupported
8889
CHECK-NEXT: warn_template_spec_extra_headers
8990
CHECK-NEXT: warn_tentative_incomplete_array

sycl/include/CL/sycl/detail/kernel_desc.hpp

+24
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ struct kernel_param_desc_t {
5151
int offset;
5252
};
5353

54+
#ifndef UNNAMED_LAMBDA_EXT
5455
template <class KernelNameType> struct KernelInfo {
5556
static constexpr unsigned getNumParams() { return 0; }
5657
static const kernel_param_desc_t &getParamDesc(int Idx) {
@@ -59,6 +60,29 @@ template <class KernelNameType> struct KernelInfo {
5960
}
6061
static constexpr const char *getName() { return ""; }
6162
};
63+
#else
64+
template <char...> struct KernelInfoData; // Should this have dummy impl?
65+
66+
// C++14 like index_sequence and make_index_sequence
67+
// not needed C++14 members (value_type, size) not implemented
68+
template <class T, T...> struct integer_sequence {};
69+
template <size_t... I> using index_sequence = integer_sequence<size_t, I...>;
70+
template <size_t N>
71+
using make_index_sequence = __make_integer_seq<integer_sequence, size_t, N>;
72+
73+
template <typename T> struct KernelInfoImpl {
74+
private:
75+
static constexpr auto n = __unique_stable_name(T);
76+
template <std::size_t... I>
77+
static KernelInfoData<n[I]...> impl(index_sequence<I...>) {
78+
return {};
79+
}
80+
81+
public:
82+
using type = decltype(impl(make_index_sequence<__builtin_strlen(n)>{}));
83+
};
84+
template <typename T> using KernelInfo = typename KernelInfoImpl<T>::type;
85+
#endif
6286

6387
} // namespace detail
6488
} // namespace sycl

sycl/test/regression/kernel_name_class.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// RUN: %CPU_RUN_PLACEHOLDER %t.out
44
// RUN: %GPU_RUN_PLACEHOLDER %t.out
55
// RUN: %ACC_RUN_PLACEHOLDER %t.out
6+
// RUN: %clangxx -fsycl %s -o %t.ext.out -lOpenCL -DUNNAMED_LAMBDA_EXT
7+
// RUN: %CPU_RUN_PLACEHOLDER %t.ext.out
68

79
//==-- kernel_name_class.cpp - SYCL kernel naming variants test ------------==//
810
//
+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// RUN: %clangxx -fsycl %s -o %t.out -lOpenCL -DUNNAMED_LAMBDA_EXT
2+
// RUN: env SYCL_DEVICE_TYPE=HOST %t.out
3+
// RUN: %CPU_RUN_PLACEHOLDER %t.out
4+
// RUN: %GPU_RUN_PLACEHOLDER %t.out
5+
// RUN: %ACC_RUN_PLACEHOLDER %t.out
6+
7+
//==-- kernel_unnamed.cpp - SYCL kernel naming variants test ------------==//
8+
//
9+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
10+
// See https://llvm.org/LICENSE.txt for license information.
11+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#include <CL/sycl.hpp>
16+
#include <iostream>
17+
18+
#define GOLD 10
19+
static int NumTestCases = 0;
20+
21+
template <class F>
22+
void foo(cl::sycl::queue &deviceQueue, cl::sycl::buffer<int, 1> &buf, F f) {
23+
deviceQueue.submit([&](cl::sycl::handler &cgh) {
24+
auto acc = buf.get_access<cl::sycl::access::mode::read_write>(cgh);
25+
cgh.single_task([=]() { acc[0] = f(acc[0], GOLD); });
26+
});
27+
}
28+
29+
namespace nm {
30+
struct Wrapper {
31+
32+
int test() {
33+
int arr[] = {0};
34+
{
35+
// Simple test
36+
cl::sycl::queue deviceQueue;
37+
cl::sycl::buffer<int, 1> buf(arr, 1);
38+
deviceQueue.submit([&](cl::sycl::handler &cgh) {
39+
auto acc = buf.get_access<cl::sycl::access::mode::read_write>(cgh);
40+
cgh.single_task([=]() { acc[0] += GOLD; });
41+
});
42+
++NumTestCases;
43+
44+
// Test lambdas with different ordinal because of macro expansion
45+
#ifdef __SYCL_DEVICE_ONLY__
46+
[] {}();
47+
#endif
48+
deviceQueue.submit([&](cl::sycl::handler &cgh) {
49+
auto acc = buf.get_access<cl::sycl::access::mode::read_write>(cgh);
50+
cgh.single_task([=]() { acc[0] += GOLD; });
51+
});
52+
++NumTestCases;
53+
54+
// Test lambda passed to function
55+
foo(deviceQueue, buf, [](int a, int b) { return a + b; });
56+
++NumTestCases;
57+
}
58+
return arr[0];
59+
}
60+
};
61+
} // namespace nm
62+
63+
int main() {
64+
nm::Wrapper w;
65+
int res = w.test();
66+
assert (res == GOLD * NumTestCases && "Wrong result");
67+
}

0 commit comments

Comments
 (0)