Skip to content

Commit 30d5d1a

Browse files
committed
[SYCL] Deferred diagnostics for SYCL Device
Signed-off-by: Premanand M Rao <premanand.m.rao@intel.com>
1 parent 4bcb91e commit 30d5d1a

16 files changed

+179
-81
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

+3-2
Original file line numberDiff line numberDiff line change
@@ -9721,11 +9721,12 @@ def err_sycl_restrict : Error<
97219721
"|use rtti"
97229722
"|use a non-const static data variable"
97239723
"|call a virtual function"
9724+
"|use exceptions"
97249725
"|call a recursive function"
97259726
"|call through a function pointer"
97269727
"|allocate storage"
9727-
"|use exceptions"
9728-
"|use inline assembly}0">;
9728+
"|use inline assembly"
9729+
"|have a class with a virtual function table}0">;
97299730
def err_sycl_virtual_types : Error<
97309731
"No class with a vtable can be used in a SYCL kernel or any code included in the kernel">;
97319732
def note_sycl_used_here : Note<"used here">;

clang/include/clang/Sema/Sema.h

+14
Original file line numberDiff line numberDiff line change
@@ -11275,8 +11275,22 @@ class Sema {
1127511275
return *SyclIntHeader.get();
1127611276
}
1127711277

11278+
enum SYCLRestrictKind {
11279+
KernelGlobalVariable,
11280+
KernelRTTI,
11281+
KernelNonConstStaticDataVariable,
11282+
KernelCallVirtualFunction,
11283+
KernelUseExceptions,
11284+
KernelCallRecursiveFunction,
11285+
KernelCallFunctionPointer,
11286+
KernelAllocateStorage,
11287+
KernelUseAssembly,
11288+
KernelHavePolymorphicClass
11289+
};
11290+
DeviceDiagBuilder SYCLDiagIfDeviceCode(SourceLocation Loc, unsigned DiagID);
1127811291
void ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc);
1127911292
void MarkDevice(void);
11293+
bool CheckSYCLCall(SourceLocation Loc, FunctionDecl *Callee);
1128011294
};
1128111295

1128211296
/// RAII object that enters a new expression evaluation context.

clang/lib/Sema/SemaDeclCXX.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -13031,6 +13031,8 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
1303113031
MarkFunctionReferenced(ConstructLoc, Constructor);
1303213032
if (getLangOpts().CUDA && !CheckCUDACall(ConstructLoc, Constructor))
1303313033
return ExprError();
13034+
if (getLangOpts().SYCLIsDevice)
13035+
CheckSYCLCall(ConstructLoc, Constructor);
1303413036

1303513037
return CXXConstructExpr::Create(
1303613038
Context, DeclInitType, ConstructLoc, Constructor, Elidable,

clang/lib/Sema/SemaExpr.cpp

+14-1
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,9 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
271271

272272
if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD))
273273
return true;
274+
275+
if (getLangOpts().SYCLIsDevice)
276+
CheckSYCLCall(Loc, FD);
274277
}
275278

276279
if (auto *MD = dyn_cast<CXXMethodDecl>(D)) {
@@ -14903,6 +14906,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
1490314906

1490414907
if (getLangOpts().CUDA)
1490514908
CheckCUDACall(Loc, Func);
14909+
if (getLangOpts().SYCLIsDevice)
14910+
CheckSYCLCall(Loc, Func);
1490614911

1490714912
// If we don't need to mark the function as used, and we don't need to
1490814913
// try to provide a definition, there's nothing more to do.
@@ -16124,7 +16129,15 @@ namespace {
1612416129
}
1612516130

1612616131
void VisitCXXNewExpr(CXXNewExpr *E) {
16127-
if (E->getOperatorNew())
16132+
FunctionDecl *FD = E->getOperatorNew();
16133+
if (FD && S.getLangOpts().SYCLIsDevice) {
16134+
if (FD->isReplaceableGlobalAllocationFunction())
16135+
S.SYCLDiagIfDeviceCode(E->getExprLoc(), diag::err_sycl_restrict)
16136+
<< S.KernelAllocateStorage;
16137+
else if (FunctionDecl *Def = FD->getDefinition())
16138+
S.CheckSYCLCall(E->getExprLoc(), Def);
16139+
}
16140+
if (FD)
1612816141
S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorNew());
1612916142
if (E->getOperatorDelete())
1613016143
S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorDelete());

clang/lib/Sema/SemaExprCXX.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,11 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
760760
CUDADiagIfDeviceCode(OpLoc, diag::err_cuda_device_exceptions)
761761
<< "throw" << CurrentCUDATarget();
762762

763+
// Exceptions aren't allowed in SYCL device code.
764+
if (getLangOpts().SYCLIsDevice)
765+
SYCLDiagIfDeviceCode(OpLoc, diag::err_sycl_restrict)
766+
<< Sema::KernelUseExceptions;
767+
763768
if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())
764769
Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw";
765770

@@ -2193,11 +2198,16 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
21932198
if (DiagnoseUseOfDecl(OperatorNew, StartLoc))
21942199
return ExprError();
21952200
MarkFunctionReferenced(StartLoc, OperatorNew);
2201+
if (getLangOpts().SYCLIsDevice) {
2202+
CheckSYCLCall(StartLoc, OperatorNew);
2203+
}
21962204
}
21972205
if (OperatorDelete) {
21982206
if (DiagnoseUseOfDecl(OperatorDelete, StartLoc))
21992207
return ExprError();
22002208
MarkFunctionReferenced(StartLoc, OperatorDelete);
2209+
if (getLangOpts().SYCLIsDevice)
2210+
CheckSYCLCall(StartLoc, OperatorDelete);
22012211
}
22022212

22032213
return CXXNewExpr::Create(Context, UseGlobal, OperatorNew, OperatorDelete,

clang/lib/Sema/SemaOverload.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -12396,6 +12396,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
1239612396
FnDecl->getType()->castAs<FunctionProtoType>()))
1239712397
return ExprError();
1239812398

12399+
if (getLangOpts().SYCLIsDevice)
12400+
CheckSYCLCall(OpLoc, FnDecl);
1239912401
return MaybeBindToTemporary(TheCall);
1240012402
} else {
1240112403
// We matched a built-in operator. Convert the arguments, then
@@ -12639,6 +12641,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
1263912641
isa<CXXMethodDecl>(FnDecl), OpLoc, TheCall->getSourceRange(),
1264012642
VariadicDoesNotApply);
1264112643

12644+
if (getLangOpts().SYCLIsDevice)
12645+
CheckSYCLCall(OpLoc, FnDecl);
1264212646
return MaybeBindToTemporary(TheCall);
1264312647
} else {
1264412648
// We matched a built-in operator. Convert the arguments, then
@@ -12852,6 +12856,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
1285212856
Method->getType()->castAs<FunctionProtoType>()))
1285312857
return ExprError();
1285412858

12859+
if (getLangOpts().SYCLIsDevice)
12860+
CheckSYCLCall(RLoc, FnDecl);
1285512861
return MaybeBindToTemporary(TheCall);
1285612862
} else {
1285712863
// We matched a built-in operator. Convert the arguments, then

clang/lib/Sema/SemaSYCL.cpp

+77-54
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,6 @@ enum target {
3838
image_array
3939
};
4040

41-
enum RestrictKind {
42-
KernelGlobalVariable,
43-
KernelRTTI,
44-
KernelNonConstStaticDataVariable,
45-
KernelCallVirtualFunction,
46-
KernelCallRecursiveFunction,
47-
KernelCallFunctionPointer,
48-
KernelAllocateStorage,
49-
KernelUseExceptions,
50-
KernelUseAssembly
51-
};
52-
5341
using ParamDesc = std::tuple<QualType, IdentifierInfo *, TypeSourceInfo *>;
5442

5543
/// Various utilities.
@@ -95,16 +83,16 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
9583
// definitions.
9684
if (RecursiveSet.count(Callee)) {
9785
SemaRef.Diag(e->getExprLoc(), diag::err_sycl_restrict)
98-
<< KernelCallRecursiveFunction;
86+
<< Sema::KernelCallRecursiveFunction;
9987
SemaRef.Diag(Callee->getSourceRange().getBegin(),
10088
diag::note_sycl_recursive_function_declared_here)
101-
<< KernelCallRecursiveFunction;
89+
<< Sema::KernelCallRecursiveFunction;
10290
}
10391

10492
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Callee))
10593
if (Method->isVirtual())
10694
SemaRef.Diag(e->getExprLoc(), diag::err_sycl_restrict)
107-
<< KernelCallVirtualFunction;
95+
<< Sema::KernelCallVirtualFunction;
10896

10997
CheckSYCLType(Callee->getReturnType(), Callee->getSourceRange());
11098

@@ -116,7 +104,7 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
116104
}
117105
} else if (!SemaRef.getLangOpts().SYCLAllowFuncPtr)
118106
SemaRef.Diag(e->getExprLoc(), diag::err_sycl_restrict)
119-
<< KernelCallFunctionPointer;
107+
<< Sema::KernelCallFunctionPointer;
120108
return true;
121109
}
122110

@@ -144,12 +132,12 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
144132
}
145133

146134
bool VisitCXXTypeidExpr(CXXTypeidExpr *E) {
147-
SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict) << KernelRTTI;
135+
SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict) << Sema::KernelRTTI;
148136
return true;
149137
}
150138

151139
bool VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E) {
152-
SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict) << KernelRTTI;
140+
SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict) << Sema::KernelRTTI;
153141
return true;
154142
}
155143

@@ -178,7 +166,7 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
178166
bool IsConst = VD->getType().getNonReferenceType().isConstQualified();
179167
if (!IsConst && VD->isStaticDataMember())
180168
SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict)
181-
<< KernelNonConstStaticDataVariable;
169+
<< Sema::KernelNonConstStaticDataVariable;
182170
}
183171
return true;
184172
}
@@ -189,11 +177,11 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
189177
bool IsConst = VD->getType().getNonReferenceType().isConstQualified();
190178
if (!IsConst && VD->isStaticDataMember())
191179
SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict)
192-
<< KernelNonConstStaticDataVariable;
180+
<< Sema::KernelNonConstStaticDataVariable;
193181
else if (!IsConst && VD->hasGlobalStorage() && !VD->isStaticLocal() &&
194182
!VD->isStaticDataMember() && !isa<ParmVarDecl>(VD))
195183
SemaRef.Diag(E->getLocation(), diag::err_sycl_restrict)
196-
<< KernelGlobalVariable;
184+
<< Sema::KernelGlobalVariable;
197185
if (!VD->isLocalVarDeclOrParm() && VD->hasGlobalStorage()) {
198186
VD->addAttr(SYCLDeviceAttr::CreateImplicit(SemaRef.Context));
199187
SemaRef.addSyclDeviceDecl(VD);
@@ -213,7 +201,7 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
213201
if (FunctionDecl *FD = E->getOperatorNew()) {
214202
if (FD->isReplaceableGlobalAllocationFunction()) {
215203
SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict)
216-
<< KernelAllocateStorage;
204+
<< Sema::KernelAllocateStorage;
217205
} else if (FunctionDecl *Def = FD->getDefinition()) {
218206
if (!Def->hasAttr<SYCLDeviceAttr>()) {
219207
Def->addAttr(SYCLDeviceAttr::CreateImplicit(SemaRef.Context));
@@ -223,40 +211,16 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
223211
}
224212
return true;
225213
}
226-
227-
bool VisitCXXThrowExpr(CXXThrowExpr *E) {
228-
SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict)
229-
<< KernelUseExceptions;
230-
return true;
231-
}
232-
233-
bool VisitCXXCatchStmt(CXXCatchStmt *S) {
234-
SemaRef.Diag(S->getBeginLoc(), diag::err_sycl_restrict)
235-
<< KernelUseExceptions;
236-
return true;
237-
}
238-
239-
bool VisitCXXTryStmt(CXXTryStmt *S) {
240-
SemaRef.Diag(S->getBeginLoc(), diag::err_sycl_restrict)
241-
<< KernelUseExceptions;
242-
return true;
243-
}
244-
245-
bool VisitSEHTryStmt(SEHTryStmt *S) {
246-
SemaRef.Diag(S->getBeginLoc(), diag::err_sycl_restrict)
247-
<< KernelUseExceptions;
248-
return true;
249-
}
250-
214+
251215
bool VisitGCCAsmStmt(GCCAsmStmt *S) {
252216
SemaRef.Diag(S->getBeginLoc(), diag::err_sycl_restrict)
253-
<< KernelUseAssembly;
217+
<< Sema::KernelUseAssembly;
254218
return true;
255219
}
256-
220+
257221
bool VisitMSAsmStmt(MSAsmStmt *S) {
258222
SemaRef.Diag(S->getBeginLoc(), diag::err_sycl_restrict)
259-
<< KernelUseAssembly;
223+
<< Sema::KernelUseAssembly;
260224
return true;
261225
}
262226

@@ -361,21 +325,31 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
361325
return true;
362326

363327
if (CRD->isPolymorphic()) {
364-
SemaRef.Diag(CRD->getLocation(), diag::err_sycl_virtual_types);
365-
SemaRef.Diag(Loc.getBegin(), diag::note_sycl_used_here);
328+
// Exceptions aren't allowed in SYCL device code.
329+
if (SemaRef.getLangOpts().SYCLIsDevice) {
330+
SemaRef.SYCLDiagIfDeviceCode(CRD->getLocation(),
331+
diag::err_sycl_restrict)
332+
<< Sema::KernelHavePolymorphicClass;
333+
SemaRef.SYCLDiagIfDeviceCode(Loc.getBegin(),
334+
diag::note_sycl_used_here);
335+
}
366336
return false;
367337
}
368338

369339
for (const auto &Field : CRD->fields()) {
370340
if (!CheckSYCLType(Field->getType(), Field->getSourceRange(), Visited)) {
371-
SemaRef.Diag(Loc.getBegin(), diag::note_sycl_used_here);
341+
if (SemaRef.getLangOpts().SYCLIsDevice)
342+
SemaRef.SYCLDiagIfDeviceCode(Loc.getBegin(),
343+
diag::note_sycl_used_here);
372344
return false;
373345
}
374346
}
375347
} else if (const auto *RD = Ty->getAsRecordDecl()) {
376348
for (const auto &Field : RD->fields()) {
377349
if (!CheckSYCLType(Field->getType(), Field->getSourceRange(), Visited)) {
378-
SemaRef.Diag(Loc.getBegin(), diag::note_sycl_used_here);
350+
if (SemaRef.getLangOpts().SYCLIsDevice)
351+
SemaRef.SYCLDiagIfDeviceCode(Loc.getBegin(),
352+
diag::note_sycl_used_here);
379353
return false;
380354
}
381355
}
@@ -1036,6 +1010,55 @@ void Sema::MarkDevice(void) {
10361010
}
10371011
}
10381012
}
1013+
//
1014+
// Do we know that we will eventually codegen the given function?
1015+
static bool isKnownEmitted(Sema &S, FunctionDecl *FD) {
1016+
if (!FD)
1017+
return true; // Seen in LIT testing
1018+
1019+
if (FD->hasAttr<SYCLDeviceAttr>() ||
1020+
FD->hasAttr<SYCLKernelAttr>())
1021+
return true;
1022+
1023+
// Templates are emitted when they're instantiated.
1024+
if (FD->isDependentContext())
1025+
return false;
1026+
1027+
// Otherwise, the function is known-emitted if it's in our set of
1028+
// known-emitted functions.
1029+
return S.DeviceKnownEmittedFns.count(FD) > 0;
1030+
}
1031+
1032+
Sema::DeviceDiagBuilder Sema::SYCLDiagIfDeviceCode(SourceLocation Loc,
1033+
unsigned DiagID) {
1034+
assert(getLangOpts().SYCLIsDevice &&
1035+
"Should only be called during SYCL compilation");
1036+
DeviceDiagBuilder::Kind DiagKind = [this] {
1037+
if (isKnownEmitted(*this, dyn_cast<FunctionDecl>(CurContext)))
1038+
return DeviceDiagBuilder::K_ImmediateWithCallStack;
1039+
else
1040+
return DeviceDiagBuilder::K_Deferred;
1041+
}();
1042+
return DeviceDiagBuilder(DiagKind, Loc, DiagID,
1043+
dyn_cast<FunctionDecl>(CurContext), *this);
1044+
}
1045+
1046+
bool Sema::CheckSYCLCall(SourceLocation Loc, FunctionDecl *Callee) {
1047+
1048+
assert(Callee && "Callee may not be null.");
1049+
FunctionDecl *Caller = getCurFunctionDecl();
1050+
1051+
// If the caller is known-emitted, mark the callee as known-emitted.
1052+
// Otherwise, mark the call in our call graph so we can traverse it later.
1053+
if (//!isOpenMPDeviceDelayedContext(*this) ||
1054+
(Caller && Caller->hasAttr<SYCLKernelAttr>()) ||
1055+
(Caller && Caller->hasAttr<SYCLDeviceAttr>()) ||
1056+
(Caller && isKnownEmitted(*this, Caller)))
1057+
markKnownEmitted(*this, Caller, Callee, Loc, isKnownEmitted);
1058+
else if (Caller)
1059+
DeviceCallGraph[Caller].insert({Callee, Loc});
1060+
return true;
1061+
}
10391062

10401063
// -----------------------------------------------------------------------------
10411064
// Integration header functionality implementation

clang/lib/Sema/SemaStmt.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -4017,6 +4017,11 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
40174017
CUDADiagIfDeviceCode(TryLoc, diag::err_cuda_device_exceptions)
40184018
<< "try" << CurrentCUDATarget();
40194019

4020+
// Exceptions aren't allowed in SYCL device code.
4021+
if (getLangOpts().SYCLIsDevice)
4022+
SYCLDiagIfDeviceCode(TryLoc, diag::err_sycl_restrict)
4023+
<< KernelUseExceptions;
4024+
40204025
if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())
40214026
Diag(TryLoc, diag::err_omp_simd_region_cannot_use_stmt) << "try";
40224027

@@ -4114,6 +4119,11 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
41144119
}
41154120
}
41164121

4122+
// Exceptions aren't allowed in SYCL device code.
4123+
if (getLangOpts().SYCLIsDevice)
4124+
SYCLDiagIfDeviceCode(TryLoc, diag::err_sycl_restrict)
4125+
<< KernelUseExceptions;
4126+
41174127
FSI->setHasSEHTry(TryLoc);
41184128

41194129
// Reject __try in Obj-C methods, blocks, and captured decls, since we don't

0 commit comments

Comments
 (0)