r265530 - [OPENMP] Parsing and Sema support for 'omp declare target' directive

Dmitry Polukhin via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 6 04:39:01 PDT 2016


Author: dpolukhin
Date: Wed Apr  6 06:38:59 2016
New Revision: 265530

URL: http://llvm.org/viewvc/llvm-project?rev=265530&view=rev
Log:
[OPENMP] Parsing and Sema support for 'omp declare target' directive

Add parsing, sema analysis for 'declare target' construct for OpenMP 4.0
(4.5 support will be added in separate patch).

The declare target directive specifies that variables, functions (C, C++
and Fortran), and subroutines (Fortran) are mapped to a device. The declare
target directive is a declarative directive. In Clang declare target is
implemented as implicit attribute for the declaration.

The syntax of the declare target directive is as follows:

 #pragma omp declare target
 declarations-definition-seq
 #pragma omp end declare target

Based on patch from Michael Wong http://reviews.llvm.org/D15321

Added:
    cfe/trunk/test/OpenMP/declare_target_ast_print.cpp   (with props)
    cfe/trunk/test/OpenMP/declare_target_messages.cpp   (with props)
Modified:
    cfe/trunk/include/clang/AST/ASTMutationListener.h
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Basic/AttrDocs.td
    cfe/trunk/include/clang/Basic/DiagnosticGroups.td
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/OpenMPKinds.def
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/include/clang/Serialization/ASTWriter.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/DeclPrinter.cpp
    cfe/trunk/lib/Basic/OpenMPKinds.cpp
    cfe/trunk/lib/Frontend/MultiplexConsumer.cpp
    cfe/trunk/lib/Parse/ParseOpenMP.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaOpenMP.cpp
    cfe/trunk/lib/Serialization/ASTCommon.h
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/lib/Serialization/ASTWriterDecl.cpp

Modified: cfe/trunk/include/clang/AST/ASTMutationListener.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTMutationListener.h?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTMutationListener.h (original)
+++ cfe/trunk/include/clang/AST/ASTMutationListener.h Wed Apr  6 06:38:59 2016
@@ -107,6 +107,12 @@ public:
   /// \param D the declaration marked OpenMP threadprivate.
   virtual void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) {}
 
+  /// \brief A declaration is marked as OpenMP declaretarget which was not
+  /// previously marked as declaretarget.
+  ///
+  /// \param D the declaration marked OpenMP declaretarget.
+  virtual void DeclarationMarkedOpenMPDeclareTarget(const Decl *D) {}
+
   /// \brief A definition has been made visible by being redefined locally.
   ///
   /// \param D The definition that was previously not visible.

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Wed Apr  6 06:38:59 2016
@@ -2276,6 +2276,15 @@ def OMPDeclareSimdDecl : Attr {
   }];
 }
 
+def OMPDeclareTargetDecl : Attr {
+  let Spellings = [Pragma<"omp", "declare target">];
+  let SemaHandler = 0;
+  let Documentation = [OMPDeclareTargetDocs];
+  let AdditionalMembers = [{
+    void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const {}
+  }];
+}
+
 def InternalLinkage : InheritableAttr {
   let Spellings = [GNU<"internal_linkage">, CXX11<"clang", "internal_linkage">];
   let Subjects = SubjectList<[Var, Function, CXXRecord]>;

Modified: cfe/trunk/include/clang/Basic/AttrDocs.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrDocs.td?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/AttrDocs.td (original)
+++ cfe/trunk/include/clang/Basic/AttrDocs.td Wed Apr  6 06:38:59 2016
@@ -1941,6 +1941,23 @@ where clause is one of the following:
   }];
 }
 
+def OMPDeclareTargetDocs : Documentation {
+  let Category = DocCatFunction;
+  let Heading = "#pragma omp declare target";
+  let Content = [{
+The `declare target` directive specifies that variables and functions are mapped
+to a device for OpenMP offload mechanism.
+
+The syntax of the declare target directive is as follows:
+
+  .. code-block:: c
+
+  #pragma omp declare target new-line
+  declarations-definition-seq
+  #pragma omp end declare target new-line
+  }];
+}
+
 def NotTailCalledDocs : Documentation {
   let Category = DocCatFunction;
   let Content = [{

Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Wed Apr  6 06:38:59 2016
@@ -819,6 +819,7 @@ def ASM : DiagGroup<"asm", [
 def SourceUsesOpenMP : DiagGroup<"source-uses-openmp">;
 def OpenMPClauses : DiagGroup<"openmp-clauses">;
 def OpenMPLoopForm : DiagGroup<"openmp-loop-form">;
+def OpenMPTarget : DiagGroup<"openmp-target">;
 
 // Backend warnings.
 def BackendInlineAsm : DiagGroup<"inline-asm">;

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Wed Apr  6 06:38:59 2016
@@ -963,6 +963,8 @@ def err_omp_map_type_missing : Error<
   "missing map type">;
 def err_omp_declare_simd_inbranch_notinbranch : Error<
   "unexpected '%0' clause, '%1' is specified already">;
+def err_expected_end_declare_target : Error<
+  "expected '#pragma omp end declare target'">;
 
 // Pragma loop support.
 def err_pragma_loop_missing_argument : Error<

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Apr  6 06:38:59 2016
@@ -7828,6 +7828,8 @@ def err_omp_global_var_arg : Error<
   "arguments of '#pragma omp %0' must have %select{global storage|static storage duration}1">;
 def err_omp_ref_type_arg : Error<
   "arguments of '#pragma omp %0' cannot be of reference type %1">;
+def err_omp_region_not_file_context : Error<
+  "directive must be at file or namespace scope">;
 def err_omp_var_scope : Error<
   "'#pragma omp %0' must appear in the scope of the %q1 variable declaration">;
 def err_omp_var_used : Error<
@@ -7903,6 +7905,8 @@ def err_omp_negative_expression_in_claus
 def err_omp_not_integral : Error<
   "expression must have integral or unscoped enumeration "
   "type, not %0">;
+def err_omp_threadprivate_in_target : Error<
+  "threadprivate variables cannot be used in target constructs">;
 def err_omp_incomplete_type : Error<
   "expression has incomplete class type %0">;
 def err_omp_explicit_conversion : Error<
@@ -7929,6 +7933,11 @@ def warn_omp_linear_step_zero : Warning<
 def warn_omp_alignment_not_power_of_two : Warning<
   "aligned clause will be ignored because the requested alignment is not a power of 2">,
   InGroup<OpenMPClauses>;
+def err_omp_enclosed_declare_target : Error<
+  "declare target region may not be enclosed within another declare target region">;
+def warn_omp_not_in_target_context : Warning<
+  "declaration is not declared in any declare target region">,
+  InGroup<OpenMPTarget>;
 def err_omp_aligned_expected_array_or_ptr : Error<
   "argument of aligned clause should be array"
   "%select{ or pointer|, pointer, reference to array or reference to pointer}1"

Modified: cfe/trunk/include/clang/Basic/OpenMPKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/OpenMPKinds.def?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/OpenMPKinds.def (original)
+++ cfe/trunk/include/clang/Basic/OpenMPKinds.def Wed Apr  6 06:38:59 2016
@@ -160,6 +160,8 @@ OPENMP_DIRECTIVE_EXT(declare_simd, "decl
 OPENMP_DIRECTIVE(taskloop)
 OPENMP_DIRECTIVE_EXT(taskloop_simd, "taskloop simd")
 OPENMP_DIRECTIVE(distribute)
+OPENMP_DIRECTIVE_EXT(declare_target, "declare target")
+OPENMP_DIRECTIVE_EXT(end_declare_target, "end declare target")
 
 // OpenMP clauses.
 OPENMP_CLAUSE(if, OMPIfClause)

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Apr  6 06:38:59 2016
@@ -7828,6 +7828,8 @@ public:
   //
 private:
   void *VarDataSharingAttributesStack;
+  /// Set to true inside '#pragma omp declare target' region.
+  bool IsInOpenMPDeclareTargetContext = false;
   /// \brief Initialization of data-sharing attributes stack.
   void InitDataSharingAttributesStack();
   void DestroyDataSharingAttributesStack();
@@ -7913,6 +7915,17 @@ public:
   DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveEnd(
       Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid);
 
+  /// Called on the start of target region i.e. '#pragma omp declare target'.
+  bool ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc);
+  /// Called at the end of target region i.e. '#pragme omp end declare target'.
+  void ActOnFinishOpenMPDeclareTargetDirective();
+  /// Check declaration inside target region.
+  void checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D);
+  /// Return true inside OpenMP target region.
+  bool isInOpenMPDeclareTargetContext() const {
+    return IsInOpenMPDeclareTargetContext;
+  }
+
   /// \brief Initialization of captured region for OpenMP region.
   void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope);
   /// \brief End of OpenMP region.

Modified: cfe/trunk/include/clang/Serialization/ASTWriter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTWriter.h?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTWriter.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTWriter.h Wed Apr  6 06:38:59 2016
@@ -861,6 +861,7 @@ public:
                                     const ObjCInterfaceDecl *IFD) override;
   void DeclarationMarkedUsed(const Decl *D) override;
   void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
+  void DeclarationMarkedOpenMPDeclareTarget(const Decl *D) override;
   void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override;
   void AddedAttributeToRecord(const Attr *Attr,
                               const RecordDecl *Record) override;

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Wed Apr  6 06:38:59 2016
@@ -8528,6 +8528,9 @@ bool ASTContext::DeclMustBeEmitted(const
       return false;
   } else if (isa<PragmaCommentDecl>(D))
     return true;
+  else if (isa<OMPThreadPrivateDecl>(D) ||
+           D->hasAttr<OMPDeclareTargetDeclAttr>())
+    return true;
   else if (isa<PragmaDetectMismatchDecl>(D))
     return true;
   else if (isa<OMPThreadPrivateDecl>(D))

Modified: cfe/trunk/lib/AST/DeclPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclPrinter.cpp?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclPrinter.cpp (original)
+++ cfe/trunk/lib/AST/DeclPrinter.cpp Wed Apr  6 06:38:59 2016
@@ -358,6 +358,11 @@ void DeclPrinter::VisitDeclContext(DeclC
     if (Terminator)
       Out << Terminator;
     Out << "\n";
+
+    // Declare target attribute is special one, natural spelling for the pragma
+    // assumes "ending" construct so print it here.
+    if (D->hasAttr<OMPDeclareTargetDeclAttr>())
+      Out << "#pragma omp end declare target\n";
   }
 
   if (!Decls.empty())

Modified: cfe/trunk/lib/Basic/OpenMPKinds.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/OpenMPKinds.cpp?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/OpenMPKinds.cpp (original)
+++ cfe/trunk/lib/Basic/OpenMPKinds.cpp Wed Apr  6 06:38:59 2016
@@ -547,6 +547,8 @@ bool clang::isAllowedClauseForDirective(
       break;
     }
     break;
+  case OMPD_declare_target:
+  case OMPD_end_declare_target:
   case OMPD_unknown:
   case OMPD_threadprivate:
   case OMPD_section:

Modified: cfe/trunk/lib/Frontend/MultiplexConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/MultiplexConsumer.cpp?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/MultiplexConsumer.cpp (original)
+++ cfe/trunk/lib/Frontend/MultiplexConsumer.cpp Wed Apr  6 06:38:59 2016
@@ -125,6 +125,7 @@ public:
   void FunctionDefinitionInstantiated(const FunctionDecl *D) override;
   void DeclarationMarkedUsed(const Decl *D) override;
   void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
+  void DeclarationMarkedOpenMPDeclareTarget(const Decl *D) override;
   void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override;
   void AddedAttributeToRecord(const Attr *Attr, 
                               const RecordDecl *Record) override;
@@ -219,6 +220,11 @@ void MultiplexASTMutationListener::Decla
   for (size_t i = 0, e = Listeners.size(); i != e; ++i)
     Listeners[i]->DeclarationMarkedOpenMPThreadPrivate(D);
 }
+void MultiplexASTMutationListener::DeclarationMarkedOpenMPDeclareTarget(
+    const Decl *D) {
+  for (auto *L : Listeners)
+    L->DeclarationMarkedOpenMPDeclareTarget(D);
+}
 void MultiplexASTMutationListener::RedefinedHiddenDefinition(const NamedDecl *D,
                                                              Module *M) {
   for (auto *L : Listeners)

Modified: cfe/trunk/lib/Parse/ParseOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseOpenMP.cpp?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseOpenMP.cpp (original)
+++ cfe/trunk/lib/Parse/ParseOpenMP.cpp Wed Apr  6 06:38:59 2016
@@ -31,6 +31,8 @@ enum OpenMPDirectiveKindEx {
   OMPD_cancellation = OMPD_unknown + 1,
   OMPD_data,
   OMPD_declare,
+  OMPD_end,
+  OMPD_end_declare,
   OMPD_enter,
   OMPD_exit,
   OMPD_point,
@@ -51,6 +53,7 @@ static unsigned getOpenMPDirectiveKindEx
       .Case("cancellation", OMPD_cancellation)
       .Case("data", OMPD_data)
       .Case("declare", OMPD_declare)
+      .Case("end", OMPD_end)
       .Case("enter", OMPD_enter)
       .Case("exit", OMPD_exit)
       .Case("point", OMPD_point)
@@ -66,6 +69,9 @@ static OpenMPDirectiveKind ParseOpenMPDi
     { OMPD_cancellation, OMPD_point, OMPD_cancellation_point },
     { OMPD_declare, OMPD_reduction, OMPD_declare_reduction },
     { OMPD_declare, OMPD_simd, OMPD_declare_simd },
+    { OMPD_declare, OMPD_target, OMPD_declare_target },
+    { OMPD_end, OMPD_declare, OMPD_end_declare },
+    { OMPD_end_declare, OMPD_target, OMPD_end_declare_target },
     { OMPD_target, OMPD_data, OMPD_target_data },
     { OMPD_target, OMPD_enter, OMPD_target_enter },
     { OMPD_target, OMPD_exit, OMPD_target_exit },
@@ -456,6 +462,53 @@ Parser::DeclGroupPtrTy Parser::ParseOpen
     return Actions.ActOnOpenMPDeclareSimdDirective(Ptr, BS,
                                                    SourceRange(Loc, EndLoc));
   }
+  case OMPD_declare_target: {
+    SourceLocation DTLoc = ConsumeAnyToken();
+    if (Tok.isNot(tok::annot_pragma_openmp_end)) {
+      Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
+          << getOpenMPDirectiveName(OMPD_declare_target);
+      SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
+    }
+    // Skip the last annot_pragma_openmp_end.
+    ConsumeAnyToken();
+
+    if (!Actions.ActOnStartOpenMPDeclareTargetDirective(DTLoc))
+      return DeclGroupPtrTy();
+
+    DKind = ParseOpenMPDirectiveKind(*this);
+    while (DKind != OMPD_end_declare_target && DKind != OMPD_declare_target &&
+           Tok.isNot(tok::eof) && Tok.isNot(tok::r_brace)) {
+      ParsedAttributesWithRange attrs(AttrFactory);
+      MaybeParseCXX11Attributes(attrs);
+      MaybeParseMicrosoftAttributes(attrs);
+      ParseExternalDeclaration(attrs);
+      if (Tok.isAnnotation() && Tok.is(tok::annot_pragma_openmp)) {
+        TentativeParsingAction TPA(*this);
+        ConsumeToken();
+        DKind = ParseOpenMPDirectiveKind(*this);
+        if (DKind != OMPD_end_declare_target)
+          TPA.Revert();
+        else
+          TPA.Commit();
+      }
+    }
+
+    if (DKind == OMPD_end_declare_target) {
+      ConsumeAnyToken();
+      if (Tok.isNot(tok::annot_pragma_openmp_end)) {
+        Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
+            << getOpenMPDirectiveName(OMPD_end_declare_target);
+        SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
+      }
+      // Skip the last annot_pragma_openmp_end.
+      ConsumeAnyToken();
+    } else {
+      Diag(Tok, diag::err_expected_end_declare_target);
+      Diag(DTLoc, diag::note_matching) << "'#pragma omp declare target'";
+    }
+    Actions.ActOnFinishOpenMPDeclareTargetDirective();
+    return DeclGroupPtrTy();
+  }
   case OMPD_unknown:
     Diag(Tok, diag::err_omp_unknown_directive);
     break;
@@ -491,6 +544,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpen
   case OMPD_taskloop:
   case OMPD_taskloop_simd:
   case OMPD_distribute:
+  case OMPD_end_declare_target:
     Diag(Tok, diag::err_omp_unexpected_directive)
         << getOpenMPDirectiveName(DKind);
     break;
@@ -711,6 +765,8 @@ StmtResult Parser::ParseOpenMPDeclarativ
     break;
   }
   case OMPD_declare_simd:
+  case OMPD_declare_target:
+  case OMPD_end_declare_target:
     Diag(Tok, diag::err_omp_unexpected_directive)
         << getOpenMPDirectiveName(DKind);
     SkipUntil(tok::annot_pragma_openmp_end);

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Apr  6 06:38:59 2016
@@ -5052,6 +5052,9 @@ NamedDecl *Sema::HandleDeclarator(Scope
       CurContext->addHiddenDecl(New);
   }
 
+  if (isInOpenMPDeclareTargetContext())
+    checkDeclIsAllowedInOpenMPTarget(nullptr, New);
+
   return New;
 }
 

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Apr  6 06:38:59 2016
@@ -13814,6 +13814,9 @@ void Sema::MarkVariableReferenced(Source
 
 static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
                                Decl *D, Expr *E, bool MightBeOdrUse) {
+  if (SemaRef.isInOpenMPDeclareTargetContext())
+    SemaRef.checkDeclIsAllowedInOpenMPTarget(E, D);
+
   if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
     DoMarkVarDeclReferenced(SemaRef, Loc, Var, E);
     return;

Modified: cfe/trunk/lib/Sema/SemaOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOpenMP.cpp?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOpenMP.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOpenMP.cpp Wed Apr  6 06:38:59 2016
@@ -644,6 +644,11 @@ DSAStackTy::DSAVarData DSAStackTy::getTo
     return DVar;
   }
 
+  if (Stack.size() == 1) {
+    // Not in OpenMP execution region and top scope was already checked.
+    return DVar;
+  }
+
   // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
   // in a Construct, C/C++, predetermined, p.4]
   //  Static data members are shared.
@@ -1706,6 +1711,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMP
   case OMPD_target_exit_data:
   case OMPD_declare_reduction:
   case OMPD_declare_simd:
+  case OMPD_declare_target:
+  case OMPD_end_declare_target:
     llvm_unreachable("OpenMP Directive is not allowed");
   case OMPD_unknown:
     llvm_unreachable("Unknown OpenMP directive");
@@ -3158,6 +3165,8 @@ StmtResult Sema::ActOnOpenMPExecutableDi
     Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc,
                                          EndLoc, VarsWithInheritedDSA);
     break;
+  case OMPD_declare_target:
+  case OMPD_end_declare_target:
   case OMPD_threadprivate:
   case OMPD_declare_reduction:
   case OMPD_declare_simd:
@@ -10354,3 +10363,141 @@ OMPClause *Sema::ActOnOpenMPDefaultmapCl
   return new (Context)
       OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M);
 }
+
+bool Sema::ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc) {
+  DeclContext *CurLexicalContext = getCurLexicalContext();
+  if (!CurLexicalContext->isFileContext() &&
+      !CurLexicalContext->isExternCContext() &&
+      !CurLexicalContext->isExternCXXContext()) {
+    Diag(Loc, diag::err_omp_region_not_file_context);
+    return false;
+  }
+  if (IsInOpenMPDeclareTargetContext) {
+    Diag(Loc, diag::err_omp_enclosed_declare_target);
+    return false;
+  }
+
+  IsInOpenMPDeclareTargetContext = true;
+  return true;
+}
+
+void Sema::ActOnFinishOpenMPDeclareTargetDirective() {
+  assert(IsInOpenMPDeclareTargetContext &&
+         "Unexpected ActOnFinishOpenMPDeclareTargetDirective");
+
+  IsInOpenMPDeclareTargetContext = false;
+}
+
+static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR,
+                                     Sema &SemaRef, Decl *D) {
+  if (!D)
+    return;
+  Decl *LD = nullptr;
+  if (isa<TagDecl>(D)) {
+    LD = cast<TagDecl>(D)->getDefinition();
+  } else if (isa<VarDecl>(D)) {
+    LD = cast<VarDecl>(D)->getDefinition();
+
+    // If this is an implicit variable that is legal and we do not need to do
+    // anything.
+    if (cast<VarDecl>(D)->isImplicit()) {
+      D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(SemaRef.Context));
+      if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener())
+        ML->DeclarationMarkedOpenMPDeclareTarget(D);
+      return;
+    }
+
+  } else if (isa<FunctionDecl>(D)) {
+    const FunctionDecl *FD = nullptr;
+    if (cast<FunctionDecl>(D)->hasBody(FD))
+      LD = const_cast<FunctionDecl *>(FD);
+
+    // If the definition is associated with the current declaration in the
+    // target region (it can be e.g. a lambda) that is legal and we do not need
+    // to do anything else.
+    if (LD == D) {
+      D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(SemaRef.Context));
+      if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener())
+        ML->DeclarationMarkedOpenMPDeclareTarget(D);
+      return;
+    }
+  }
+  if (!LD)
+    LD = D;
+  if (LD && !LD->hasAttr<OMPDeclareTargetDeclAttr>() &&
+      (isa<VarDecl>(LD) || isa<FunctionDecl>(LD))) {
+    // Outlined declaration is not declared target.
+    if (LD->isOutOfLine()) {
+      SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context);
+      SemaRef.Diag(SL, diag::note_used_here) << SR;
+    } else {
+      DeclContext *DC = LD->getDeclContext();
+      while (DC) {
+        if (isa<FunctionDecl>(DC) &&
+            cast<FunctionDecl>(DC)->hasAttr<OMPDeclareTargetDeclAttr>())
+          break;
+        DC = DC->getParent();
+      }
+      if (DC)
+        return;
+
+      // Is not declared in target context.
+      SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context);
+      SemaRef.Diag(SL, diag::note_used_here) << SR;
+    }
+    // Mark decl as declared target to prevent further diagnostic.
+    D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(SemaRef.Context));
+    if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener())
+      ML->DeclarationMarkedOpenMPDeclareTarget(D);
+  }
+}
+
+static bool checkValueDeclInTarget(SourceLocation SL, SourceRange SR,
+                                   Sema &SemaRef, DSAStackTy *Stack,
+                                   ValueDecl *VD) {
+  if (VD->hasAttr<OMPDeclareTargetDeclAttr>())
+    return true;
+  if (!CheckTypeMappable(SL, SR, SemaRef, Stack, VD->getType()))
+    return false;
+  return true;
+}
+
+void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D) {
+  if (!D || D->isInvalidDecl())
+    return;
+  SourceRange SR = E ? E->getSourceRange() : D->getSourceRange();
+  SourceLocation SL = E ? E->getLocStart() : D->getLocation();
+  // 2.10.6: threadprivate variable cannot appear in a declare target directive.
+  if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+    if (DSAStack->isThreadPrivate(VD)) {
+      Diag(SL, diag::err_omp_threadprivate_in_target);
+      ReportOriginalDSA(*this, DSAStack, VD, DSAStack->getTopDSA(VD, false));
+      return;
+    }
+  }
+  if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
+    // Problem if any with var declared with incomplete type will be reported
+    // as normal, so no need to check it here.
+    if ((E || !VD->getType()->isIncompleteType()) &&
+        !checkValueDeclInTarget(SL, SR, *this, DSAStack, VD)) {
+      // Mark decl as declared target to prevent further diagnostic.
+      if (isa<VarDecl>(VD) || isa<FunctionDecl>(VD)) {
+        VD->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(Context));
+        if (ASTMutationListener *ML = Context.getASTMutationListener())
+          ML->DeclarationMarkedOpenMPDeclareTarget(VD);
+      }
+      return;
+    }
+  }
+  if (!E) {
+    // Checking declaration inside declare target region.
+    if (!D->hasAttr<OMPDeclareTargetDeclAttr>() &&
+        (isa<VarDecl>(D) || isa<FunctionDecl>(D))) {
+      D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(Context));
+      if (ASTMutationListener *ML = Context.getASTMutationListener())
+        ML->DeclarationMarkedOpenMPDeclareTarget(D);
+    }
+    return;
+  }
+  checkDeclInTargetContext(E->getExprLoc(), E->getSourceRange(), *this, D);
+}

Modified: cfe/trunk/lib/Serialization/ASTCommon.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTCommon.h?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTCommon.h (original)
+++ cfe/trunk/lib/Serialization/ASTCommon.h Wed Apr  6 06:38:59 2016
@@ -37,6 +37,7 @@ enum DeclUpdateKind {
   UPD_MANGLING_NUMBER,
   UPD_STATIC_LOCAL_NUMBER,
   UPD_DECL_MARKED_OPENMP_THREADPRIVATE,
+  UPD_DECL_MARKED_OPENMP_DECLARETARGET,
   UPD_DECL_EXPORTED,
   UPD_ADDED_ATTR_TO_RECORD
 };

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Wed Apr  6 06:38:59 2016
@@ -3879,6 +3879,11 @@ void ASTDeclReader::UpdateDecl(Decl *D,
           Reader.Context, ReadSourceRange(Record, Idx)));
       break;
 
+    case UPD_DECL_MARKED_OPENMP_DECLARETARGET:
+      D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(
+          Reader.Context, ReadSourceRange(Record, Idx)));
+      break;
+
     case UPD_DECL_EXPORTED: {
       unsigned SubmoduleID = readSubmoduleID(Record, Idx);
       auto *Exported = cast<NamedDecl>(D);

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Wed Apr  6 06:38:59 2016
@@ -4760,6 +4760,11 @@ void ASTWriter::WriteDeclUpdatesBlocks(R
             D->getAttr<OMPThreadPrivateDeclAttr>()->getRange());
         break;
 
+      case UPD_DECL_MARKED_OPENMP_DECLARETARGET:
+        Record.AddSourceRange(
+            D->getAttr<OMPDeclareTargetDeclAttr>()->getRange());
+        break;
+
       case UPD_DECL_EXPORTED:
         Record.push_back(getSubmoduleID(Update.getModule()));
         break;
@@ -5887,6 +5892,14 @@ void ASTWriter::DeclarationMarkedOpenMPT
   DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_THREADPRIVATE));
 }
 
+void ASTWriter::DeclarationMarkedOpenMPDeclareTarget(const Decl *D) {
+  assert(!WritingAST && "Already writing the AST!");
+  if (!D->isFromASTFile())
+    return;
+
+  DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_DECLARETARGET));
+}
+
 void ASTWriter::RedefinedHiddenDefinition(const NamedDecl *D, Module *M) {
   assert(!WritingAST && "Already writing the AST!");
   assert(D->isHidden() && "expected a hidden declaration");

Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=265530&r1=265529&r2=265530&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Wed Apr  6 06:38:59 2016
@@ -2133,8 +2133,10 @@ static bool isRequiredDecl(const Decl *D
   // An ObjCMethodDecl is never considered as "required" because its
   // implementation container always is.
 
-  // File scoped assembly or obj-c implementation must be seen.
-  if (isa<FileScopeAsmDecl>(D) || isa<ObjCImplDecl>(D))
+  // File scoped assembly or obj-c or OMP declare target implementation must be
+  // seen.
+  if (isa<FileScopeAsmDecl>(D) || isa<ObjCImplDecl>(D) ||
+      D->hasAttr<OMPDeclareTargetDeclAttr>())
     return true;
 
   // ImportDecl is used by codegen to determine the set of imported modules to

Added: cfe/trunk/test/OpenMP/declare_target_ast_print.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/declare_target_ast_print.cpp?rev=265530&view=auto
==============================================================================
--- cfe/trunk/test/OpenMP/declare_target_ast_print.cpp (added)
+++ cfe/trunk/test/OpenMP/declare_target_ast_print.cpp Wed Apr  6 06:38:59 2016
@@ -0,0 +1,93 @@
+// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+#pragma omp declare target
+// CHECK: #pragma omp declare target
+void foo() {}
+// CHECK-NEXT: void foo()
+#pragma omp end declare target
+// CHECK: #pragma omp end declare target
+
+extern "C" {
+#pragma omp declare target
+// CHECK: #pragma omp declare target
+void foo_c() {}
+// CHECK-NEXT: void foo_c()
+#pragma omp end declare target
+// CHECK: #pragma omp end declare target
+}
+
+extern "C++" {
+#pragma omp declare target
+// CHECK: #pragma omp declare target
+void foo_cpp() {}
+// CHECK-NEXT: void foo_cpp()
+#pragma omp end declare target
+// CHECK: #pragma omp end declare target
+}
+
+#pragma omp declare target
+template <class T>
+struct C {
+// CHECK: template <class T = int> struct C
+  T t;
+// CHECK-NEXT: int t;
+  static T ts;
+// CHECK-NEXT: #pragma omp declare target
+// CHECK-NEXT: static int ts;
+// CHECK: #pragma omp end declare target
+
+  C(T t) : t(t) {
+  }
+// CHECK: #pragma omp declare target
+// CHECK-NEXT: C(int t) : t(t) {
+// CHECK-NEXT: }
+// CHECK: #pragma omp end declare target
+
+  T foo() {
+    return t;
+  }
+// CHECK: #pragma omp declare target
+// CHECK-NEXT: int foo() {
+// CHECK-NEXT: return this->t;
+// CHECK-NEXT: }
+// CHECK: #pragma omp end declare target
+};
+
+// CHECK: template <class T> struct C {
+// CHECK: #pragma omp declare target
+// CHECK-NEXT: static T ts;
+// CHECK-NEXT: #pragma omp end declare target
+
+template<class T>
+T C<T>::ts = 1;
+// CHECK: #pragma omp declare target
+// CHECK: T ts = 1;
+// CHECK: #pragma omp end declare target
+
+// CHECK: #pragma omp declare target
+// CHECK: int test1()
+int test1() {
+  C<int> c(1);
+  return c.foo() + c.ts;
+}
+#pragma omp end declare target
+// CHECK: #pragma omp end declare target
+
+int main (int argc, char **argv) {
+  foo();
+  foo_c();
+  foo_cpp();
+  test1();
+  return (0);
+}
+
+// CHECK: #pragma omp declare target
+// CHECK-NEXT: int ts = 1;
+// CHECK-NEXT: #pragma omp end declare target
+#endif

Propchange: cfe/trunk/test/OpenMP/declare_target_ast_print.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/OpenMP/declare_target_ast_print.cpp
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Rev URL"

Propchange: cfe/trunk/test/OpenMP/declare_target_ast_print.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/OpenMP/declare_target_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/declare_target_messages.cpp?rev=265530&view=auto
==============================================================================
--- cfe/trunk/test/OpenMP/declare_target_messages.cpp (added)
+++ cfe/trunk/test/OpenMP/declare_target_messages.cpp Wed Apr  6 06:38:59 2016
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -fnoopenmp-use-tls -ferror-limit 100 -o - %s
+
+#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}}
+
+int a, b; // expected-warning {{declaration is not declared in any declare target region}}
+__thread int t; // expected-note {{defined as threadprivate or thread local}}
+#pragma omp declare target private(a) // expected-warning {{extra tokens at the end of '#pragma omp declare target' are ignored}}
+void f();
+#pragma omp end declare target shared(a) // expected-warning {{extra tokens at the end of '#pragma omp end declare target' are ignored}}
+void c(); // expected-warning {{declaration is not declared in any declare target region}}
+
+extern int b;
+
+struct NonT {
+  int a;
+};
+
+typedef int sint;
+
+#pragma omp declare target // expected-note {{to match this '#pragma omp declare target'}}
+#pragma omp threadprivate(a) // expected-note {{defined as threadprivate or thread local}}
+extern int b;
+int g;
+
+struct T { // expected-note {{mappable type cannot be polymorphic}}
+  int a;
+  virtual int method();
+};
+
+class VC { // expected-note {{mappable type cannot be polymorphic}}
+  T member;
+  NonT member1;
+  public:
+    virtual int method() { T a; return 0; } // expected-error {{type 'T' is not mappable to target}}
+};
+
+struct C {
+  NonT a;
+  sint b;
+  int method();
+  int method1();
+};
+
+int C::method1() {
+  return 0;
+}
+
+void foo() {
+  a = 0; // expected-error {{threadprivate variables cannot be used in target constructs}}
+  b = 0; // expected-note {{used here}}
+  t = 1; // expected-error {{threadprivate variables cannot be used in target constructs}}
+  C object;
+  VC object1; // expected-error {{type 'VC' is not mappable to target}}
+  g = object.method();
+  g += object.method1();
+  g += object1.method();
+  f();
+  c(); // expected-note {{used here}}
+}
+#pragma omp declare target // expected-error {{expected '#pragma omp end declare target'}}
+void foo1() {}
+#pragma omp end declare target
+#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}}
+
+int C::method() {
+  return 0;
+}
+
+struct S {
+#pragma omp declare target // expected-error {{directive must be at file or namespace scope}}
+  int v;
+#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}}
+};
+
+int main (int argc, char **argv) {
+#pragma omp declare target // expected-error {{unexpected OpenMP directive '#pragma omp declare target'}}
+  int v;
+#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}}
+  foo();
+  return (0);
+}
+
+namespace {
+#pragma omp declare target // expected-note {{to match this '#pragma omp declare target'}}
+  int x;
+} //  expected-error {{expected '#pragma omp end declare target'}}
+#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}}
+
+#pragma omp declare target // expected-error {{expected '#pragma omp end declare target'}} expected-note {{to match this '#pragma omp declare target'}}

Propchange: cfe/trunk/test/OpenMP/declare_target_messages.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/OpenMP/declare_target_messages.cpp
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Rev URL"

Propchange: cfe/trunk/test/OpenMP/declare_target_messages.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain




More information about the cfe-commits mailing list