Skip to content

Commit 1853516

Browse files
authored
[SYCL] Forbid non-const static variable uses in device code (#1213)
Signed-off-by: Aleksander Fadeev <[email protected]>
1 parent dcbdcfd commit 1853516

File tree

6 files changed

+104
-82
lines changed

6 files changed

+104
-82
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10626,7 +10626,7 @@ def err_sycl_kernel_name_class_not_top_level : Error<
1062610626
"nest in a namespace: %0">;
1062710627
def err_sycl_restrict : Error<
1062810628
"SYCL kernel cannot "
10629-
"%select{use a global variable"
10629+
"%select{use a non-const global variable"
1063010630
"|use rtti"
1063110631
"|use a non-const static data variable"
1063210632
"|call a virtual function"

clang/lib/Sema/SemaExpr.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,15 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
210210
bool ObjCPropertyAccess,
211211
bool AvoidPartialAvailabilityChecks,
212212
ObjCInterfaceDecl *ClassReceiver) {
213+
if (getLangOpts().SYCLIsDevice) {
214+
if (auto VD = dyn_cast<VarDecl>(D)) {
215+
if (VD->getStorageClass() == SC_Static &&
216+
!VD->getType().isConstant(Context))
217+
SYCLDiagIfDeviceCode(*Locs.begin(), diag::err_sycl_restrict)
218+
<< Sema::KernelNonConstStaticDataVariable;
219+
}
220+
}
221+
213222
SourceLocation Loc = Locs.front();
214223
if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) {
215224
// If there were any diagnostics suppressed by template argument deduction,

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -321,29 +321,16 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
321321
return true;
322322
}
323323

324-
bool VisitMemberExpr(MemberExpr *E) {
325-
if (VarDecl *VD = dyn_cast<VarDecl>(E->getMemberDecl())) {
326-
bool IsConst = VD->getType().getNonReferenceType().isConstQualified();
327-
if (!IsConst && VD->isStaticDataMember())
328-
SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict)
329-
<< Sema::KernelNonConstStaticDataVariable;
330-
}
331-
return true;
332-
}
333-
334324
bool VisitDeclRefExpr(DeclRefExpr *E) {
335-
Decl* D = E->getDecl();
325+
Decl *D = E->getDecl();
336326
if (SemaRef.isKnownGoodSYCLDecl(D))
337327
return true;
338328

339329
CheckSYCLType(E->getType(), E->getSourceRange());
340330
if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
341331
bool IsConst = VD->getType().getNonReferenceType().isConstQualified();
342-
if (!IsConst && VD->isStaticDataMember())
343-
SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict)
344-
<< Sema::KernelNonConstStaticDataVariable;
345-
else if (!IsConst && VD->hasGlobalStorage() && !VD->isStaticLocal() &&
346-
!VD->isStaticDataMember() && !isa<ParmVarDecl>(VD)) {
332+
if (!IsConst && VD->hasGlobalStorage() && !VD->isStaticLocal() &&
333+
!VD->isStaticDataMember() && !isa<ParmVarDecl>(VD)) {
347334
if (VD->getTLSKind() != VarDecl::TLS_None)
348335
SemaRef.Diag(E->getLocation(), diag::err_thread_unsupported);
349336
SemaRef.Diag(E->getLocation(), diag::err_sycl_restrict)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_cc1 -verify -fsyntax-only -fsycl-is-device %s
2+
const int glob1 = 1;
3+
int glob2 = 2;
4+
template <typename name, typename Func>
5+
__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) {
6+
// expected-note-re@+1{{called by 'kernel_single_task<fake_kernel, (lambda at {{.*}})>}}
7+
kernelFunc();
8+
}
9+
10+
int main() {
11+
static int n = 0;
12+
const static int l = 0;
13+
kernel_single_task<class fake_kernel>([]() {
14+
int m = l;
15+
m = glob1;
16+
// expected-error@+1{{SYCL kernel cannot use a non-const static data variable}}
17+
m = n;
18+
// expected-error@+1{{SYCL kernel cannot use a non-const global variable}}
19+
m = glob2;
20+
});
21+
return 0;
22+
}

clang/test/SemaSYCL/sycl-restrict.cpp

Lines changed: 67 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,39 @@
22
// RUN: %clang_cc1 -fcxx-exceptions -triple spir64 -fsycl-is-device -fno-sycl-allow-func-ptr -Wno-return-type -verify -fsyntax-only -std=c++17 %s
33
// RUN: %clang_cc1 -fcxx-exceptions -triple spir64 -fsycl-is-device -DALLOW_FP=1 -fsycl-allow-func-ptr -Wno-return-type -verify -fsyntax-only -std=c++17 %s
44

5-
65
namespace std {
7-
class type_info;
8-
typedef __typeof__(sizeof(int)) size_t;
9-
}
6+
class type_info;
7+
typedef __typeof__(sizeof(int)) size_t;
8+
} // namespace std
109
namespace Check_User_Operators {
11-
class Fraction
12-
{
13-
// expected-error@+2 {{SYCL kernel cannot call a recursive function}}
14-
// expected-note@+1 {{function implemented using recursion declared here}}
15-
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
16-
int n, d;
10+
class Fraction {
11+
// expected-error@+2 {{SYCL kernel cannot call a recursive function}}
12+
// expected-note@+1 {{function implemented using recursion declared here}}
13+
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
14+
int n, d;
15+
1716
public:
18-
Fraction(int n, int d = 1) : n(n/gcd(n, d)), d(d/gcd(n, d)) { }
19-
int num() const { return n; }
20-
int den() const { return d; }
17+
Fraction(int n, int d = 1) : n(n / gcd(n, d)), d(d / gcd(n, d)) {}
18+
int num() const { return n; }
19+
int den() const { return d; }
2120
};
22-
bool operator==(const Fraction& lhs, const Fraction& rhs)
23-
{
24-
new int; // expected-error {{SYCL kernel cannot allocate storage}}
25-
return lhs.num() == rhs.num() && lhs.den() == rhs.den();
26-
}}
21+
bool operator==(const Fraction &lhs, const Fraction &rhs) {
22+
new int; // expected-error {{SYCL kernel cannot allocate storage}}
23+
return lhs.num() == rhs.num() && lhs.den() == rhs.den();
24+
}
25+
} // namespace Check_User_Operators
2726

2827
namespace Check_VLA_Restriction {
2928
void no_restriction(int p) {
30-
int index[p+2];
29+
int index[p + 2];
3130
}
3231
void restriction(int p) {
3332
// expected-error@+1 {{variable length arrays are not supported for the current target}}
34-
int index[p+2];
35-
}
33+
int index[p + 2];
3634
}
35+
} // namespace Check_VLA_Restriction
3736

38-
void* operator new (std::size_t size, void* ptr) throw() { return ptr; };
37+
void *operator new(std::size_t size, void *ptr) throw() { return ptr; };
3938
namespace Check_RTTI_Restriction {
4039
struct A {
4140
virtual ~A(){};
@@ -50,35 +49,38 @@ struct OverloadedNewDelete {
5049
void *operator new(std::size_t size) throw() {
5150
// expected-error@+1 {{SYCL kernel cannot allocate storage}}
5251
float *pt = new float;
53-
return 0;}
52+
return 0;
53+
}
5454
// This overload does not allocate: no diagnostic.
55-
void *operator new[](std::size_t size) throw() {return 0;}
55+
void *operator new[](std::size_t size) throw() { return 0; }
5656
void operator delete(void *){};
5757
void operator delete[](void *){};
5858
};
5959

6060
bool isa_B(A *a) {
6161
Check_User_Operators::Fraction f1(3, 8), f2(1, 2), f3(10, 2);
62-
if (f1 == f2) return false;
62+
if (f1 == f2)
63+
return false;
6364

6465
Check_VLA_Restriction::restriction(7);
6566
// expected-error@+1 {{SYCL kernel cannot allocate storage}}
6667
int *ip = new int;
67-
int i; int *p3 = new(&i) int; // no error on placement new
68+
int i;
69+
int *p3 = new (&i) int; // no error on placement new
6870
// expected-note@+1 {{called by 'isa_B'}}
69-
OverloadedNewDelete *x = new( struct OverloadedNewDelete );
70-
auto y = new struct OverloadedNewDelete [5];
71+
OverloadedNewDelete *x = new (struct OverloadedNewDelete);
72+
auto y = new struct OverloadedNewDelete[5];
7173
// expected-error@+1 {{SYCL kernel cannot use rtti}}
7274
(void)typeid(int);
7375
// expected-error@+1 {{SYCL kernel cannot use rtti}}
7476
return dynamic_cast<B *>(a) != 0;
7577
}
7678

77-
template<typename N, typename L>
79+
template <typename N, typename L>
7880
__attribute__((sycl_kernel)) void kernel1(L l) {
7981
l();
8082
}
81-
}
83+
} // namespace Check_RTTI_Restriction
8284

8385
typedef struct Base {
8486
virtual void f() const {}
@@ -87,22 +89,19 @@ typedef struct Base {
8789
typedef struct A {
8890
static int stat_member;
8991
const static int const_stat_member;
90-
constexpr static int constexpr_stat_member=0;
92+
constexpr static int constexpr_stat_member = 0;
9193

92-
int fm(void)
93-
{
94+
int fm(void) {
9495
// expected-error@+1 {{SYCL kernel cannot use a non-const static data variable}}
9596
return stat_member;
9697
}
9798
} a_type;
9899

99-
100100
b_type b;
101101

102-
using myFuncDef = int(int,int);
102+
using myFuncDef = int(int, int);
103103

104-
void eh_ok(void)
105-
{
104+
void eh_ok(void) {
106105
__float128 A;
107106
try {
108107
;
@@ -112,8 +111,7 @@ void eh_ok(void)
112111
throw 20;
113112
}
114113

115-
void eh_not_ok(void)
116-
{
114+
void eh_not_ok(void) {
117115
// expected-error@+1 {{SYCL kernel cannot use exceptions}}
118116
try {
119117
;
@@ -134,7 +132,7 @@ void usage(myFuncDef functionPtr) {
134132
// expected-error@+2 {{SYCL kernel cannot call through a function pointer}}
135133
#endif
136134
if ((*functionPtr)(1, 2))
137-
// expected-error@+2 {{SYCL kernel cannot use a global variable}}
135+
// expected-error@+2 {{SYCL kernel cannot use a non-const global variable}}
138136
// expected-error@+1 {{SYCL kernel cannot call a virtual function}}
139137
b.f();
140138
Check_RTTI_Restriction::kernel1<class kernel_name>([]() {
@@ -146,58 +144,64 @@ void usage(myFuncDef functionPtr) {
146144
}
147145

148146
namespace ns {
149-
int glob;
147+
int glob;
150148
}
151149
extern "C++" {
152-
int another_global = 5;
153-
namespace AnotherNS {
154-
int moar_globals = 5;
155-
}
150+
int another_global = 5;
151+
namespace AnotherNS {
152+
int moar_globals = 5;
153+
}
156154
}
157155

158156
int addInt(int n, int m) {
159-
return n+m;
157+
return n + m;
160158
}
161159

162-
int use2 ( a_type ab, a_type *abp ) {
160+
int use2(a_type ab, a_type *abp) {
163161

164-
if (ab.constexpr_stat_member) return 2;
165-
if (ab.const_stat_member) return 1;
162+
if (ab.constexpr_stat_member)
163+
return 2;
164+
if (ab.const_stat_member)
165+
return 1;
166166
// expected-error@+1 {{SYCL kernel cannot use a non-const static data variable}}
167-
if (ab.stat_member) return 0;
167+
if (ab.stat_member)
168+
return 0;
168169
// expected-error@+1 {{SYCL kernel cannot use a non-const static data variable}}
169-
if (abp->stat_member) return 0;
170-
if (ab.fm()) return 0;
171-
// expected-error@+1 {{SYCL kernel cannot use a global variable}}
172-
return another_global ;
173-
// expected-error@+1 {{SYCL kernel cannot use a global variable}}
170+
if (abp->stat_member)
171+
return 0;
172+
// expected-note@+1 {{called by 'use2'}}
173+
if (ab.fm())
174+
return 0;
175+
// expected-error@+1 {{SYCL kernel cannot use a non-const global variable}}
176+
return another_global;
177+
// expected-error@+1 {{SYCL kernel cannot use a non-const global variable}}
174178
return ns::glob +
175-
// expected-error@+1 {{SYCL kernel cannot use a global variable}}
176-
AnotherNS::moar_globals;
179+
// expected-error@+1 {{SYCL kernel cannot use a non-const global variable}}
180+
AnotherNS::moar_globals;
177181
// expected-note@+1 {{called by 'use2'}}
178182
eh_not_ok();
179-
Check_RTTI_Restriction:: A *a;
183+
Check_RTTI_Restriction::A *a;
180184
// expected-note@+1 2{{called by 'use2'}}
181-
Check_RTTI_Restriction:: isa_B(a);
185+
Check_RTTI_Restriction::isa_B(a);
182186
// expected-note@+1 {{called by 'use2'}}
183187
usage(&addInt);
184188
Check_User_Operators::Fraction f1(3, 8), f2(1, 2), f3(10, 2);
185189
// expected-note@+1 {{called by 'use2'}}
186-
if (f1 == f2) return false;
190+
if (f1 == f2)
191+
return false;
187192
}
188193

189194
template <typename name, typename Func>
190195
__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) {
191196
kernelFunc();
192197
a_type ab;
193198
a_type *p;
194-
// expected-note@+1 5{{called by 'kernel_single_task}}
199+
// expected-note@+1 7{{called by 'kernel_single_task}}
195200
use2(ab, p);
196201
}
197202

198203
int main() {
199204
a_type ab;
200-
kernel_single_task<class fake_kernel>([]() { usage( &addInt ); });
205+
kernel_single_task<class fake_kernel>([]() { usage(&addInt); });
201206
return 0;
202207
}
203-

clang/test/SemaSYCL/tls_error.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ extern __thread void (*__once_call)(); // expected-no-error
55

66
void usage() {
77
// expected-error@+2{{thread-local storage is not supported for the current target}}
8-
// expected-error@+1{{SYCL kernel cannot use a global variable}}
8+
// expected-error@+1{{SYCL kernel cannot use a non-const global variable}}
99
__once_callable = 0;
1010
// expected-error@+3{{thread-local storage is not supported for the current target}}
11-
// expected-error@+2{{SYCL kernel cannot use a global variable}}
11+
// expected-error@+2{{SYCL kernel cannot use a non-const global variable}}
1212
// expected-error@+1{{SYCL kernel cannot call through a function pointer}}
1313
__once_call();
1414
}

0 commit comments

Comments
 (0)