]> granicus.if.org Git - clang/commitdiff
[OPENMP] Mark variables captured in declare target region as implicitly
authorAlexey Bataev <a.bataev@hotmail.com>
Tue, 7 Aug 2018 16:14:36 +0000 (16:14 +0000)
committerAlexey Bataev <a.bataev@hotmail.com>
Tue, 7 Aug 2018 16:14:36 +0000 (16:14 +0000)
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

include/clang/Sema/Sema.h
lib/CodeGen/CGOpenMPRuntime.cpp
lib/CodeGen/CGOpenMPRuntime.h
lib/CodeGen/CodeGenModule.cpp
lib/Sema/SemaOpenMP.cpp
test/OpenMP/declare_target_ast_print.cpp
test/OpenMP/declare_target_codegen.cpp

index b1077c620f8aa1a682a1d2490a81c1e1ad0724f5..8fe16f81268931a9760f82a0cb95c8d70912e008 100644 (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;
index 4d9f495c16eb20e09f0fd359ad37f0cb4b2536b5..168504ccaf79d684de7bdd01347fbd1d1a85d5fa 100644 (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) {
index 01ff0c20fd6680afcf2bf3548e3605121d593621..ed2b56b5448da531c91181966e4010ab46ffe523 100644 (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.
index 8c5e0df0969b86829f8c5d7b46521d54ccd862d3..dedd57efbd9706bd9ba0188679eba5b85f519a50 100644 (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.
index e1a4c420d4024625e83e728e66b92454600577f4..0b1c33082080d4b3065e5842aa64f909ba4468e7 100644 (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 &&
index bd1acc28dc6c205132778d92c2740d39f0875c0f..ae6c296310670ff27bc5dde66e6891443385d191 100644 (file)
 #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() {}
index 96bdc874ece262484662f71a1d8bb342e276f66f..fbeb6fb47fc0a71858d57b8851a152081cccbf3e 100644 (file)
 // 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;