From: Alexey Bataev Date: Tue, 7 Aug 2018 16:14:36 +0000 (+0000) Subject: [OPENMP] Mark variables captured in declare target region as implicitly X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=159b66c5de09c6394e5c2a193190a749d7c79d02;p=clang [OPENMP] Mark variables captured in declare target region as implicitly declare target. According to OpenMP 5.0, variables captured in lambdas in declare target regions must be considered as implicitly declare target. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@339152 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index b1077c620f..8fe16f8126 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -8662,7 +8662,7 @@ public: /// Check if the specified variable is used in one of the private /// clauses (private, firstprivate, lastprivate, reduction etc.) in OpenMP /// constructs. - VarDecl *isOpenMPCapturedDecl(ValueDecl *D) const; + VarDecl *isOpenMPCapturedDecl(ValueDecl *D); ExprResult getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK, ExprObjectKind OK, SourceLocation Loc); @@ -8746,8 +8746,9 @@ public: OMPDeclareTargetDeclAttr::MapTypeTy MT, NamedDeclSetType &SameDirectiveDecls); /// Check declaration inside target region. - void checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, - SourceLocation IdLoc = SourceLocation()); + void + checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, + SourceLocation IdLoc = SourceLocation()); /// Return true inside OpenMP declare target region. bool isInOpenMPDeclareTargetContext() const { return IsInOpenMPDeclareTargetContext; diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index 4d9f495c16..168504ccaf 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -8106,7 +8106,12 @@ bool CGOpenMPRuntime::emitTargetGlobalVariable(GlobalDecl GD) { // Do not to emit variable if it is not marked as declare target. llvm::Optional Res = isDeclareTargetDeclaration(cast(GD.getDecl())); - return !Res || *Res == OMPDeclareTargetDeclAttr::MT_Link; + if (!Res || *Res == OMPDeclareTargetDeclAttr::MT_Link) { + if (CGM.getContext().DeclMustBeEmitted(GD.getDecl())) + DeferredGlobalVariables.insert(cast(GD.getDecl())); + return true; + } + return false; } void CGOpenMPRuntime::registerTargetGlobalVariable(const VarDecl *VD, @@ -8163,6 +8168,18 @@ bool CGOpenMPRuntime::emitTargetGlobal(GlobalDecl GD) { return emitTargetGlobalVariable(GD); } +void CGOpenMPRuntime::emitDeferredTargetDecls() const { + for (const VarDecl *VD : DeferredGlobalVariables) { + llvm::Optional Res = + isDeclareTargetDeclaration(VD); + if (Res) { + assert(*Res != OMPDeclareTargetDeclAttr::MT_Link && + "Implicit declare target variables must be only to()."); + CGM.EmitGlobal(VD); + } + } +} + CGOpenMPRuntime::DisableAutoDeclareTargetRAII::DisableAutoDeclareTargetRAII( CodeGenModule &CGM) : CGM(CGM) { diff --git a/lib/CodeGen/CGOpenMPRuntime.h b/lib/CodeGen/CGOpenMPRuntime.h index 01ff0c20fd..ed2b56b544 100644 --- a/lib/CodeGen/CGOpenMPRuntime.h +++ b/lib/CodeGen/CGOpenMPRuntime.h @@ -602,6 +602,10 @@ private: bool ShouldMarkAsGlobal = true; llvm::SmallDenseSet AlreadyEmittedTargetFunctions; + /// List of variables that can become declare target implicitly and, thus, + /// must be emitted. + llvm::SmallDenseSet DeferredGlobalVariables; + /// Creates and registers offloading binary descriptor for the current /// compilation unit. The function that does the registration is returned. llvm::Function *createOffloadingBinaryDescriptorRegistration(); @@ -1509,6 +1513,8 @@ public: /// true, if it was marked already, and false, otherwise. bool markAsGlobalTarget(GlobalDecl GD); + /// Emit deferred declare target variables marked for deferred emission. + void emitDeferredTargetDecls() const; }; /// Class supports emissionof SIMD-only code. diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 8c5e0df096..dedd57efbd 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1747,6 +1747,10 @@ void CodeGenModule::EmitModuleLinkOptions() { } void CodeGenModule::EmitDeferred() { + // Emit deferred declare target declarations. + if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd) + getOpenMPRuntime().emitDeferredTargetDecls(); + // Emit code for any potentially referenced deferred decls. Since a // previously unused static decl may become used during the generation of code // for a static function, iterate until no changes are made. diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index e1a4c420d4..0b1c330820 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -1417,7 +1417,7 @@ bool Sema::isInOpenMPTargetExecutionDirective() const { false); } -VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D) const { +VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); D = getCanonicalDecl(D); @@ -1425,13 +1425,22 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D) const { // 'target' we return true so that this global is also mapped to the device. // auto *VD = dyn_cast(D); - if (VD && !VD->hasLocalStorage() && isInOpenMPTargetExecutionDirective()) { - // If the declaration is enclosed in a 'declare target' directive, - // then it should not be captured. - // - if (isDeclareTargetDeclaration(VD)) + if (VD && !VD->hasLocalStorage()) { + if (isInOpenMPDeclareTargetContext() && + (getCurCapturedRegion() || getCurBlock() || getCurLambda())) { + // Try to mark variable as declare target if it is used in capturing + // regions. + if (!isDeclareTargetDeclaration(VD)) + checkDeclIsAllowedInOpenMPTarget(nullptr, VD); return nullptr; - return VD; + } else if (isInOpenMPTargetExecutionDirective()) { + // If the declaration is enclosed in a 'declare target' directive, + // then it should not be captured. + // + if (isDeclareTargetDeclaration(VD)) + return nullptr; + return VD; + } } if (DSAStack->getCurrentDirective() != OMPD_unknown && diff --git a/test/OpenMP/declare_target_ast_print.cpp b/test/OpenMP/declare_target_ast_print.cpp index bd1acc28dc..ae6c296310 100644 --- a/test/OpenMP/declare_target_ast_print.cpp +++ b/test/OpenMP/declare_target_ast_print.cpp @@ -10,6 +10,25 @@ #ifndef HEADER #define HEADER +int out_decl_target = 0; +// CHECK: #pragma omp declare target{{$}} +// CHECK: int out_decl_target = 0; +// CHECK: #pragma omp end declare target{{$}} +// CHECK: #pragma omp declare target{{$}} +// CHECK: void lambda() +// CHECK: #pragma omp end declare target{{$}} + +#pragma omp declare target +void lambda () { +#ifdef __cpp_lambdas + (void)[&] { ++out_decl_target; }; +#else + #pragma clang __debug captured + (void)out_decl_target; +#endif +}; +#pragma omp end declare target + #pragma omp declare target // CHECK: #pragma omp declare target{{$}} void foo() {} diff --git a/test/OpenMP/declare_target_codegen.cpp b/test/OpenMP/declare_target_codegen.cpp index 96bdc874ec..fbeb6fb47f 100644 --- a/test/OpenMP/declare_target_codegen.cpp +++ b/test/OpenMP/declare_target_codegen.cpp @@ -20,17 +20,32 @@ // CHECK-DAG: @globals = global %struct.S zeroinitializer, // CHECK-DAG: [[STAT:@.+stat]] = internal global %struct.S zeroinitializer, // CHECK-DAG: [[STAT_REF:@.+]] = internal constant %struct.S* [[STAT]] -// CHECK-DAG: @llvm.used = appending global [2 x i8*] [i8* bitcast (void ()* @__omp_offloading__{{.+}}_globals_l[[@LINE+42]]_ctor to i8*), i8* bitcast (void ()* @__omp_offloading__{{.+}}_stat_l[[@LINE+43]]_ctor to i8*)], +// CHECK-DAG: @out_decl_target = global i32 0, +// CHECK-DAG: @llvm.used = appending global [2 x i8*] [i8* bitcast (void ()* @__omp_offloading__{{.+}}_globals_l[[@LINE+56]]_ctor to i8*), i8* bitcast (void ()* @__omp_offloading__{{.+}}_stat_l[[@LINE+57]]_ctor to i8*)], // CHECK-DAG: @llvm.compiler.used = appending global [1 x i8*] [i8* bitcast (%struct.S** [[STAT_REF]] to i8*)], // CHECK-DAG: define {{.*}}i32 @{{.*}}{{foo|bar|baz2|baz3|FA|f_method}}{{.*}}() // CHECK-DAG: define {{.*}}void @{{.*}}TemplateClass{{.*}}(%class.TemplateClass* %{{.*}}) // CHECK-DAG: define {{.*}}i32 @{{.*}}TemplateClass{{.*}}f_method{{.*}}(%class.TemplateClass* %{{.*}}) -// CHECK-DAG: define {{.*}}void @__omp_offloading__{{.*}}_globals_l[[@LINE+36]]_ctor() +// CHECK-DAG: define {{.*}}void @__omp_offloading__{{.*}}_globals_l[[@LINE+50]]_ctor() #ifndef HEADER #define HEADER +int out_decl_target = 0; +#pragma omp declare target +void lambda () { +#ifdef __cpp_lambdas + (void)[&] { (void)out_decl_target; }; +#else +#pragma clang __debug captured + { + (void)out_decl_target; + } +#endif +}; +#pragma omp end declare target + template class TemplateClass { T a;