diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -421,4 +421,13 @@ "options %0 and %1 are set to different values">; def err_opencl_feature_requires : Error< "feature %0 requires support of %1 feature">; + +def warn_throw_not_valid_on_target : Warning< + "target '%0' does not support exception handling;" + " 'throw' is assumed to be never reached">, + InGroup; +def warn_try_not_valid_on_target : Warning< + "target '%0' does not support exception handling;" + " 'catch' block is ignored">, + InGroup; } diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1279,9 +1279,10 @@ def OpenMPPre51Compat : DiagGroup<"pre-openmp-51-compat">; def OpenMP51Ext : DiagGroup<"openmp-51-extensions">; def OpenMPExtensions : DiagGroup<"openmp-extensions">; +def OpenMPTargetException : DiagGroup<"openmp-target-exception">; def OpenMP : DiagGroup<"openmp", [ SourceUsesOpenMP, OpenMPClauses, OpenMPLoopForm, OpenMPTarget, - OpenMPMapping, OpenMP51Ext, OpenMPExtensions + OpenMPMapping, OpenMP51Ext, OpenMPExtensions, OpenMPTargetException ]>; // Backend warnings. diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -440,6 +440,17 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E, bool KeepInsertionPoint) { + // If the exception is being emitted in an OpenMP target region, + // and the target is a GPU, we do not support exception handling. + // Therefore, we emit a trap which will abort the program, and + // prompt a warning indicating that a trap will be emitted. + const llvm::Triple &T = Target.getTriple(); + if (CGM.getLangOpts().OpenMPIsTargetDevice && (T.isNVPTX() || T.isAMDGCN())) { + CGM.getDiags().Report(E->getExprLoc(), diag::warn_throw_not_valid_on_target) + << T.str(); + EmitTrapCall(llvm::Intrinsic::trap); + return; + } if (const Expr *SubExpr = E->getSubExpr()) { QualType ThrowType = SubExpr->getType(); if (ThrowType->isObjCObjectPointerType()) { @@ -609,9 +620,20 @@ } void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { - EnterCXXTryStmt(S); + const llvm::Triple &T = Target.getTriple(); + // If we encounter a try statement on in an OpenMP target region offloaded to + // a GPU, we treat it as a basic block. + const bool IsTargetDevice = + (CGM.getLangOpts().OpenMPIsTargetDevice && (T.isNVPTX() || T.isAMDGCN())); + if (IsTargetDevice) { + CGM.getDiags().Report(S.getTryLoc(), diag::warn_try_not_valid_on_target) + << T.str(); + } + if (!IsTargetDevice) + EnterCXXTryStmt(S); EmitStmt(S.getTryBlock()); - ExitCXXTryStmt(S); + if (!IsTargetDevice) + ExitCXXTryStmt(S); } void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3820,12 +3820,15 @@ } // Set the flag to prevent the implementation from emitting device exception - // handling code for those requiring so. + // handling code for those requiring so. However, if the user explicitly + // enabled exception handling on the device, we will allow exceptions during + // Sema and handle the exceptions differently in CodeGen. if ((Opts.OpenMPIsTargetDevice && (T.isNVPTX() || T.isAMDGCN())) || Opts.OpenCLCPlusPlus) { - - Opts.Exceptions = 0; - Opts.CXXExceptions = 0; + Opts.Exceptions = Args.hasFlag(options::OPT_fexceptions, + options::OPT_fno_exceptions, false); + Opts.CXXExceptions = Args.hasFlag(options::OPT_fcxx_exceptions, + options::OPT_fno_cxx_exceptions, false); } if (Opts.OpenMPIsTargetDevice && T.isNVPTX()) { Opts.OpenMPCUDANumSMs = diff --git a/clang/test/OpenMP/amdgpu_exceptions.cpp b/clang/test/OpenMP/amdgpu_exceptions.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/amdgpu_exceptions.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -fopenmp -triple amdgcn-amd-amdhsa -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -S -verify=with -Wopenmp-target-exception +// RUN: %clang_cc1 -fopenmp -triple amdgcn-amd-amdhsa -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -S -verify=without -Wno-openmp-target-exception +// RUN: %clang_cc1 -fopenmp -triple amdgcn-amd-amdhsa -fopenmp-is-target-device %s -emit-llvm -S -verify=noexceptions + +// noexceptions-error@11 {{cannot use 'try' with exceptions disabled}} +// noexceptions-error@12 {{cannot use 'throw' with exceptions disabled}} + +#pragma omp declare target +int foo(void) { + int error = -1; + try { // with-warning {{target 'amdgcn-amd-amdhsa' does not support exception handling; 'catch' block is ignored}} + throw 404; // with-warning {{target 'amdgcn-amd-amdhsa' does not support exception handling; 'throw' is assumed to be never reached}} + } + catch (int e){ + error = e; + } + return error; +} +#pragma omp end declare target +// without-no-diagnostics diff --git a/clang/test/OpenMP/amdgpu_throw.cpp b/clang/test/OpenMP/amdgpu_throw.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/amdgpu_throw.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -fopenmp -triple amdgcn-amd-amdhsa -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -S -verify=with -Wopenmp-target-exception +// RUN: %clang_cc1 -fopenmp -triple amdgcn-amd-amdhsa -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -S -verify=without -Wno-openmp-target-exception +// RUN: %clang_cc1 -fopenmp -triple amdgcn-amd-amdhsa -fopenmp-is-target-device %s -emit-llvm -S -verify=noexceptions + +// noexceptions-error@9 {{cannot use 'throw' with exceptions disabled}} + +#pragma omp declare target +void foo(void) { + throw 404; // with-warning {{target 'amdgcn-amd-amdhsa' does not support exception handling; 'throw' is assumed to be never reached}} +} +#pragma omp end declare target +// without-no-diagnostics diff --git a/clang/test/OpenMP/amdgpu_try_catch.cpp b/clang/test/OpenMP/amdgpu_try_catch.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/amdgpu_try_catch.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -fopenmp -triple amdgcn-amd-amdhsa -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -S -verify=with -Wopenmp-target-exception +// RUN: %clang_cc1 -fopenmp -triple amdgcn-amd-amdhsa -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -S -verify=without -Wno-openmp-target-exception +// RUN: %clang_cc1 -fopenmp -triple amdgcn-amd-amdhsa -fopenmp-is-target-device %s -emit-llvm -S -verify=noexceptions + +// noexceptions-error@10 {{cannot use 'try' with exceptions disabled}} + +#pragma omp declare target +int foo(void) { + int error = -1; + try { // with-warning {{target 'amdgcn-amd-amdhsa' does not support exception handling; 'catch' block is ignored}} + error = 1; + } + catch (int e){ + error = e; + } + return error; +} +#pragma omp end declare target +// without-no-diagnostics diff --git a/clang/test/OpenMP/nvptx_exceptions.cpp b/clang/test/OpenMP/nvptx_exceptions.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/nvptx_exceptions.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -S -verify=with -Wopenmp-target-exception +// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -S -verify=without -Wno-openmp-target-exception +// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device %s -emit-llvm -S -verify=noexceptions + +// noexceptions-error@11 {{cannot use 'try' with exceptions disabled}} +// noexceptions-error@12 {{cannot use 'throw' with exceptions disabled}} + +#pragma omp declare target +int foo(void) { + int error = -1; + try { // with-warning {{target 'nvptx64' does not support exception handling; 'catch' block is ignored}} + throw 404; // with-warning {{target 'nvptx64' does not support exception handling; 'throw' is assumed to be never reached}} + } + catch (int e){ + error = e; + } + return error; +} +#pragma omp end declare target +// without-no-diagnostics diff --git a/clang/test/OpenMP/nvptx_throw.cpp b/clang/test/OpenMP/nvptx_throw.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/nvptx_throw.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -S -verify=with -Wopenmp-target-exception +// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -S -verify=without -Wno-openmp-target-exception +// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device %s -emit-llvm -S -verify=noexceptions + +// noexceptions-error@9 {{cannot use 'throw' with exceptions disabled}} + +#pragma omp declare target +void foo(void) { + throw 404; // with-warning {{target 'nvptx64' does not support exception handling; 'throw' is assumed to be never reached}} +} +#pragma omp end declare target +// without-no-diagnostics diff --git a/clang/test/OpenMP/nvptx_try_catch.cpp b/clang/test/OpenMP/nvptx_try_catch.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/nvptx_try_catch.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -S -verify=with -Wopenmp-target-exception +// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -S -verify=without -Wno-openmp-target-exception +// RUN: %clang_cc1 -fopenmp -triple nvptx64 -fopenmp-is-target-device %s -emit-llvm -S -verify=noexceptions + +// noexceptions-error@10 {{cannot use 'try' with exceptions disabled}} + +#pragma omp declare target +int foo(void) { + int error = -1; + try { // with-warning {{target 'nvptx64' does not support exception handling; 'catch' block is ignored}} + error = 1; + } + catch (int e){ + error = e; + } + return error; +} +#pragma omp end declare target +// without-no-diagnostics diff --git a/clang/test/OpenMP/x86_target_exceptions.cpp b/clang/test/OpenMP/x86_target_exceptions.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/x86_target_exceptions.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -fopenmp -triple x86_64-pc-linux-gnu -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -S -verify -Wopenmp-target-exception +#pragma omp declare target +int foo(void) { + int error = -1; + try { + throw 404; + } + catch (int e){ + error = e; + } + return error; +} +#pragma omp end declare target +// expected-no-diagnostics diff --git a/clang/test/OpenMP/x86_target_throw.cpp b/clang/test/OpenMP/x86_target_throw.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/x86_target_throw.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -fopenmp -triple x86_64-pc-linux-gnu -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -S -verify -Wopenmp-target-exception +#pragma omp declare target +void foo(void) { + throw 404; +} +#pragma omp end declare target +// expected-no-diagnostics diff --git a/clang/test/OpenMP/x86_target_try_catch.cpp b/clang/test/OpenMP/x86_target_try_catch.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/x86_target_try_catch.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -fopenmp -triple x86_64-pc-linux-gnu -fopenmp-is-target-device -fcxx-exceptions -fexceptions %s -emit-llvm -S -verify -Wopenmp-target-exception +#pragma omp declare target +int foo(void) { + int error = -1; + try { + error = 1; + } + catch (int e){ + error = e; + } + return error; +} +#pragma omp end declare target +// expected-no-diagnostics