Skip to content

Commit 227af47

Browse files
authored
[SYCL] Add warning for attributes applied to non-kernel functions (#15154)
According to [5.8.1. Kernel attributes](https://registry.khronos.org/SYCL/specs/sycl-2020/html/sycl-2020.html#sec:kernel.attributes), kernel attributes can only be applied to SYCL kernel functions, but not to a regular device functions. Based on this information, this pull request introduces a warning diagnostic whenever specified attributes are applied to regular device functions.
1 parent da480db commit 227af47

12 files changed

+156
-25
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12358,6 +12358,8 @@ def err_bit_cast_type_size_mismatch : Error<
1235812358
"__builtin_bit_cast source size does not equal destination size (%0 vs %1)">;
1235912359

1236012360
// SYCL-specific diagnostics
12361+
def warn_sycl_incorrect_use_attribute_non_kernel_function : Warning<
12362+
"%0 attribute can only be applied to a SYCL kernel function">, InGroup<SyclStrict>;
1236112363
def warn_sycl_kernel_num_of_template_params : Warning<
1236212364
"'sycl_kernel' attribute only applies to a function template with at least"
1236312365
" two template parameters">, InGroup<IgnoredAttributes>;

clang/include/clang/Sema/SemaSYCL.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ class SemaSYCL : public SemaBase {
259259
// useful notes that shows where the kernel was called.
260260
bool DiagnosingSYCLKernel = false;
261261

262+
llvm::DenseSet<const FunctionDecl *> SYCLKernelFunctions;
263+
262264
public:
263265
SemaSYCL(Sema &S);
264266

@@ -300,6 +302,10 @@ class SemaSYCL : public SemaBase {
300302
void addSyclDeviceDecl(Decl *d) { SyclDeviceDecls.insert(d); }
301303
llvm::SetVector<Decl *> &syclDeviceDecls() { return SyclDeviceDecls; }
302304

305+
void addSYCLKernelFunction(const FunctionDecl *FD) {
306+
SYCLKernelFunctions.insert(FD);
307+
}
308+
303309
/// Lazily creates and returns SYCL integration header instance.
304310
SYCLIntegrationHeader &getSyclIntegrationHeader() {
305311
if (SyclIntHeader == nullptr)
@@ -375,6 +381,8 @@ class SemaSYCL : public SemaBase {
375381
SourceLocation Loc,
376382
DeviceDiagnosticReason Reason);
377383

384+
void performSYCLDelayedAttributesAnalaysis(const FunctionDecl *FD);
385+
378386
/// Tells whether given variable is a SYCL explicit SIMD extension's "private
379387
/// global" variable - global variable in the private address space.
380388
bool isSYCLEsimdPrivateGlobal(VarDecl *VDecl) {

clang/lib/Sema/Sema.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1909,6 +1909,10 @@ class DeferredDiagnosticsEmitter
19091909
void checkFunc(SourceLocation Loc, FunctionDecl *FD) {
19101910
auto &Done = DoneMap[InOMPDeviceContext > 0 ? 1 : 0];
19111911
FunctionDecl *Caller = UsePath.empty() ? nullptr : UsePath.back();
1912+
1913+
if (!Caller && S.LangOpts.SYCLIsDevice)
1914+
S.SYCL().performSYCLDelayedAttributesAnalaysis(FD);
1915+
19121916
if ((!ShouldEmitRootNode && !S.getLangOpts().OpenMP && !Caller) ||
19131917
S.shouldIgnoreInHostDeviceCheck(FD) || InUsePath.count(FD))
19141918
return;

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,8 @@ class SingleDeviceFunctionTracker {
882882
// having a kernel lambda with a lambda call inside of it.
883883
KernelBody = CurrentDecl;
884884
}
885+
if (KernelBody)
886+
Parent.SemaSYCLRef.addSYCLKernelFunction(KernelBody);
885887
}
886888

887889
// Recurse.
@@ -6852,3 +6854,19 @@ ExprResult SemaSYCL::ActOnUniqueStableNameExpr(SourceLocation OpLoc,
68526854

68536855
return BuildUniqueStableNameExpr(OpLoc, LParen, RParen, TSI);
68546856
}
6857+
6858+
void SemaSYCL::performSYCLDelayedAttributesAnalaysis(const FunctionDecl *FD) {
6859+
if (SYCLKernelFunctions.contains(FD))
6860+
return;
6861+
6862+
for (const auto *KernelAttr : std::vector<AttributeCommonInfo *>{
6863+
FD->getAttr<SYCLReqdWorkGroupSizeAttr>(),
6864+
FD->getAttr<IntelReqdSubGroupSizeAttr>(),
6865+
FD->getAttr<SYCLWorkGroupSizeHintAttr>(),
6866+
FD->getAttr<VecTypeHintAttr>()}) {
6867+
if (KernelAttr)
6868+
Diag(KernelAttr->getLoc(),
6869+
diag::warn_sycl_incorrect_use_attribute_non_kernel_function)
6870+
<< KernelAttr;
6871+
}
6872+
}

clang/test/SemaSYCL/check-work-group-size-hint-device.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717

1818
// Produce a conflicting attribute warning when the args are different.
1919
[[sycl::work_group_size_hint(4, 1, 1)]] void f3(); // expected-note {{previous attribute is here}}
20-
[[sycl::work_group_size_hint(1, 1, 32)]] void f3() {} // expected-warning {{attribute 'work_group_size_hint' is already applied with different arguments}}
20+
[[sycl::work_group_size_hint(1, 1, 32)]] void f3() {} // expected-warning {{attribute 'work_group_size_hint' is already applied with different arguments}} \
21+
// expected-warning {{'work_group_size_hint' attribute can only be applied to a SYCL kernel function}}
2122

2223
// 1 and 2 dim versions
2324
[[sycl::work_group_size_hint(2)]] void f4(); // ok
@@ -70,10 +71,13 @@ void instantiate() {
7071
f8<0>(); // expected-note {{in instantiation}}
7172
#endif
7273

74+
// expected-warning@#f9prev {{'work_group_size_hint' attribute can only be applied to a SYCL kernel function}}
7375
f9<1, 1, 1>(); // OK, args are the same on the redecl.
7476

7577
// expected-warning@#f9 {{attribute 'work_group_size_hint' is already applied with different arguments}}
7678
// expected-note@#f9prev {{previous attribute is here}}
79+
// expected-warning@#f9prev {{'work_group_size_hint' attribute can only be applied to a SYCL kernel function}}
80+
7781
f9<1, 2, 3>(); // expected-note {{in instantiation}}
7882
}
7983

@@ -97,14 +101,14 @@ class Functor16x2x1 {
97101

98102
class Functor4x4x4 {
99103
public:
100-
[[sycl::work_group_size_hint(4, 4, 4)]] void operator()() const {};
104+
[[sycl::work_group_size_hint(4, 4, 4)]] void operator()() const {}; // expected-warning {{'work_group_size_hint' attribute can only be applied to a SYCL kernel function}}
101105
};
102106

103107
// Checking whether propagation of the attribute happens or not, according to the SYCL version.
104108
#if defined(EXPECT_PROP) // if attribute is propagated, then we expect errors here
105109
void f8x8x8(){};
106110
#else // otherwise no error
107-
[[sycl::work_group_size_hint(8, 8, 8)]] void f8x8x8(){};
111+
[[sycl::work_group_size_hint(8, 8, 8)]] void f8x8x8(){}; // expected-warning {{'work_group_size_hint' attribute can only be applied to a SYCL kernel function}}
108112
#endif
109113
class FunctorNoProp {
110114
public:

clang/test/SemaSYCL/device_has.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ enum class aspect {
1717

1818
[[sycl::device_has("123")]] void func1() {} // expected-error{{'device_has' attribute argument is invalid; argument must be device aspect of type sycl::aspect}}
1919
[[sycl::device_has(fake_cl::sycl::aspect::aspect1)]] void func2() {} // expected-error{{'device_has' attribute argument is invalid; argument must be device aspect of type sycl::aspect}}
20-
2120
[[sycl::device_has(sycl::aspect::cpu)]] void func3(); // expected-note{{previous attribute is here}}
2221
[[sycl::device_has(sycl::aspect::gpu)]] void func3() {} // expected-warning{{attribute 'device_has' is already applied}}
2322

clang/test/SemaSYCL/intel-max-work-group-size.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,15 @@ void instantiate() {
7070
// a declaration along with [[sycl::reqd_work_group_size(X1, Y1, Z1)]]
7171
// attribute, check to see if values of reqd_work_group_size arguments are
7272
// equal or less than values coming from max_work_group_size attribute.
73-
[[sycl::reqd_work_group_size(64, 64, 64)]] // expected-note {{conflicting attribute is here}}
73+
[[sycl::reqd_work_group_size(64, 64, 64)]] // expected-note {{conflicting attribute is here}} // expected-warning {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
7474
[[intel::max_work_group_size(64, 16, 64)]] // expected-error {{'max_work_group_size' attribute conflicts with 'reqd_work_group_size' attribute}}
7575
void
7676
f9() {}
7777

7878
[[intel::max_work_group_size(4, 4, 4)]] void f10();
7979
[[sycl::reqd_work_group_size(2, 2, 2)]] void f10(); // OK
8080

81-
[[sycl::reqd_work_group_size(2, 2, 2)]] [[intel::max_work_group_size(4, 4, 4)]] void f11() {} // OK
81+
[[sycl::reqd_work_group_size(2, 2, 2)]] [[intel::max_work_group_size(4, 4, 4)]] void f11() {} // expected-warning {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
8282

8383
[[sycl::reqd_work_group_size(64, 64, 64)]] void f12(); // expected-note {{conflicting attribute is here}}
8484
[[intel::max_work_group_size(16, 16, 16)]] void f12(); // expected-error {{'max_work_group_size' attribute conflicts with 'reqd_work_group_size' attribute}}
@@ -91,14 +91,14 @@ f13() {}
9191
[[sycl::reqd_work_group_size(64, 64, 64)]] void f14(); // expected-error{{'reqd_work_group_size' attribute conflicts with 'max_work_group_size' attribute}}
9292

9393
[[cl::reqd_work_group_size(1, 2, 3)]] // expected-warning {{attribute 'cl::reqd_work_group_size' is deprecated}} \
94-
// expected-note {{did you mean to use 'sycl::reqd_work_group_size' instead?}}
94+
// expected-note {{did you mean to use 'sycl::reqd_work_group_size' instead?}} // expected-warning {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
9595
[[intel::max_work_group_size(1, 2, 3)]] void
9696
f15() {} // OK
9797

9898
[[intel::max_work_group_size(2, 3, 7)]] void f16(); // expected-note {{conflicting attribute is here}}
9999
[[sycl::reqd_work_group_size(7, 3, 2)]] void f16(); // expected-error{{'reqd_work_group_size' attribute conflicts with 'max_work_group_size' attribute}}
100100

101-
[[intel::max_work_group_size(1, 2, 3)]] [[sycl::reqd_work_group_size(1, 2, 3)]] void f17(){}; // OK
101+
[[intel::max_work_group_size(1, 2, 3)]] [[sycl::reqd_work_group_size(1, 2, 3)]] void f17(){}; // expected-warning {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
102102

103103
[[sycl::reqd_work_group_size(16)]] // expected-note {{conflicting attribute is here}}
104104
[[intel::max_work_group_size(16, 1, 1)]] void // expected-error {{'max_work_group_size' attribute conflicts with 'reqd_work_group_size' attribute}}

clang/test/SemaSYCL/reqd-sub-group-size.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,19 @@ int main() {
3333
return 0;
3434
}
3535
[[intel::reqd_sub_group_size(16)]] SYCL_EXTERNAL void B();
36-
[[intel::reqd_sub_group_size(16)]] void A() {
36+
[[intel::reqd_sub_group_size(16)]] void A() // expected-warning {{'reqd_sub_group_size' attribute can only be applied to a SYCL kernel function}}
37+
{
3738
}
3839

39-
[[intel::reqd_sub_group_size(16)]] SYCL_EXTERNAL void B() {
40+
[[intel::reqd_sub_group_size(16)]] SYCL_EXTERNAL void B() { // expected-warning {{'reqd_sub_group_size' attribute can only be applied to a SYCL kernel function}}
4041
A();
4142
}
4243
// expected-note@+1 {{conflicting attribute is here}}
43-
[[intel::reqd_sub_group_size(2)]] void sg_size2() {}
44+
[[intel::reqd_sub_group_size(2)]] void sg_size2() {} // expected-warning {{'reqd_sub_group_size' attribute can only be applied to a SYCL kernel function}}
4445

45-
// expected-note@+2 {{conflicting attribute is here}}
46-
// expected-error@+1 {{conflicting attributes applied to a SYCL kernel}}
46+
// expected-note@+3 {{conflicting attribute is here}}
47+
// expected-error@+2 {{conflicting attributes applied to a SYCL kernel}}
48+
// expected-warning@+1 {{'reqd_sub_group_size' attribute can only be applied to a SYCL kernel function}}
4749
[[intel::reqd_sub_group_size(4)]] __attribute__((sycl_device)) void sg_size4() {
4850
sg_size2();
4951
}
@@ -67,7 +69,7 @@ int main() {
6769

6870
// No diagnostic is emitted because the arguments match.
6971
[[intel::reqd_sub_group_size(12)]] void same();
70-
[[intel::reqd_sub_group_size(12)]] void same() {} // OK
72+
[[intel::reqd_sub_group_size(12)]] void same() {} // expected-warning {{'reqd_sub_group_size' attribute can only be applied to a SYCL kernel function}}
7173

7274
// No diagnostic because the attributes are synonyms with identical behavior.
7375
[[sycl::reqd_sub_group_size(12)]] void same(); // OK
@@ -117,10 +119,12 @@ int check() {
117119

118120
// Test that checks template parameter support on function.
119121
template <int N>
120-
// expected-error@+1{{'reqd_sub_group_size' attribute requires a positive integral compile time constant expression}}
122+
// expected-error@+2{{'reqd_sub_group_size' attribute requires a positive integral compile time constant expression}}
123+
// expected-warning@+1 {{'reqd_sub_group_size' attribute can only be applied to a SYCL kernel function}}
121124
[[intel::reqd_sub_group_size(N)]] void func3() {}
122125

123126
template <int N>
127+
// expected-warning@+1 {{'reqd_sub_group_size' attribute can only be applied to a SYCL kernel function}}
124128
[[intel::reqd_sub_group_size(4)]] void func4(); // expected-note {{previous attribute is here}}
125129

126130
template <int N>

clang/test/SemaSYCL/reqd_work_group_size.cpp

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,28 +22,31 @@ class Functor30 {
2222

2323
// Tests for 'reqd_work_group_size' attribute duplication.
2424
// No diagnostic is emitted because the arguments match. Duplicate attribute is silently ignored.
25+
// expected-warning@+1 {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
2526
[[sycl::reqd_work_group_size(6, 6, 6)]] [[sycl::reqd_work_group_size(6, 6, 6)]] void f2() {}
2627

2728
// No diagnostic is emitted because the arguments match.
2829
[[sycl::reqd_work_group_size(32, 32, 32)]] void f3();
2930
[[sycl::reqd_work_group_size(32, 32, 32)]] void f3(); // OK
3031

3132
// Produce a conflicting attribute warning when the args are different.
32-
[[sycl::reqd_work_group_size(6, 6, 6)]] // expected-note {{previous attribute is here}}
33+
[[sycl::reqd_work_group_size(6, 6, 6)]] // expected-note {{previous attribute is here}} // expected-warning {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
3334
[[sycl::reqd_work_group_size(16, 16, 16)]] void // expected-error {{attribute 'reqd_work_group_size' is already applied with different arguments}}
3435
f4() {}
3536

3637
// Catch the easy case where the attributes are all specified at once with
3738
// different arguments.
3839
struct TRIFuncObjGood1 {
39-
// expected-note@+2 {{previous attribute is here}}
40-
// expected-error@+1 {{attribute 'reqd_work_group_size' is already applied with different arguments}}
40+
// expected-note@+3 {{previous attribute is here}}
41+
// expected-error@+2 {{attribute 'reqd_work_group_size' is already applied with different arguments}}
42+
// expected-warning@+1 {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
4143
[[sycl::reqd_work_group_size(64)]] [[sycl::reqd_work_group_size(128)]] void operator()() const {}
4244
};
4345

4446
struct TRIFuncObjGood2 {
45-
// expected-note@+2 {{previous attribute is here}}
46-
// expected-error@+1 {{attribute 'reqd_work_group_size' is already applied with different arguments}}
47+
// expected-note@+3 {{previous attribute is here}}
48+
// expected-error@+2 {{attribute 'reqd_work_group_size' is already applied with different arguments}}
49+
// expected-warning@+1 {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
4750
[[sycl::reqd_work_group_size(64, 64)]] [[sycl::reqd_work_group_size(128, 128)]] void operator()() const {}
4851
};
4952

@@ -52,7 +55,8 @@ struct TRIFuncObjGood3 {
5255
operator()() const;
5356
};
5457

55-
[[sycl::reqd_work_group_size(4, 4)]] // expected-error {{attribute 'reqd_work_group_size' is already applied with different arguments}}
58+
[[sycl::reqd_work_group_size(4, 4)]] // expected-error {{attribute 'reqd_work_group_size' is already applied with different arguments}} \
59+
// expected-warning {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
5660
void
5761
TRIFuncObjGood3::operator()() const {}
5862

@@ -73,7 +77,7 @@ class FunctorC {
7377

7478
class Functor32 {
7579
public:
76-
[[sycl::reqd_work_group_size(32, 1, 1)]] // expected-note {{previous attribute is here}}
80+
[[sycl::reqd_work_group_size(32, 1, 1)]] // expected-note {{previous attribute is here}} // expected-warning {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
7781
[[sycl::reqd_work_group_size(1, 1, 32)]] void // expected-error{{attribute 'reqd_work_group_size' is already applied with different arguments}}
7882
operator()() const {}
7983
};
@@ -105,16 +109,18 @@ void instantiate() {
105109
f7<1, 1, 1>(); // OK, args are the same on the redecl.
106110
// expected-error@#f7 {{attribute 'reqd_work_group_size' is already applied with different arguments}}
107111
// expected-note@#f7prev {{previous attribute is here}}
112+
// expected-warning@#f7prev {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
113+
// expected-warning@#f7prev {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
108114
f7<2, 2, 2>(); // expected-note {{in instantiation}}
109115
}
110116

111117
// Tests for 'reqd_work_group_size' attribute duplication.
112118

113-
[[sycl::reqd_work_group_size(8)]] // expected-note {{previous attribute is here}}
119+
[[sycl::reqd_work_group_size(8)]] // expected-note {{previous attribute is here}} // expected-warning {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
114120
[[sycl::reqd_work_group_size(1, 1, 8)]] void // expected-error {{attribute 'reqd_work_group_size' is already applied with different arguments}}
115121
f8(){};
116122

117-
[[sycl::reqd_work_group_size(32, 32, 1)]] // expected-note {{previous attribute is here}}
123+
[[sycl::reqd_work_group_size(32, 32, 1)]] // expected-note {{previous attribute is here}} // expected-warning {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
118124
[[sycl::reqd_work_group_size(32, 32)]] void f9() {} // expected-error {{attribute 'reqd_work_group_size' is already applied with different arguments}}
119125

120126
// Test that template redeclarations also get diagnosed properly.
@@ -127,6 +133,8 @@ void test() {
127133
f10<64, 1, 1>(); // OK, args are the same on the redecl.
128134
// expected-error@#f10err {{attribute 'reqd_work_group_size' is already applied with different arguments}}
129135
// expected-note@#f10prev {{previous attribute is here}}
136+
// expected-warning@#f10prev {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
137+
// expected-warning@#f10prev {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
130138
f10<1, 1, 64>(); // expected-note {{in instantiation}}
131139
}
132140

@@ -135,7 +143,8 @@ struct TRIFuncObjBad {
135143
operator()() const;
136144
};
137145

138-
[[sycl::reqd_work_group_size(1, 1, 32)]] // expected-error {{attribute 'reqd_work_group_size' is already applied with different arguments}}
146+
[[sycl::reqd_work_group_size(1, 1, 32)]] // expected-error {{attribute 'reqd_work_group_size' is already applied with different arguments}} \
147+
// expected-warning {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
139148
void
140149
TRIFuncObjBad::operator()() const {}
141150

@@ -174,6 +183,7 @@ int main() {
174183
KernelFunctor<16, 1, 1>();
175184
}
176185
// Test that checks template parameter support on function.
186+
// expected-warning@+2 {{'reqd_work_group_size' attribute can only be applied to a SYCL kernel function}}
177187
template <int N, int N1, int N2>
178188
[[sycl::reqd_work_group_size(N, N1, N2)]] void func3() {}
179189

clang/test/SemaSYCL/sub-group-size.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,11 @@ void calls_kernel_4() {
123123
sycl::kernel_single_task<class Kernel4>([]() { // #Kernel4
124124
// integer-error@#AttrFunc2{{kernel-called function must have a sub group size that matches the size specified for the kernel}}
125125
// integer-note@#Kernel4{{kernel declared here}}
126+
// expected-warning@#AttrFunc2 {{'sub_group_size' attribute can only be applied to a SYCL kernel function}}
126127
AttrFunc2();
127128
// integer-error@#AttrExternalDefined2{{kernel-called function must have a sub group size that matches the size specified for the kernel}}
128129
// integer-note@#Kernel4{{kernel declared here}}
130+
// expected-warning@#AttrExternalDefined2 {{'sub_group_size' attribute can only be applied to a SYCL kernel function}}
129131
AttrExternalDefined2();
130132
// integer-error@#AttrExternalNotDefined2{{kernel-called function must have a sub group size that matches the size specified for the kernel}}
131133
// integer-note@#Kernel4{{kernel declared here}}

0 commit comments

Comments
 (0)