ABataev retitled this revision from "[OPENMP] Initial support for '#pragma omp 
declare simd' directive." to "[OPENMP 4.0] Initial support for '#pragma omp 
declare simd' directive.".

Update after review


http://reviews.llvm.org/D10599

Files:
  include/clang/AST/ASTMutationListener.h
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  include/clang/Basic/DiagnosticParseKinds.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/OpenMPKinds.def
  include/clang/Parse/Parser.h
  include/clang/Sema/Sema.h
  include/clang/Serialization/ASTWriter.h
  lib/AST/DeclPrinter.cpp
  lib/Basic/OpenMPKinds.cpp
  lib/Frontend/MultiplexConsumer.cpp
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/ParseOpenMP.cpp
  lib/Parse/Parser.cpp
  lib/Sema/SemaOpenMP.cpp
  lib/Serialization/ASTCommon.h
  lib/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriter.cpp
  test/OpenMP/declare_simd_ast_print.c
  test/OpenMP/declare_simd_ast_print.cpp
  test/OpenMP/declare_simd_messages.cpp

Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -4626,6 +4626,14 @@
                        Record);
         break;
 
+      case UPD_DECL_MARKED_OPENMP_DECLARE_SIMD: {
+        auto *Attr = D->getAttr<OMPDeclareSimdDeclAttr>();
+        AddSourceRange(Attr->getRange(), Record);
+        Record.push_back(Attr->getNumberOfDirectives());
+        Record.push_back(Attr->getComplete() ? 1 : 0);
+        break;
+      }
+
       case UPD_DECL_EXPORTED:
         Record.push_back(getSubmoduleID(Update.getModule()));
         break;
@@ -5776,6 +5784,14 @@
   DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_THREADPRIVATE));
 }
 
+void ASTWriter::DeclarationMarkedOpenMPDeclareSimd(const Decl *D) {
+  assert(!WritingAST && "Already writing the AST!");
+  if (!D->isFromASTFile())
+    return;
+
+  DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_DECLARE_SIMD));
+}
+
 void ASTWriter::RedefinedHiddenDefinition(const NamedDecl *D, Module *M) {
   assert(!WritingAST && "Already writing the AST!");
   assert(D->isHidden() && "expected a hidden declaration");
Index: lib/Serialization/ASTCommon.h
===================================================================
--- lib/Serialization/ASTCommon.h
+++ lib/Serialization/ASTCommon.h
@@ -36,6 +36,7 @@
   UPD_MANGLING_NUMBER,
   UPD_STATIC_LOCAL_NUMBER,
   UPD_DECL_MARKED_OPENMP_THREADPRIVATE,
+  UPD_DECL_MARKED_OPENMP_DECLARE_SIMD,
   UPD_DECL_EXPORTED,
   UPD_ADDED_ATTR_TO_RECORD
 };
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -3916,6 +3916,16 @@
           Reader.Context, ReadSourceRange(Record, Idx)));
       break;
 
+    case UPD_DECL_MARKED_OPENMP_DECLARE_SIMD: {
+      SourceRange SR = ReadSourceRange(Record, Idx);
+      unsigned NumberOfDirectives = Record[Idx++];
+      bool Complete = Record[Idx++] != 0;
+      auto *Attr = new (Reader.Context) OMPDeclareSimdDeclAttr(
+          SR, Reader.Context, NumberOfDirectives, Complete, /*SI=*/0);
+      D->addAttr(Attr);
+      break;
+    }
+
     case UPD_DECL_EXPORTED: {
       unsigned SubmoduleID = readSubmoduleID(Record, Idx);
       auto *Exported = cast<NamedDecl>(D);
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -653,7 +653,7 @@
     HandlePragmaOpenCLExtension();
     return DeclGroupPtrTy();
   case tok::annot_pragma_openmp:
-    return ParseOpenMPDeclarativeDirective();
+    return ParseOpenMPDeclarativeDirective(/*IsInTagDecl=*/false);
   case tok::annot_pragma_ms_pointers_to_members:
     HandlePragmaMSPointersToMembers();
     return DeclGroupPtrTy();
Index: lib/Parse/ParseOpenMP.cpp
===================================================================
--- lib/Parse/ParseOpenMP.cpp
+++ lib/Parse/ParseOpenMP.cpp
@@ -30,6 +30,7 @@
   // E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd
   // TODO: add other combined directives in topological order.
   const OpenMPDirectiveKind F[][3] = {
+      {OMPD_unknown /*declare*/, OMPD_simd, OMPD_declare_simd},
       {OMPD_unknown /*cancellation*/, OMPD_unknown /*point*/,
        OMPD_cancellation_point},
       {OMPD_for, OMPD_simd, OMPD_for_simd},
@@ -43,25 +44,25 @@
           : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
   bool TokenMatched = false;
   for (unsigned i = 0; i < llvm::array_lengthof(F); ++i) {
-    if (!Tok.isAnnotation() && DKind == OMPD_unknown) {
+    if (!Tok.isAnnotation() && DKind == OMPD_unknown)
       TokenMatched =
-          (i == 0) &&
-          !P.getPreprocessor().getSpelling(Tok).compare("cancellation");
-    } else {
+          ((i == 0) &&
+           !P.getPreprocessor().getSpelling(Tok).compare("declare")) ||
+          ((i == 1) &&
+           !P.getPreprocessor().getSpelling(Tok).compare("cancellation"));
+    else
       TokenMatched = DKind == F[i][0] && DKind != OMPD_unknown;
-    }
     if (TokenMatched) {
       Tok = P.getPreprocessor().LookAhead(0);
       auto SDKind =
           Tok.isAnnotation()
               ? OMPD_unknown
               : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
-      if (!Tok.isAnnotation() && DKind == OMPD_unknown) {
+      if (!Tok.isAnnotation() && SDKind == OMPD_unknown)
         TokenMatched =
-            (i == 0) && !P.getPreprocessor().getSpelling(Tok).compare("point");
-      } else {
+            (i == 1) && !P.getPreprocessor().getSpelling(Tok).compare("point");
+      else
         TokenMatched = SDKind == F[i][1] && SDKind != OMPD_unknown;
-      }
       if (TokenMatched) {
         P.ConsumeToken();
         DKind = F[i][2];
@@ -76,13 +77,17 @@
 ///       threadprivate-directive:
 ///         annot_pragma_openmp 'threadprivate' simple-variable-list
 ///
-Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
+Parser::DeclGroupPtrTy
+Parser::ParseOpenMPDeclarativeDirective(bool IsInTagDecl, unsigned Level) {
   assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
   ParenBraceBracketBalancer BalancerRAIIObj(*this);
 
+  auto AnnotationVal = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue());
   SourceLocation Loc = ConsumeToken();
   SmallVector<Expr *, 5> Identifiers;
-  auto DKind = ParseOpenMPDirectiveKind(*this);
+  OpenMPDirectiveKind DKind =
+      (AnnotationVal == 0) ? ParseOpenMPDirectiveKind(*this)
+                           : static_cast<OpenMPDirectiveKind>(AnnotationVal);
 
   switch (DKind) {
   case OMPD_threadprivate:
@@ -100,6 +105,85 @@
       return Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers);
     }
     break;
+  case OMPD_declare_simd: {
+    // The syntax is:
+    // { #pragma omp declare simd }
+    // <function-declaration-or-definition>
+    //
+    if (AnnotationVal == 0)
+      // Skip 'simd' if it was restored from cached tokens.
+      ConsumeToken();
+    if (IsInTagDecl) {
+      LateParseOpenMPDeclarativeDirective(/*DKind=*/OMPD_declare_simd, Loc);
+      return DeclGroupPtrTy();
+    }
+
+    SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1>
+        FirstClauses(OMPC_unknown + 1);
+    SmallVector<OMPClause *, 4> Clauses;
+    SmallVector<Token, 8> CachedPragmas;
+
+    while (Tok.isNot(tok::annot_pragma_openmp_end) && Tok.isNot(tok::eof)) {
+      CachedPragmas.push_back(Tok);
+      ConsumeAnyToken();
+    }
+    CachedPragmas.push_back(Tok);
+    if (Tok.isNot(tok::eof))
+      ConsumeAnyToken();
+
+    DeclGroupPtrTy Ptr;
+    if (Tok.is(tok::annot_pragma_openmp)) {
+      Ptr = ParseOpenMPDeclarativeDirective(IsInTagDecl, Level + 1);
+    } else {
+      // Here we expect to see some function declaration.
+      ParsedAttributesWithRange attrs(AttrFactory);
+      MaybeParseCXX11Attributes(attrs);
+      MaybeParseMicrosoftAttributes(attrs);
+      ParsingDeclSpec PDS(*this);
+      Ptr = ParseExternalDeclaration(attrs, &PDS);
+    }
+    if (!Ptr || Ptr.get().isNull())
+      return DeclGroupPtrTy();
+    if (Ptr.get().isDeclGroup()) {
+      Diag(Tok, diag::err_omp_single_decl_in_declare_simd);
+      return DeclGroupPtrTy();
+    }
+
+    // Append the current token at the end of the new token stream so that it
+    // doesn't get lost.
+    CachedPragmas.push_back(Tok);
+    // Push back tokens for pragma.
+    PP.EnterTokenStream(CachedPragmas.data(), CachedPragmas.size(),
+                        /*DisableMacroExpansion=*/true,
+                        /*OwnsTokens=*/false);
+    // Parse pragma itself.
+    // Consume the previously pushed token.
+    ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
+
+    while (Tok.isNot(tok::annot_pragma_openmp_end)) {
+      OpenMPClauseKind CKind = Tok.isAnnotation()
+                                   ? OMPC_unknown
+                                   : getOpenMPClauseKind(PP.getSpelling(Tok));
+      Actions.StartOpenMPClause(CKind);
+      OMPClause *Clause =
+          ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt());
+      FirstClauses[CKind].setInt(true);
+      if (Clause) {
+        FirstClauses[CKind].setPointer(Clause);
+        Clauses.push_back(Clause);
+      }
+
+      // Skip ',' if any.
+      if (Tok.is(tok::comma))
+        ConsumeToken();
+      Actions.EndOpenMPClause();
+    }
+    // Consume final annot_pragma_openmp_end.
+    ConsumeToken();
+
+    return Actions.ActOnOpenMPDeclareSimdDirective(
+        Clauses, Ptr.get().getSingleDecl(), Loc, Level == 0);
+  }
   case OMPD_unknown:
     Diag(Tok, diag::err_omp_unknown_directive);
     break;
@@ -135,6 +219,70 @@
   return DeclGroupPtrTy();
 }
 
+/// \brief Late parsing of declarative OpenMP directives.
+///
+///       declare-simd:
+///         annot_pragma_openmp 'declare simd' {<clause> [,]}
+///         annot_pragma_openmp_end
+///         <template function>
+///
+void Parser::LateParseOpenMPDeclarativeDirective(OpenMPDirectiveKind DKind,
+                                                 SourceLocation Loc) {
+  if (DKind == OMPD_declare_simd) {
+    LateParsedOpenMPDeclaration *Decl = new LateParsedOpenMPDeclaration(this);
+    getCurrentClass().LateParsedDeclarations.push_back(Decl);
+
+    Token LocalTok;
+    LocalTok.startToken();
+    LocalTok.setKind(tok::annot_pragma_openmp);
+    LocalTok.setLocation(Loc);
+    LocalTok.setAnnotationValue(
+        reinterpret_cast<void *>(static_cast<uintptr_t>(OMPD_declare_simd)));
+    Decl->Tokens.push_back(LocalTok);
+
+    do {
+      while (Tok.isNot(tok::annot_pragma_openmp_end) && Tok.isNot(tok::eof)) {
+        Decl->Tokens.push_back(Tok);
+        ConsumeAnyToken();
+      }
+      Decl->Tokens.push_back(Tok);
+      if (Tok.isNot(tok::eof))
+        ConsumeAnyToken();
+    } while (Tok.is(tok::annot_pragma_openmp));
+
+    LexTemplateFunctionForLateParsing(Decl->Tokens);
+  }
+}
+
+/// \brief Actual parsing of late OpenMP declaration.
+void Parser::LateParsedOpenMPDeclaration::ParseLexedMethodDeclarations() {
+  // Save the current token position.
+  SourceLocation OrigLoc = Self->Tok.getLocation();
+
+  assert(!Tokens.empty() && "Empty body!");
+  // Append the current token at the end of the new token stream so that it
+  // doesn't get lost.
+  Tokens.push_back(Self->Tok);
+  Self->PP.EnterTokenStream(Tokens.data(), Tokens.size(), true, false);
+
+  // Consume the previously pushed token.
+  Self->ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
+
+  Self->ParseOpenMPDeclarativeDirective(/*IsInTagDecl=*/false);
+
+  if (Self->Tok.getLocation() != OrigLoc) {
+    // Due to parsing error, we either went over the cached tokens or
+    // there are still cached tokens left. If it's the latter case skip the
+    // leftover tokens.
+    // Since this is an uncommon situation that should be avoided, use the
+    // expensive isBeforeInTranslationUnit call.
+    if (Self->PP.getSourceManager().isBeforeInTranslationUnit(
+            Self->Tok.getLocation(), OrigLoc))
+      while (Self->Tok.getLocation() != OrigLoc && Self->Tok.isNot(tok::eof))
+        Self->ConsumeAnyToken();
+  }
+}
+
 /// \brief Parsing of declarative or executable OpenMP directives.
 ///
 ///       threadprivate-directive:
@@ -299,6 +447,11 @@
     OMPDirectiveScope.Exit();
     break;
   }
+  case OMPD_declare_simd:
+    Diag(Tok, diag::err_omp_unexpected_directive)
+        << getOpenMPDirectiveName(DKind);
+    SkipUntil(tok::annot_pragma_openmp_end);
+    break;
   case OMPD_unknown:
     Diag(Tok, diag::err_omp_unknown_directive);
     SkipUntil(tok::annot_pragma_openmp_end);
Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -2975,7 +2975,7 @@
       }
 
       if (Tok.is(tok::annot_pragma_openmp)) {
-        ParseOpenMPDeclarativeDirective();
+        ParseOpenMPDeclarativeDirective(/*IsInTagDecl=*/true);
         continue;
       }
 
Index: lib/AST/DeclPrinter.cpp
===================================================================
--- lib/AST/DeclPrinter.cpp
+++ lib/AST/DeclPrinter.cpp
@@ -36,6 +36,7 @@
     void ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls);
 
     void Print(AccessSpecifier AS);
+    void print(OMPDeclareSimdDeclAttr *A);
 
     /// Print an Objective-C method type in parentheses.
     ///
@@ -407,7 +408,22 @@
   }
 }
 
+void DeclPrinter::print(OMPDeclareSimdDeclAttr *A) {
+  for (unsigned i = 0; i < A->getNumberOfDirectives(); ++i) {
+    A->printPrettyPragma(Out, Policy);
+    Indent();
+  }
+}
+
 void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
+  if (auto *Attr = D->getAttr<OMPDeclareSimdDeclAttr>()) {
+    if (D->getTemplatedKind() !=
+            FunctionDecl::TK_FunctionTemplateSpecialization &&
+        D->getTemplatedKind() != FunctionDecl::TK_FunctionTemplate &&
+        D->getTemplatedKind() !=
+            FunctionDecl::TK_DependentFunctionTemplateSpecialization)
+      print(Attr);
+  }
   CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
   CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D);
   if (!Policy.SuppressSpecifiers) {
@@ -914,11 +930,15 @@
   if (PrintInstantiation) {
     TemplateParameterList *Params = D->getTemplateParameters();
     for (auto *I : D->specializations()) {
+      if (auto *Attr = I->getAttr<OMPDeclareSimdDeclAttr>())
+        print(Attr);
       PrintTemplateParameters(Params, I->getTemplateSpecializationArgs());
       Visit(I);
     }
   }
 
+  if (auto *Attr = D->getTemplatedDecl()->getAttr<OMPDeclareSimdDeclAttr>())
+    print(Attr);
   return VisitRedeclarableTemplateDecl(D);
 }
 
Index: lib/Sema/SemaOpenMP.cpp
===================================================================
--- lib/Sema/SemaOpenMP.cpp
+++ lib/Sema/SemaOpenMP.cpp
@@ -1327,6 +1327,7 @@
   case OMPD_cancellation_point:
   case OMPD_cancel:
   case OMPD_flush:
+  case OMPD_declare_simd:
     llvm_unreachable("OpenMP Directive is not allowed");
   case OMPD_unknown:
     llvm_unreachable("Unknown OpenMP directive");
@@ -2117,6 +2118,7 @@
     Res = ActOnOpenMPCancelDirective(StartLoc, EndLoc, CancelRegion);
     break;
   case OMPD_threadprivate:
+  case OMPD_declare_simd:
     llvm_unreachable("OpenMP Directive is not allowed");
   case OMPD_unknown:
     llvm_unreachable("Unknown OpenMP directive");
@@ -2134,6 +2136,34 @@
   return Res;
 }
 
+Sema::DeclGroupPtrTy
+Sema::ActOnOpenMPDeclareSimdDirective(ArrayRef<OMPClause *> Clauses,
+                                      Decl *ADecl, SourceLocation StartLoc,
+                                      bool LastDirective) {
+  if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ADecl))
+    ADecl = FTD->getTemplatedDecl();
+
+  if (!isa<FunctionDecl>(ADecl)) {
+    Diag(ADecl->getLocation(), diag::err_omp_function_expected)
+        << ADecl->getDeclContext()->isFileContext();
+    return DeclGroupPtrTy();
+  }
+  if (auto *Attr = ADecl->getAttr<OMPDeclareSimdDeclAttr>()) {
+    if (!Attr->getComplete()) {
+      Attr->setNumberOfDirectives(Attr->getNumberOfDirectives() + 1);
+      if (LastDirective)
+        Attr->setComplete();
+    }
+  } else {
+    auto *NewAttr = new (Context) OMPDeclareSimdDeclAttr(
+        SourceRange(StartLoc, StartLoc), Context, 1, LastDirective, /*SI=*/0);
+    ADecl->addAttr(NewAttr);
+    if (auto *ML = Context.getASTMutationListener())
+      ML->DeclarationMarkedOpenMPDeclareSimd(ADecl);
+  }
+  return ConvertDeclToDeclGroup(ADecl);
+}
+
 StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
                                               Stmt *AStmt,
                                               SourceLocation StartLoc,
Index: lib/Basic/OpenMPKinds.cpp
===================================================================
--- lib/Basic/OpenMPKinds.cpp
+++ lib/Basic/OpenMPKinds.cpp
@@ -338,6 +338,8 @@
       break;
     }
     break;
+  case OMPD_declare_simd:
+    break;
   case OMPD_unknown:
   case OMPD_threadprivate:
   case OMPD_section:
Index: lib/Frontend/MultiplexConsumer.cpp
===================================================================
--- lib/Frontend/MultiplexConsumer.cpp
+++ lib/Frontend/MultiplexConsumer.cpp
@@ -127,6 +127,7 @@
                                     const ObjCCategoryDecl *ClassExt) override;
   void DeclarationMarkedUsed(const Decl *D) override;
   void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
+  void DeclarationMarkedOpenMPDeclareSimd(const Decl *D) override;
   void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override;
   void AddedAttributeToRecord(const Attr *Attr, 
                               const RecordDecl *Record) override;
@@ -223,6 +224,11 @@
   for (size_t i = 0, e = Listeners.size(); i != e; ++i)
     Listeners[i]->DeclarationMarkedOpenMPThreadPrivate(D);
 }
+void MultiplexASTMutationListener::DeclarationMarkedOpenMPDeclareSimd(
+    const Decl *D) {
+  for (auto *Listener : Listeners)
+    Listener->DeclarationMarkedOpenMPDeclareSimd(D);
+}
 void MultiplexASTMutationListener::RedefinedHiddenDefinition(const NamedDecl *D,
                                                              Module *M) {
   for (auto *L : Listeners)
Index: include/clang/Serialization/ASTWriter.h
===================================================================
--- include/clang/Serialization/ASTWriter.h
+++ include/clang/Serialization/ASTWriter.h
@@ -865,6 +865,7 @@
                                     const ObjCCategoryDecl *ClassExt) override;
   void DeclarationMarkedUsed(const Decl *D) override;
   void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
+  void DeclarationMarkedOpenMPDeclareSimd(const Decl *D) override;
   void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override;
   void AddedAttributeToRecord(const Attr *Attr,
                               const RecordDecl *Record) override;
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -1021,6 +1021,19 @@
     CachedTokens *ExceptionSpecTokens;
   };
 
+  /// \brief An OpenMP declaration inside a class.
+  struct LateParsedOpenMPDeclaration : public LateParsedDeclaration {
+    explicit LateParsedOpenMPDeclaration(Parser *P) : Self(P) {}
+
+    void ParseLexedMethodDeclarations() override;
+
+    Parser *Self;
+
+    /// \brief The set of tokens that make up an exception-specification that
+    /// has not yet been parsed.
+    CachedTokens Tokens;
+  };
+
   /// LateParsedMemberInitializer - An initializer for a non-static class data
   /// member whose parsing must to be delayed until the class is completely
   /// defined (C++11 [class.mem]p2).
@@ -2416,7 +2429,13 @@
   //===--------------------------------------------------------------------===//
   // OpenMP: Directives and clauses.
   /// \brief Parses declarative OpenMP directives.
-  DeclGroupPtrTy ParseOpenMPDeclarativeDirective();
+  /// \param Level Current level of declarative directive, in case it is allowed
+  /// to apply multiple declarative directives to the same declaration.
+  DeclGroupPtrTy ParseOpenMPDeclarativeDirective(bool IsInTagDecl,
+                                                 unsigned Level = 0);
+  /// \brief Late parse directive.
+  void LateParseOpenMPDeclarativeDirective(OpenMPDirectiveKind DKind,
+                                           SourceLocation Loc);
   /// \brief Parses simple list of variables.
   ///
   /// \param Kind Kind of the directive.
Index: include/clang/AST/ASTMutationListener.h
===================================================================
--- include/clang/AST/ASTMutationListener.h
+++ include/clang/AST/ASTMutationListener.h
@@ -115,6 +115,12 @@
   /// \param D the declaration marked OpenMP threadprivate.
   virtual void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) {}
 
+  /// \brief A declaration is marked as OpenMP declare simd which was not
+  /// previously marked as declare simd.
+  ///
+  /// \param D The declaration marked OpenMP declare simd.
+  virtual void DeclarationMarkedOpenMPDeclareSimd(const Decl *D) {}
+
   /// \brief A definition has been made visible by being redefined locally.
   ///
   /// \param D The definition that was previously not visible.
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -144,6 +144,7 @@
   class ObjCPropertyDecl;
   class ObjCProtocolDecl;
   class OMPThreadPrivateDecl;
+  class OMPDeclareSimdDecl;
   class OMPClause;
   class OverloadCandidateSet;
   class OverloadExpr;
@@ -7869,6 +7870,13 @@
                                         SourceLocation EndLoc,
                                         OpenMPDirectiveKind CancelRegion);
 
+  /// \brief Called on well-formed '\#pragma omp declare simd' after parsing of
+  /// the associated method/function.
+  DeclGroupPtrTy ActOnOpenMPDeclareSimdDirective(ArrayRef<OMPClause *> Clauses,
+                                                 Decl *ADecl,
+                                                 SourceLocation StartLoc,
+                                                 bool LastDirective);
+
   OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
                                          Expr *Expr,
                                          SourceLocation StartLoc,
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -7637,6 +7637,8 @@
   "the 'copyprivate' clause must not be used with the 'nowait' clause">;
 def note_omp_nowait_clause_here : Note<
   "'nowait' clause is here">;
+def err_omp_function_expected : Error<
+  "'#pragma omp declare simd' can be applied to functions only">;
 def err_omp_wrong_cancel_region : Error<
   "one of 'for', 'parallel', 'sections' or 'taskgroup' is expected">;
 def err_omp_parent_cancel_region_nowait : Error<
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -989,6 +989,8 @@
   "'#pragma omp %0' cannot be an immediate substatement">;
 def err_omp_expected_identifier_for_critical : Error<
   "expected identifier specifying the name of the 'omp critical' directive">;
+def err_omp_single_decl_in_declare_simd : Error<
+  "single declaration is expected with 'declare simd' directive">;
 
 // Pragma loop support.
 def err_pragma_loop_missing_argument : Error<
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -1583,3 +1583,33 @@
 The ``returns_nonnull`` attribute implies that returning a null pointer is undefined behavior, which the optimizer may take advantage of. The ``_Nonnull`` type qualifier indicates that a pointer cannot be null in a more general manner (because it is part of the type system) and does not imply undefined behavior, making it more widely applicable
 }];
 }
+
+def OMPDeclareSimdDocs : Documentation {
+  let Category = DocCatStmt;
+  let Heading = "#pragma omp declare simd";
+  let Content = [{
+The declare simd construct can be applied to a function to enable the creation of one or more versions that can process multiple arguments using SIMD instructions from a single invocation from a SIMD loop. The declare simd directive is a declarative directive. There may be multiple declare simd directives for a function. The use of a declare simd construct on a function enables the creation of SIMD
+versions of the associated function that can be used to process multiple arguments from a single invocation from a SIMD loop concurrently.
+The syntax of the declare simd construct is as follows:
+
+  .. code-block:: c
+
+  #pragma omp declare simd [clause[[,] clause] ...] new-line
+  [#pragma omp declare simd [clause[[,] clause] ...] new-line]
+  [...]
+  function definition or declaration
+
+where clause is one of the following:
+
+  .. code-block:: c
+
+  simdlen(length)
+  linear(argument-list[:constant-linear-step])
+  aligned(argument-list[:alignment])
+  uniform(argument-list)
+  inbranch
+  notinbranch
+
+  }];
+}
+
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -2054,3 +2054,21 @@
   let SemaHandler = 0;
   let Documentation = [Undocumented];
 }
+
+def OMPDeclareSimdDecl : InheritableAttr {
+  // This attribute has no spellings as it is only ever created implicitly.
+  let Spellings = [];
+  let Subjects = SubjectList<[Function]>;
+  let SemaHandler = 0;
+  let HasCustomParsing = 1;
+  let Documentation = [OMPDeclareSimdDocs];
+  let Args = [UnsignedArgument<"NumberOfDirectives">, BoolArgument<"Complete">];
+  let AdditionalMembers = [{
+  void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const {
+    OS << "#pragma omp declare simd\n";
+  }
+  void setNumberOfDirectives(unsigned N) { numberOfDirectives = N; }
+  void setComplete() { complete = true; }
+  }];
+}
+
Index: include/clang/Basic/OpenMPKinds.def
===================================================================
--- include/clang/Basic/OpenMPKinds.def
+++ include/clang/Basic/OpenMPKinds.def
@@ -99,6 +99,7 @@
 OPENMP_DIRECTIVE_EXT(parallel_sections, "parallel sections")
 OPENMP_DIRECTIVE_EXT(for_simd, "for simd")
 OPENMP_DIRECTIVE_EXT(cancellation_point, "cancellation point")
+OPENMP_DIRECTIVE_EXT(declare_simd, "declare simd")
 
 // OpenMP clauses.
 OPENMP_CLAUSE(if, OMPIfClause)
Index: test/OpenMP/declare_simd_ast_print.c
===================================================================
--- test/OpenMP/declare_simd_ast_print.c
+++ test/OpenMP/declare_simd_ast_print.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+#pragma omp declare simd
+#pragma omp declare simd
+void add_1(float *d, float *s1, float *s2);
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: #pragma omp declare simd
+// CHECK-NEXT: void add_1(float *d, float *s1, float *s2)
+
+#endif
Index: test/OpenMP/declare_simd_ast_print.cpp
===================================================================
--- test/OpenMP/declare_simd_ast_print.cpp
+++ test/OpenMP/declare_simd_ast_print.cpp
@@ -0,0 +1,103 @@
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+#pragma omp declare simd
+void add_1(float *d);
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: void add_1(float *d);
+//
+
+#pragma omp declare simd
+template <class C> void h(C *hp, C *hp2, C *hq, C *lin) {
+}
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: template <class C = int> void h(int *hp, int *hp2, int *hq, int *lin) {
+// CHECK-NEXT: h((float *)hp, (float *)hp2, (float *)hq, (float *)lin);
+// CHECK-NEXT: }
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: template <class C = float> void h(float *hp, float *hp2, float *hq, float *lin) {
+// CHECK-NEXT: }
+
+// CHECK: #pragma omp declare simd
+// CHECK: template <class C> void h(C *hp, C *hp2, C *hq, C *lin) {
+// CHECK-NEXT: }
+//
+
+// Instatiate with <C=int> explicitly.
+// Pragmas need to be same, otherwise standard says that's undefined behavior.
+#pragma omp declare simd
+template <>
+void h(int *hp, int *hp2, int *hq, int *lin)
+{
+  // Instatiate with <C=float> implicitly.
+  // This is special case where the directive is stored by Sema and is
+  // generated together with the (pending) function instatiation.
+  h((float*) hp, (float*) hp2, (float*) hq, (float*) lin);
+}
+
+class VV {
+  // CHECK: #pragma omp declare simd
+  // CHECK-NEXT: int add(int a, int b)     {
+  // CHECK-NEXT: return a + b;
+  // CHECK-NEXT: }
+  #pragma omp declare simd
+  int add(int a, int b) { return a + b; }
+
+  // CHECK: #pragma omp declare simd
+  // CHECK-NEXT: #pragma omp declare simd
+  // CHECK-NEXT: float addpf(float *a, float *b)     {
+  // CHECK-NEXT: return *a + *b;
+  // CHECK-NEXT: }
+  #pragma omp declare simd
+  #pragma omp declare simd
+  float addpf(float *a, float *b) { return *a + *b; }
+};
+
+// CHECK: template <int X = 16> class TVV {
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: int tadd(int a, int b);
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: float taddpf(float *a, float *b) {
+// CHECK-NEXT: return *a + *b;
+// CHECK-NEXT: }
+// CHECK: }
+template <int X>
+class TVV {
+public:
+// CHECK: template <int X> class TVV {
+  #pragma omp declare simd
+  int tadd(int a, int b) { return a + b; }
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: int tadd(int a, int b) {
+// CHECK-NEXT: return a + b;
+// CHECK-NEXT: }
+
+
+  #pragma omp declare simd
+  float taddpf(float *a, float *b) { return *a + *b; }
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: float taddpf(float *a, float *b) {
+// CHECK-NEXT: return *a + *b;
+// CHECK-NEXT: }
+};
+// CHECK: };
+
+// CHECK: TVV<16> t16;
+TVV<16> t16;
+
+void f() {
+  float a = 1.0f, b = 2.0f;
+  float r = t16.taddpf(&a, &b);
+}
+
+#endif
Index: test/OpenMP/declare_simd_messages.cpp
===================================================================
--- test/OpenMP/declare_simd_messages.cpp
+++ test/OpenMP/declare_simd_messages.cpp
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -x c++ -std=c++11 %s
+
+// expected-error@+1 {{expected an OpenMP directive}}
+#pragma omp declare
+
+// expected-error@+2 {{'#pragma omp declare simd' can be applied to functions only}}
+#pragma omp declare simd
+int a;
+// expected-error@+2 {{'#pragma omp declare simd' can be applied to functions only}}
+#pragma omp declare simd
+#pragma omp threadprivate(a)
+int var;
+#pragma omp threadprivate(var)
+
+// expected-error@+2 {{expected an OpenMP directive}}
+#pragma omp declare simd
+#pragma omp declare
+
+#pragma omp declare simd
+#pragma omp declare simd
+int main();
+
+#pragma omp declare simd
+template <class C>
+void h(C *hp, C *hp2, C *hq, C *lin) {
+}
+
+#pragma omp declare simd
+template <>
+void h(int *hp, int *hp2, int *hq, int *lin) {
+  h((float *)hp, (float *)hp2, (float *)hq, (float *)lin);
+}
+
+template <class T>
+struct St {
+#pragma omp declare simd
+  void h(T *hp) {
+// expected-error@+1 {{unexpected OpenMP directive '#pragma omp declare simd'}}
+#pragma omp declare simd
+    *hp = *t;
+  }
+
+private:
+  T t;
+};
+#pragma omp declare simd
+// expected-error@+1 {{expected external declaration}}
+#pragma omp declare simd
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to