diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 73194b1d6f471..db702ec62e794 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -12079,11 +12079,33 @@ class Sema final { KernelCallDllimportFunction, KernelCallVariadicFunction }; - DeviceDiagBuilder SYCLDiagIfDeviceCode(SourceLocation Loc, unsigned DiagID); bool isKnownGoodSYCLDecl(const Decl *D); void ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, MangleContext &MC); void MarkDevice(void); - bool CheckSYCLCall(SourceLocation Loc, FunctionDecl *Callee); + + /// Creates a DeviceDiagBuilder that emits the diagnostic if the current + /// context is "used as device code". + /// + /// - If CurLexicalContext is a kernel function or it is known that the + /// function will be emitted for the device, emits the diagnostics + /// immediately. + /// - If CurLexicalContext is a function and we are compiling + /// for the device, but we don't know that this function will be codegen'ed + /// for devive yet, creates a diagnostic which is emitted if and when we + /// realize that the function will be codegen'ed. + /// + /// Example usage: + /// + /// Variables with thread storage duration are not allowed to be used in SYCL + /// device code + /// if (getLangOpts().SYCLIsDevice) + /// SYCLDiagIfDeviceCode(Loc, diag::err_thread_unsupported); + DeviceDiagBuilder SYCLDiagIfDeviceCode(SourceLocation Loc, unsigned DiagID); + + /// Checks if Callee function is a device function and emits + /// diagnostics if it is known that it is a device function, adds this + /// function to the DeviceCallGraph otherwise. + void checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee); }; /// RAII object that enters a new expression evaluation context. diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 8c9714d6e4420..d44fd674f2eb2 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1610,6 +1610,9 @@ Sema::DeviceDiagBuilder Sema::targetDiag(SourceLocation Loc, unsigned DiagID) { if (getLangOpts().CUDA) return getLangOpts().CUDAIsDevice ? CUDADiagIfDeviceCode(Loc, DiagID) : CUDADiagIfHostCode(Loc, DiagID); + // TODO: analyze which usages of targetDiag could be reused for SYCL. + // if (getLangOpts().SYCLIsDevice) + // return SYCLDiagIfDeviceCode(Loc, DiagID); return DeviceDiagBuilder(DeviceDiagBuilder::K_Immediate, Loc, DiagID, getCurFunctionDecl(), *this); } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 34137657a919e..437de8b595b4b 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -14644,7 +14644,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, if (getLangOpts().CUDA && !CheckCUDACall(ConstructLoc, Constructor)) return ExprError(); if (getLangOpts().SYCLIsDevice) - CheckSYCLCall(ConstructLoc, Constructor); + checkSYCLDeviceFunction(ConstructLoc, Constructor); return CXXConstructExpr::Create( Context, DeclInitType, ConstructLoc, Constructor, Elidable, diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index ac2a9e1cff08e..a0b4e6193c78d 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -269,7 +269,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef Locs, return true; if (getLangOpts().SYCLIsDevice) - CheckSYCLCall(Loc, FD); + checkSYCLDeviceFunction(Loc, FD); } if (auto *MD = dyn_cast(D)) { @@ -15649,7 +15649,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, if (getLangOpts().CUDA) CheckCUDACall(Loc, Func); if (getLangOpts().SYCLIsDevice) - CheckSYCLCall(Loc, Func); + checkSYCLDeviceFunction(Loc, Func); // If we need a definition, try to create one. if (NeedDefinition && !Func->getBody()) { @@ -17219,15 +17219,7 @@ namespace { } void VisitCXXNewExpr(CXXNewExpr *E) { - FunctionDecl *FD = E->getOperatorNew(); - if (FD && S.getLangOpts().SYCLIsDevice) { - if (FD->isReplaceableGlobalAllocationFunction()) - S.SYCLDiagIfDeviceCode(E->getExprLoc(), diag::err_sycl_restrict) - << S.KernelAllocateStorage; - else if (FunctionDecl *Def = FD->getDefinition()) - S.CheckSYCLCall(E->getExprLoc(), Def); - } - if (FD) + if (E->getOperatorNew()) S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorNew()); if (E->getOperatorDelete()) S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorDelete()); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index ed26411a2d22e..327bc100ce426 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -2171,16 +2171,15 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, if (DiagnoseUseOfDecl(OperatorNew, StartLoc)) return ExprError(); MarkFunctionReferenced(StartLoc, OperatorNew); - if (getLangOpts().SYCLIsDevice) { - CheckSYCLCall(StartLoc, OperatorNew); - } + if (getLangOpts().SYCLIsDevice && + OperatorNew->isReplaceableGlobalAllocationFunction()) + SYCLDiagIfDeviceCode(StartLoc, diag::err_sycl_restrict) + << KernelAllocateStorage; } if (OperatorDelete) { if (DiagnoseUseOfDecl(OperatorDelete, StartLoc)) return ExprError(); MarkFunctionReferenced(StartLoc, OperatorDelete); - if (getLangOpts().SYCLIsDevice) - CheckSYCLCall(StartLoc, OperatorDelete); } return CXXNewExpr::Create(Context, UseGlobal, OperatorNew, OperatorDelete, diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 5fb59b545176d..fa811ee2bd25a 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -12916,8 +12916,6 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, FnDecl->getType()->castAs())) return ExprError(); - if (getLangOpts().SYCLIsDevice) - CheckSYCLCall(OpLoc, FnDecl); return MaybeBindToTemporary(TheCall); } else { // We matched a built-in operator. Convert the arguments, then @@ -13270,8 +13268,6 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, isa(FnDecl), OpLoc, TheCall->getSourceRange(), VariadicDoesNotApply); - if (getLangOpts().SYCLIsDevice) - CheckSYCLCall(OpLoc, FnDecl); ExprResult R = MaybeBindToTemporary(TheCall); if (R.isInvalid()) return ExprError(); @@ -13633,8 +13629,6 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, Method->getType()->castAs())) return ExprError(); - if (getLangOpts().SYCLIsDevice) - CheckSYCLCall(RLoc, FnDecl); return MaybeBindToTemporary(TheCall); } else { // We matched a built-in operator. Convert the arguments, then diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index ea78f26bde711..513e48143d633 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -359,10 +359,7 @@ class MarkDeviceFunction : public RecursiveASTVisitor { // new operator and any user-defined overloads that // do not allocate storage are permitted. if (FunctionDecl *FD = E->getOperatorNew()) { - if (FD->isReplaceableGlobalAllocationFunction()) { - SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict) - << Sema::KernelAllocateStorage; - } else if (FunctionDecl *Def = FD->getDefinition()) { + if (FunctionDecl *Def = FD->getDefinition()) { if (!Def->hasAttr()) { Def->addAttr(SYCLDeviceAttr::CreateImplicit(SemaRef.Context)); SemaRef.addSyclDeviceDecl(Def); @@ -521,8 +518,7 @@ class MarkDeviceFunction : public RecursiveASTVisitor { if (!CheckSYCLType(Field->getType(), Field->getSourceRange(), Visited)) { if (SemaRef.getLangOpts().SYCLIsDevice) - SemaRef.SYCLDiagIfDeviceCode(Loc.getBegin(), - diag::note_sycl_used_here); + SemaRef.Diag(Loc.getBegin(), diag::note_sycl_used_here); return false; } } @@ -531,8 +527,7 @@ class MarkDeviceFunction : public RecursiveASTVisitor { if (!CheckSYCLType(Field->getType(), Field->getSourceRange(), Visited)) { if (SemaRef.getLangOpts().SYCLIsDevice) - SemaRef.SYCLDiagIfDeviceCode(Loc.getBegin(), - diag::note_sycl_used_here); + SemaRef.Diag(Loc.getBegin(), diag::note_sycl_used_here); return false; } } @@ -1390,8 +1385,7 @@ void Sema::MarkDevice(void) { // Do we know that we will eventually codegen the given function? static bool isKnownEmitted(Sema &S, FunctionDecl *FD) { - if (!FD) - return true; // Seen in LIT testing + assert(FD && "Given function may not be null."); if (FD->hasAttr() || FD->hasAttr()) return true; @@ -1407,16 +1401,16 @@ Sema::DeviceDiagBuilder Sema::SYCLDiagIfDeviceCode(SourceLocation Loc, "Should only be called during SYCL compilation"); FunctionDecl *FD = dyn_cast(getCurLexicalContext()); DeviceDiagBuilder::Kind DiagKind = [this, FD] { - if (ConstructingOpenCLKernel) + if (ConstructingOpenCLKernel || !FD) return DeviceDiagBuilder::K_Nop; - else if (isKnownEmitted(*this, FD)) + if (isKnownEmitted(*this, FD)) return DeviceDiagBuilder::K_ImmediateWithCallStack; return DeviceDiagBuilder::K_Deferred; }(); return DeviceDiagBuilder(DiagKind, Loc, DiagID, FD, *this); } -bool Sema::CheckSYCLCall(SourceLocation Loc, FunctionDecl *Callee) { +void Sema::checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) { assert(Callee && "Callee may not be null."); FunctionDecl *Caller = dyn_cast(getCurLexicalContext()); @@ -1426,7 +1420,6 @@ bool Sema::CheckSYCLCall(SourceLocation Loc, FunctionDecl *Callee) { markKnownEmitted(*this, Caller, Callee, Loc, isKnownEmitted); else if (Caller) DeviceCallGraph[Caller].insert({Callee, Loc}); - return true; } // ----------------------------------------------------------------------------- diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 2c8d1c386f14c..10f80d6c4fccd 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -259,12 +259,11 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, // Skip all the checks if we are compiling SYCL device code, but the function // is not marked to be used on device, this code won't be codegen'ed anyway. if (getLangOpts().SYCLIsDevice) { - SYCLDiagIfDeviceCode(AsmLoc, diag::err_sycl_restrict) - << KernelUseAssembly; + SYCLDiagIfDeviceCode(AsmLoc, diag::err_sycl_restrict) << KernelUseAssembly; return new (Context) - GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, - NumInputs, Names, Constraints, Exprs.data(), AsmString, - NumClobbers, Clobbers, NumLabels, RParenLoc); + GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, + Names, Constraints, Exprs.data(), AsmString, NumClobbers, + Clobbers, NumLabels, RParenLoc); } FunctionDecl *FD = dyn_cast(getCurLexicalContext()); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 732b3e06e8ccd..611c649338257 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1500,11 +1500,15 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = Context.DoubleTy; break; case DeclSpec::TST_float128: - if (!S.Context.getTargetInfo().hasFloat128Type() && - !S.getLangOpts().SYCLIsDevice && - !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) + if (!S.Context.getTargetInfo().hasFloat128Type() && + S.getLangOpts().SYCLIsDevice) + S.SYCLDiagIfDeviceCode(DS.getTypeSpecTypeLoc(), + diag::err_type_unsupported) + << "__float128"; + else if (!S.Context.getTargetInfo().hasFloat128Type() && + !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) - << "__float128"; + << "__float128"; Result = Context.Float128Ty; break; case DeclSpec::TST_bool: Result = Context.BoolTy; break; // _Bool or bool diff --git a/clang/test/SemaSYCL/inline-asm.cpp b/clang/test/SemaSYCL/inline-asm.cpp index 4d414e29a9aa7..fc5f0986e7adc 100644 --- a/clang/test/SemaSYCL/inline-asm.cpp +++ b/clang/test/SemaSYCL/inline-asm.cpp @@ -19,7 +19,7 @@ void bar() { #endif // LINUX_ASM } -template +template __attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) { // expected-note@+1 {{called by 'kernel_single_task // expected-note@+1 2{{function implemented using recursion declared here}} __attribute__((sycl_kernel)) void kernel_single_task2(Func kernelFunc) { + // expected-note@+1 {{called by 'kernel_single_task2}} kernelFunc(); - // expected-error@+1 2{{SYCL kernel cannot allocate storage}} - int *ip = new int; // expected-error@+1 2{{SYCL kernel cannot call a recursive function}} kernel_single_task2(kernelFunc); } int main() { + // expected-note@+1 {{called by 'operator()'}} kernel_single_task2([]() { usage3( &addInt ); }); return fib(5); } diff --git a/clang/test/SemaSYCL/restrict-recursion4.cpp b/clang/test/SemaSYCL/restrict-recursion4.cpp index 7264f2ccf803d..cad0b9aff7273 100644 --- a/clang/test/SemaSYCL/restrict-recursion4.cpp +++ b/clang/test/SemaSYCL/restrict-recursion4.cpp @@ -18,6 +18,8 @@ void kernel2(void) { using myFuncDef = int(int,int); void usage2(myFuncDef functionPtr) { + // expected-error@+1 {{SYCL kernel cannot allocate storage}} + int *ip = new int; // expected-error@+1 {{SYCL kernel cannot call a recursive function}} kernel2(); } @@ -28,12 +30,12 @@ int addInt(int n, int m) { template __attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) { - // expected-error@+1 {{SYCL kernel cannot allocate storage}} - int *ip = new int; + // expected-note@+1 {{called by 'kernel_single_task}} kernelFunc(); } int main() { + // expected-note@+1 {{called by 'operator()'}} kernel_single_task([]() {usage2(&addInt);}); return fib(5); } diff --git a/clang/test/SemaSYCL/sycl-restrict.cpp b/clang/test/SemaSYCL/sycl-restrict.cpp index 083b7f775f2cc..658395e92c3ff 100644 --- a/clang/test/SemaSYCL/sycl-restrict.cpp +++ b/clang/test/SemaSYCL/sycl-restrict.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -fcxx-exceptions -fsycl-is-device -Wno-return-type -verify -fsyntax-only -std=c++17 %s -// RUN: %clang_cc1 -fcxx-exceptions -fsycl-is-device -fno-sycl-allow-func-ptr -Wno-return-type -verify -fsyntax-only -std=c++17 %s -// RUN: %clang_cc1 -fcxx-exceptions -fsycl-is-device -DALLOW_FP=1 -fsycl-allow-func-ptr -Wno-return-type -verify -fsyntax-only -std=c++17 %s +// RUN: %clang_cc1 -fcxx-exceptions -triple spir64 -fsycl-is-device -Wno-return-type -verify -fsyntax-only -std=c++17 %s +// 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 +// 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 namespace std { @@ -65,6 +65,7 @@ bool isa_B(A *a) { // expected-error@+1 {{SYCL kernel cannot allocate storage}} int *ip = new int; int i; int *p3 = new(&i) int; // no error on placement new + // expected-note@+1 {{called by 'isa_B'}} OverloadedNewDelete *x = new( struct OverloadedNewDelete ); auto y = new struct OverloadedNewDelete [5]; // expected-error@+1 {{SYCL kernel cannot use rtti}} @@ -102,6 +103,7 @@ using myFuncDef = int(int,int); void eh_ok(void) { + __float128 A; try { ; } catch (...) { @@ -138,6 +140,9 @@ void usage(myFuncDef functionPtr) { Check_RTTI_Restriction::kernel1([]() { Check_RTTI_Restriction::A *a; Check_RTTI_Restriction::isa_B(a); }); + + // expected-error@+1 {{__float128 is not supported on this target}} + __float128 A; } namespace ns { @@ -172,9 +177,12 @@ int use2 ( a_type ab, a_type *abp ) { // expected-note@+1 {{called by 'use2'}} eh_not_ok(); Check_RTTI_Restriction:: A *a; + // expected-note@+1 2{{called by 'use2'}} Check_RTTI_Restriction:: isa_B(a); + // expected-note@+1 {{called by 'use2'}} usage(&addInt); Check_User_Operators::Fraction f1(3, 8), f2(1, 2), f3(10, 2); + // expected-note@+1 {{called by 'use2'}} if (f1 == f2) return false; } @@ -183,7 +191,7 @@ __attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) { kernelFunc(); a_type ab; a_type *p; - // expected-note@+1 {{called by 'kernel_single_task'}} + // expected-note@+1 5{{called by 'kernel_single_task'}} use2(ab, p); }