diff options
-rw-r--r-- | clang/include/clang/Basic/LangOptions.def | 1 | ||||
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 20 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOpenMP.cpp | 50 | ||||
-rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 13 | ||||
-rw-r--r-- | clang/test/OpenMP/nvptx_target_exceptions_messages.cpp | 13 |
8 files changed, 100 insertions, 14 deletions
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 4e391d2562c..d52f9c0b68a 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -203,7 +203,6 @@ LANGOPT(OpenMPUseTLS , 1, 0, "Use TLS for threadprivates or runtime calls") LANGOPT(OpenMPIsDevice , 1, 0, "Generate code only for OpenMP target device") LANGOPT(OpenMPCUDAMode , 1, 0, "Generate code for OpenMP pragmas in SIMT/SPMD mode") LANGOPT(OpenMPCUDAForceFullRuntime , 1, 0, "Force to use full runtime in all constructs when offloading to CUDA devices") -LANGOPT(OpenMPHostCXXExceptions , 1, 0, "C++ exceptions handling in the host code.") LANGOPT(OpenMPCUDANumSMs , 32, 0, "Number of SMs for CUDA devices.") LANGOPT(OpenMPCUDABlocksPerSM , 32, 0, "Number of blocks per SM for CUDA devices.") LANGOPT(OpenMPOptimisticCollapse , 1, 0, "Use at most 32 bits to represent the collapsed loop nest counter.") diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 36b856edfa6..0c2479a0207 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -8763,6 +8763,9 @@ private: /// Pop OpenMP function region for non-capturing function. void popOpenMPFunctionRegion(const sema::FunctionScopeInfo *OldFSI); + /// Check whether we're allowed to call Callee from the current function. + void checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee); + /// Checks if a type or a declaration is disabled due to the owning extension /// being disabled, and emits diagnostic messages if it is disabled. /// \param D type or declaration to be checked. @@ -10249,6 +10252,23 @@ public: /// Same as CUDADiagIfDeviceCode, with "host" and "device" switched. DeviceDiagBuilder CUDADiagIfHostCode(SourceLocation Loc, unsigned DiagID); + /// Creates a DeviceDiagBuilder that emits the diagnostic if the current + /// context is "used as device code". + /// + /// - If CurContext is a `declare target` function or it is known that the + /// function is emitted for the device, emits the diagnostics immediately. + /// - If CurContext is a non-`declare target` function and we are compiling + /// for the device, creates a diagnostic which is emitted if and when we + /// realize that the function will be codegen'ed. + /// + /// Example usage: + /// + /// // Variable-length arrays are not allowed in NVPTX device code. + /// if (diagIfOpenMPDeviceCode(Loc, diag::err_vla_unsupported)) + /// return ExprError(); + /// // Otherwise, continue parsing as normal. + DeviceDiagBuilder diagIfOpenMPDeviceCode(SourceLocation Loc, unsigned DiagID); + enum CUDAFunctionTarget { CFT_Device, CFT_Global, diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index b991a89e41b..bda8427b1a1 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2827,7 +2827,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // Set the flag to prevent the implementation from emitting device exception // handling code for those requiring so. - Opts.OpenMPHostCXXExceptions = Opts.Exceptions && Opts.CXXExceptions; if ((Opts.OpenMPIsDevice && T.isNVPTX()) || Opts.OpenCLCPlusPlus) { Opts.Exceptions = 0; Opts.CXXExceptions = 0; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index b675986f56b..4d9a8df26f4 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -14896,6 +14896,9 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, } Func->markUsed(Context); + + if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice) + checkOpenMPDeviceFunction(Loc, Func); } static void diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 5ac248d36b4..b8431ce36ec 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -750,12 +750,13 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, bool IsThrownVarInScope) { // Don't report an error if 'throw' is used in system headers. if (!getLangOpts().CXXExceptions && - !getSourceManager().isInSystemHeader(OpLoc) && - (!getLangOpts().OpenMPIsDevice || - !getLangOpts().OpenMPHostCXXExceptions || - isInOpenMPTargetExecutionDirective() || - isInOpenMPDeclareTargetContext())) - Diag(OpLoc, diag::err_exceptions_disabled) << "throw"; + !getSourceManager().isInSystemHeader(OpLoc)) { + // Delay error emission for the OpenMP device code. + if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice) + diagIfOpenMPDeviceCode(OpLoc, diag::err_exceptions_disabled) << "throw"; + else + Diag(OpLoc, diag::err_exceptions_disabled) << "throw"; + } // Exceptions aren't allowed in CUDA device code. if (getLangOpts().CUDA) diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 6fa98b43764..203de2a57a4 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -1393,6 +1393,56 @@ void Sema::popOpenMPFunctionRegion(const FunctionScopeInfo *OldFSI) { DSAStack->popFunction(OldFSI); } +static bool isOpenMPDeviceDelayedContext(Sema &S) { + assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice && + "Expected OpenMP device compilation."); + return !S.isInOpenMPTargetExecutionDirective() && + !S.isInOpenMPDeclareTargetContext(); +} + +/// Do we know that we will eventually codegen the given function? +static bool isKnownEmitted(Sema &S, FunctionDecl *FD) { + assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice && + "Expected OpenMP device compilation."); + // Templates are emitted when they're instantiated. + if (FD->isDependentContext()) + return false; + + if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration( + FD->getCanonicalDecl())) + return true; + + // Otherwise, the function is known-emitted if it's in our set of + // known-emitted functions. + return S.DeviceKnownEmittedFns.count(FD) > 0; +} + +Sema::DeviceDiagBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc, + unsigned DiagID) { + assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice && + "Expected OpenMP device compilation."); + return DeviceDiagBuilder((isOpenMPDeviceDelayedContext(*this) && + !isKnownEmitted(*this, getCurFunctionDecl())) + ? DeviceDiagBuilder::K_Deferred + : DeviceDiagBuilder::K_Immediate, + Loc, DiagID, getCurFunctionDecl(), *this); +} + +void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) { + assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice && + "Expected OpenMP device compilation."); + assert(Callee && "Callee may not be null."); + FunctionDecl *Caller = getCurFunctionDecl(); + + // If the caller is known-emitted, mark the callee as known-emitted. + // Otherwise, mark the call in our call graph so we can traverse it later. + if (!isOpenMPDeviceDelayedContext(*this) || + (Caller && isKnownEmitted(*this, Caller))) + markKnownEmitted(*this, Caller, Callee, Loc, isKnownEmitted); + else if (Caller) + DeviceCallGraph[Caller].insert({Callee, Loc}); +} + bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index d19383e41a8..e4b43576538 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -3997,12 +3997,13 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, ArrayRef<Stmt *> Handlers) { // Don't report an error if 'try' is used in system headers. if (!getLangOpts().CXXExceptions && - !getSourceManager().isInSystemHeader(TryLoc) && - (!getLangOpts().OpenMPIsDevice || - !getLangOpts().OpenMPHostCXXExceptions || - isInOpenMPTargetExecutionDirective() || - isInOpenMPDeclareTargetContext())) - Diag(TryLoc, diag::err_exceptions_disabled) << "try"; + !getSourceManager().isInSystemHeader(TryLoc)) { + // Delay error emission for the OpenMP device code. + if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice) + diagIfOpenMPDeviceCode(TryLoc, diag::err_exceptions_disabled) << "try"; + else + Diag(TryLoc, diag::err_exceptions_disabled) << "try"; + } // Exceptions aren't allowed in CUDA device code. if (getLangOpts().CUDA) diff --git a/clang/test/OpenMP/nvptx_target_exceptions_messages.cpp b/clang/test/OpenMP/nvptx_target_exceptions_messages.cpp index 15c9522540f..433ba13f73d 100644 --- a/clang/test/OpenMP/nvptx_target_exceptions_messages.cpp +++ b/clang/test/OpenMP/nvptx_target_exceptions_messages.cpp @@ -68,4 +68,17 @@ int baz2() { return 2 + baz3(); } +int baz1() { throw 1; } // expected-error {{cannot use 'throw' with exceptions disabled}} + +int foobar1(); +int foobar2(); + +int (*A)() = &foobar1; +#pragma omp declare target +int (*B)() = &foobar2; +#pragma omp end declare target + +int foobar1() { throw 1; } +int foobar2() { throw 1; } // expected-error {{cannot use 'throw' with exceptions disabled}} + #endif // HEADER |