[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.

llvm-svn: 339152
This commit is contained in:
Alexey Bataev 2018-08-07 16:14:36 +00:00
parent ab2cbad6fe
commit bf8fe71b91
7 changed files with 84 additions and 13 deletions

View File

@ -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;

View File

@ -8106,7 +8106,12 @@ bool CGOpenMPRuntime::emitTargetGlobalVariable(GlobalDecl GD) {
// Do not to emit variable if it is not marked as declare target.
llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
isDeclareTargetDeclaration(cast<VarDecl>(GD.getDecl()));
return !Res || *Res == OMPDeclareTargetDeclAttr::MT_Link;
if (!Res || *Res == OMPDeclareTargetDeclAttr::MT_Link) {
if (CGM.getContext().DeclMustBeEmitted(GD.getDecl()))
DeferredGlobalVariables.insert(cast<VarDecl>(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<OMPDeclareTargetDeclAttr::MapTypeTy> 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) {

View File

@ -602,6 +602,10 @@ private:
bool ShouldMarkAsGlobal = true;
llvm::SmallDenseSet<const FunctionDecl *> AlreadyEmittedTargetFunctions;
/// List of variables that can become declare target implicitly and, thus,
/// must be emitted.
llvm::SmallDenseSet<const VarDecl *> 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.

View File

@ -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.

View File

@ -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<VarDecl>(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 &&

View File

@ -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() {}

View File

@ -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 <typename T>
class TemplateClass {
T a;