Skip to content

Commit 1b5c5a8

Browse files
[SYCL] Fix SYCL_EXTERNAL device code when linking with a static lib (#14256)
Static library linking mechanism uses symbols pulled in by the host linker to determine what parts of device code to include during its linking. The exceptions thrown from nd_item on host interfere with that, since all the following host code for the kernel can get optimized away. This change removes those exceptions since nd_item can't be constructed on the host side.
1 parent aabe45a commit 1b5c5a8

File tree

2 files changed

+79
-14
lines changed

2 files changed

+79
-14
lines changed

sycl/include/sycl/nd_item.hpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ template <int Dimensions = 1> class nd_item {
5353
#ifdef __SYCL_DEVICE_ONLY__
5454
return __spirv::initGlobalInvocationId<Dimensions, id<Dimensions>>();
5555
#else
56-
throw sycl::exception(sycl::make_error_code(sycl::errc::invalid),
57-
"nd_item methods can't be invoked on the host");
5856
return {};
5957
#endif
6058
}
@@ -86,8 +84,6 @@ template <int Dimensions = 1> class nd_item {
8684
#ifdef __SYCL_DEVICE_ONLY__
8785
return __spirv::initLocalInvocationId<Dimensions, id<Dimensions>>();
8886
#else
89-
throw sycl::exception(sycl::make_error_code(sycl::errc::invalid),
90-
"nd_item methods can't be invoked on the host");
9187
return {};
9288
#endif
9389
}
@@ -149,8 +145,6 @@ template <int Dimensions = 1> class nd_item {
149145
#ifdef __SYCL_DEVICE_ONLY__
150146
return __spirv::initNumWorkgroups<Dimensions, range<Dimensions>>();
151147
#else
152-
throw sycl::exception(sycl::make_error_code(sycl::errc::invalid),
153-
"nd_item methods can't be invoked on the host");
154148
return {};
155149
#endif
156150
}
@@ -165,8 +159,6 @@ template <int Dimensions = 1> class nd_item {
165159
#ifdef __SYCL_DEVICE_ONLY__
166160
return __spirv::initGlobalSize<Dimensions, range<Dimensions>>();
167161
#else
168-
throw sycl::exception(sycl::make_error_code(sycl::errc::invalid),
169-
"nd_item methods can't be invoked on the host");
170162
return {};
171163
#endif
172164
}
@@ -181,8 +173,6 @@ template <int Dimensions = 1> class nd_item {
181173
#ifdef __SYCL_DEVICE_ONLY__
182174
return __spirv::initWorkgroupSize<Dimensions, range<Dimensions>>();
183175
#else
184-
throw sycl::exception(sycl::make_error_code(sycl::errc::invalid),
185-
"nd_item methods can't be invoked on the host");
186176
return {};
187177
#endif
188178
}
@@ -198,8 +188,6 @@ template <int Dimensions = 1> class nd_item {
198188
#ifdef __SYCL_DEVICE_ONLY__
199189
return __spirv::initGlobalOffset<Dimensions, id<Dimensions>>();
200190
#else
201-
throw sycl::exception(sycl::make_error_code(sycl::errc::invalid),
202-
"nd_item methods can't be invoked on the host");
203191
return {};
204192
#endif
205193
}
@@ -529,8 +517,6 @@ template <int Dimensions = 1> class nd_item {
529517
#ifdef __SYCL_DEVICE_ONLY__
530518
return __spirv::initWorkgroupId<Dimensions, id<Dimensions>>();
531519
#else
532-
throw sycl::exception(sycl::make_error_code(sycl::errc::invalid),
533-
"nd_item methods can't be invoked on the host");
534520
return {};
535521
#endif
536522
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Check that, when linking with a static library, SYCL_EXTERNAL device code
2+
// is preserved despite optimizations.
3+
// RUN: %{build} -O3 -DSOURCE1 -c -o %t1.o
4+
// RUN: %{build} -O3 -DSOURCE2 -c -o %t2.o
5+
// RUN: %{build} -O3 -DSOURCE3 -c -o %t3.o
6+
// RUN: rm -f %t.a
7+
// RUN: llvm-ar crv %t.a %t1.o %t2.o
8+
// RUN: %clangxx -fsycl -fsycl-targets=%{sycl_triple} -O3 %t3.o %t.a -o %t1.exe
9+
// RUN: %{run} %t1.exe
10+
11+
// Check the repacked case as it can behave differently.
12+
// RUN: echo create %t_repacked.a > %t.txt
13+
// RUN: echo addlib %t.a >> %t.txt
14+
// RUN: echo save >> %t.txt
15+
// RUN: cat %t.txt | llvm-ar -M
16+
// RUN: %clangxx -fsycl -fsycl-targets=%{sycl_triple} -O3 %t3.o %t_repacked.a -o %t2.exe
17+
// RUN: %{run} %t2.exe
18+
19+
#include <iostream>
20+
#include <sycl/detail/core.hpp>
21+
22+
#ifdef SOURCE1
23+
int local_f2(int b);
24+
25+
SYCL_EXTERNAL
26+
int external_f1(int a, int b) { return a + local_f2(b); }
27+
28+
int local_f2(int b) { return b + 5; }
29+
#endif // SOURCE1
30+
31+
#ifdef SOURCE2
32+
SYCL_EXTERNAL
33+
int external_f1(int A, int B);
34+
35+
void hostf(unsigned Size, sycl::buffer<int, 1> &bufA,
36+
sycl::buffer<int, 1> &bufB, sycl::buffer<int, 1> &bufC) {
37+
sycl::range<1> range{Size};
38+
sycl::queue().submit([&](sycl::handler &cgh) {
39+
auto accA = bufA.get_access<sycl::access::mode::read>(cgh);
40+
auto accB = bufB.get_access<sycl::access::mode::read>(cgh);
41+
auto accC = bufC.get_access<sycl::access::mode::write>(cgh);
42+
43+
cgh.parallel_for<class Test>(range, [=](sycl::id<1> ID) {
44+
accC[ID] = external_f1(accA[ID], accB[ID]);
45+
});
46+
});
47+
}
48+
#endif
49+
50+
#ifdef SOURCE3
51+
extern void hostf(unsigned Size, sycl::buffer<int, 1> &bufA,
52+
sycl::buffer<int, 1> &bufB, sycl::buffer<int, 1> &c);
53+
int ref(int a, int b) { return a + b + 5; }
54+
55+
int main(void) {
56+
constexpr unsigned Size = 4;
57+
int A[Size] = {1, 2, 3, 4};
58+
int B[Size] = {1, 2, 3, 4};
59+
int C[Size];
60+
61+
{
62+
sycl::range<1> range{Size};
63+
sycl::buffer<int, 1> bufA(A, range);
64+
sycl::buffer<int, 1> bufB(B, range);
65+
sycl::buffer<int, 1> bufC(C, range);
66+
hostf(Size, bufA, bufB, bufC);
67+
}
68+
for (unsigned I = 0; I < Size; ++I) {
69+
int Ref = ref(A[I], B[I]);
70+
if (C[I] != Ref) {
71+
std::cout << "fail: [" << I << "] == " << C[I] << ", expected " << Ref
72+
<< "\n";
73+
return 1;
74+
}
75+
}
76+
std::cout << "pass\n";
77+
return 0;
78+
}
79+
#endif // SOURCE3

0 commit comments

Comments
 (0)