[prev in list] [next in list] [prev in thread] [next in thread] 

List:       cfe-commits
Subject:    Re: [PATCH] D10599: [OPENMP 4.0] Initial support for '#pragma omp declare simd' directive.
From:       Alexey Bataev <a.bataev () hotmail ! com>
Date:       2015-07-27 4:00:26
Message-ID: 2503f53917c06701f0c8ea00e9c40182 () localhost ! localdomain
[Download RAW message or body]

ABataev updated the summary for this revision.
ABataev updated this revision to Diff 30669.
ABataev added a comment.

Update after review


http://reviews.llvm.org/D10599

Files:
  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
  lib/AST/DeclPrinter.cpp
  lib/Basic/OpenMPKinds.cpp
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/ParseOpenMP.cpp
  lib/Parse/Parser.cpp
  lib/Sema/SemaOpenMP.cpp
  test/OpenMP/declare_simd_ast_print.c
  test/OpenMP/declare_simd_ast_print.cpp
  test/OpenMP/declare_simd_messages.cpp


["D10599.30669.patch" (text/x-patch)]

Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -652,8 +652,10 @@
   case tok::annot_pragma_opencl_extension:
     HandlePragmaOpenCLExtension();
     return DeclGroupPtrTy();
-  case tok::annot_pragma_openmp:
-    return ParseOpenMPDeclarativeDirective();
+  case tok::annot_pragma_openmp: {
+    AccessSpecifier AS = AS_none;
+    return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, attrs);
+  }
   case tok::annot_pragma_ms_pointers_to_members:
     HandlePragmaMSPointersToMembers();
     return DeclGroupPtrTy();
Index: lib/Parse/ParseOpenMP.cpp
===================================================================
--- lib/Parse/ParseOpenMP.cpp
+++ lib/Parse/ParseOpenMP.cpp
@@ -31,6 +31,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_target, OMPD_unknown /*data*/, OMPD_target_data},
@@ -46,13 +47,14 @@
 
   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);
@@ -64,12 +66,11 @@
 
       if (!TokenIsAnnotation && SDKind == OMPD_unknown) {
         TokenMatched =
-            ((i == 0) &&
+            ((i == 1) &&
              !P.getPreprocessor().getSpelling(Tok).compare("point")) ||
-            ((i == 1) && !P.getPreprocessor().getSpelling(Tok).compare("data"));
-      } else {
+            ((i == 2) && !P.getPreprocessor().getSpelling(Tok).compare("data"));
+      } else
         TokenMatched = SDKind == F[i][1] && SDKind != OMPD_unknown;
-      }
 
       if (TokenMatched) {
         P.ConsumeToken();
@@ -84,14 +85,25 @@
 ///
 ///       threadprivate-directive:
 ///         annot_pragma_openmp 'threadprivate' simple-variable-list
+///         annot_pragma_omp_end
 ///
-Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
+///       declare-simd-directive:
+///         annot_pragma_openmp 'declare simd' {<clause> [,]}
+///         annot_pragma_omp_end
+///         <function declaration/definition>
+///
+Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
+    AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
+    DeclSpec::TST TagType, Decl *TagDecl) {
   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:
@@ -109,6 +121,97 @@
       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();
+
+    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 = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, TagType,
+                                                       TagDecl);
+    else
+      // Here we expect to see some function declaration.
+      while (Tok.isNot(tok::r_brace) && !isEofOrEom() &&
+             (!Ptr || Ptr.get().isNull())) {
+        if (AS == AS_none || TagType == DeclSpec::TST_unspecified) {
+          MaybeParseCXX11Attributes(Attrs);
+          MaybeParseMicrosoftAttributes(Attrs);
+          ParsingDeclSpec PDS(*this);
+          Ptr = ParseExternalDeclaration(Attrs, &PDS);
+        } else
+          Ptr = ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType,
+                                                          TagDecl);
+      }
+    if (!Ptr || Ptr.get().isNull()) {
+      if (isEofOrEom())
+        Diag(Loc, diag::err_omp_decl_in_declare_simd);
+      return DeclGroupPtrTy();
+    }
+    if (!Ptr.get().isSingleDecl())
+      Diag(Loc, diag::err_omp_single_decl_in_declare_simd);
+
+    // 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();
+    }
+    // The last seen token is annot_pragma_openmp_end - need to check for
+    // extra tokens.
+    if (Tok.isNot(tok::annot_pragma_openmp_end)) {
+      Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
+          << getOpenMPDirectiveName(OMPD_declare_simd);
+      SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
+    }
+    // Skip the last annot_pragma_openmp_end.
+    ConsumeToken();
+
+    if (Ptr.get().isSingleDecl())
+      return Actions.ActOnOpenMPDeclareSimdDirective(
+          Clauses, Ptr.get().getSingleDecl(), Loc);
+    return Ptr;
+  }
   case OMPD_unknown:
     Diag(Tok, diag::err_omp_unknown_directive);
     break;
@@ -310,6 +413,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
@@ -2234,8 +2234,9 @@
 ///       constant-initializer:
 ///         '=' constant-expression
 ///
-void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
-                                            AttributeList *AccessAttrs,
+Parser::DeclGroupPtrTy
+Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
+                                       AttributeList *AccessAttrs,
                                        const ParsedTemplateInfo &TemplateInfo,
                                        ParsingDeclRAIIObject *TemplateDiags) {
   if (Tok.is(tok::at)) {
@@ -2246,7 +2247,7 @@
 
     ConsumeToken();
     SkipUntil(tok::r_brace, StopAtSemi);
-    return;
+    return DeclGroupPtrTy();
   }
 
   // Turn on colon protection early, while parsing declspec, although there is
@@ -2280,52 +2281,49 @@
 
       if (SS.isInvalid()) {
         SkipUntil(tok::semi);
-        return;
+        return DeclGroupPtrTy();
       }
 
       // Try to parse an unqualified-id.
       SourceLocation TemplateKWLoc;
       UnqualifiedId Name;
       if (ParseUnqualifiedId(SS, false, true, true, ParsedType(),
                              TemplateKWLoc, Name)) {
         SkipUntil(tok::semi);
-        return;
+        return DeclGroupPtrTy();
       }
 
       // TODO: recover from mistakenly-qualified operator declarations.
       if (ExpectAndConsume(tok::semi, diag::err_expected_after,
                            "access declaration")) {
         SkipUntil(tok::semi);
-        return;
+        return DeclGroupPtrTy();
       }
 
-      Actions.ActOnUsingDeclaration(getCurScope(), AS,
-                                    /* HasUsingKeyword */ false,
-                                    SourceLocation(),
-                                    SS, Name,
-                                    /* AttrList */ nullptr,
-                                    /* HasTypenameKeyword */ false,
-                                    SourceLocation());
-      return;
+      return DeclGroupPtrTy::make(DeclGroupRef(Actions.ActOnUsingDeclaration(
+          getCurScope(), AS,
+          /* HasUsingKeyword */ false, SourceLocation(), SS, Name,
+          /* AttrList */ nullptr,
+          /* HasTypenameKeyword */ false, SourceLocation())));
     }
   }
 
   // static_assert-declaration. A templated static_assert declaration is
   // diagnosed in Parser::ParseSingleDeclarationAfterTemplate.
   if (!TemplateInfo.Kind &&
       Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
     SourceLocation DeclEnd;
-    ParseStaticAssertDeclaration(DeclEnd);
-    return;
+    return DeclGroupPtrTy::make(
+        DeclGroupRef(ParseStaticAssertDeclaration(DeclEnd)));
   }
 
   if (Tok.is(tok::kw_template)) {
     assert(!TemplateInfo.TemplateParams &&
            "Nested template improperly parsed?");
     SourceLocation DeclEnd;
-    ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd,
-                                         AS, AccessAttrs);
-    return;
+    return DeclGroupPtrTy::make(
+        DeclGroupRef(ParseDeclarationStartingWithTemplate(
+            Declarator::MemberContext, DeclEnd, AS, AccessAttrs)));
   }
 
   // Handle:  member-declaration ::= '__extension__' member-declaration
@@ -2357,13 +2355,12 @@
     if (Tok.is(tok::kw_namespace)) {
       Diag(UsingLoc, diag::err_using_namespace_in_class);
       SkipUntil(tok::semi, StopBeforeMatch);
-    } else {
-      SourceLocation DeclEnd;
-      // Otherwise, it must be a using-declaration or an alias-declaration.
-      ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo,
-                            UsingLoc, DeclEnd, AS);
+      return DeclGroupPtrTy();
     }
-    return;
+    SourceLocation DeclEnd;
+    // Otherwise, it must be a using-declaration or an alias-declaration.
+    return DeclGroupPtrTy::make(DeclGroupRef(ParseUsingDeclaration(
+        Declarator::MemberContext, TemplateInfo, UsingLoc, DeclEnd, AS)));
   }
 
   // Hold late-parsed attributes so we can attach a Decl to them later.
@@ -2388,7 +2385,7 @@
       TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate &&
       DiagnoseMissingSemiAfterTagDefinition(DS, AS, DSC_class,
                                             &CommonLateParsedAttrs))
-    return;
+    return DeclGroupPtrTy();
 
   MultiTemplateParamsArg TemplateParams(
       TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data()
@@ -2402,7 +2399,7 @@
     Decl *TheDecl =
       Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, TemplateParams);
     DS.complete(TheDecl);
-    return;
+    return DeclGroupPtrTy::make(DeclGroupRef(TheDecl));
   }
 
   ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext);
@@ -2443,7 +2440,7 @@
   if (ParseCXXMemberDeclaratorBeforeInitializer(
           DeclaratorInfo, VS, BitfieldSize, LateParsedAttrs)) {
     TryConsumeToken(tok::semi);
-    return;
+    return DeclGroupPtrTy();
   }
 
   // Check for a member function definition.
@@ -2492,7 +2489,7 @@
         // Consume the optional ';'
         TryConsumeToken(tok::semi);
 
-        return;
+        return DeclGroupPtrTy();
       }
 
       if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
@@ -2521,7 +2518,7 @@
       if (Tok.is(tok::semi))
         ConsumeExtraSemi(AfterMemberFunctionDefinition);
 
-      return;
+      return DeclGroupPtrTy::make(DeclGroupRef(FunDecl));
     }
   }
 
@@ -2695,10 +2692,10 @@
     SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
     // If we stopped at a ';', eat it.
     TryConsumeToken(tok::semi);
-    return;
+    return DeclGroupPtrTy();
   }
 
-  Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup);
+  return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup);
 }
 
 /// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer.
@@ -2816,6 +2813,96 @@
     MaybeParseGNUAttributes(Attrs);
 }
 
+Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas(
+    AccessSpecifier &AS, ParsedAttributesWithRange &AccessAttrs,
+    DeclSpec::TST TagType, Decl *TagDecl) {
+  if (getLangOpts().MicrosoftExt &&
+      Tok.isOneOf(tok::kw___if_exists, tok::kw___if_not_exists)) {
+    ParseMicrosoftIfExistsClassDeclaration(TagType, AS);
+    return DeclGroupPtrTy();
+  }
+
+  // Check for extraneous top-level semicolon.
+  if (Tok.is(tok::semi)) {
+    ConsumeExtraSemi(InsideStruct, TagType);
+    return DeclGroupPtrTy();
+  }
+
+  if (Tok.is(tok::annot_pragma_vis)) {
+    HandlePragmaVisibility();
+    return DeclGroupPtrTy();
+  }
+
+  if (Tok.is(tok::annot_pragma_pack)) {
+    HandlePragmaPack();
+    return DeclGroupPtrTy();
+  }
+
+  if (Tok.is(tok::annot_pragma_align)) {
+    HandlePragmaAlign();
+    return DeclGroupPtrTy();
+  }
+
+  if (Tok.is(tok::annot_pragma_ms_pointers_to_members)) {
+    HandlePragmaMSPointersToMembers();
+    return DeclGroupPtrTy();
+  }
+
+  if (Tok.is(tok::annot_pragma_ms_pragma)) {
+    HandlePragmaMSPragma();
+    return DeclGroupPtrTy();
+  }
+
+  // If we see a namespace here, a close brace was missing somewhere.
+  if (Tok.is(tok::kw_namespace)) {
+    DiagnoseUnexpectedNamespace(cast<NamedDecl>(TagDecl));
+    return DeclGroupPtrTy();
+  }
+
+  AccessSpecifier NewAS = getAccessSpecifierIfPresent();
+  if (NewAS != AS_none) {
+    // Current token is a C++ access specifier.
+    AS = NewAS;
+    SourceLocation ASLoc = Tok.getLocation();
+    unsigned TokLength = Tok.getLength();
+    ConsumeToken();
+    AccessAttrs.clear();
+    MaybeParseGNUAttributes(AccessAttrs);
+
+    SourceLocation EndLoc;
+    if (TryConsumeToken(tok::colon, EndLoc)) {
+    } else if (TryConsumeToken(tok::semi, EndLoc)) {
+      Diag(EndLoc, diag::err_expected)
+          << tok::colon << FixItHint::CreateReplacement(EndLoc, ":");
+    } else {
+      EndLoc = ASLoc.getLocWithOffset(TokLength);
+      Diag(EndLoc, diag::err_expected)
+          << tok::colon << FixItHint::CreateInsertion(EndLoc, ":");
+    }
+
+    // The Microsoft extension __interface does not permit non-public
+    // access specifiers.
+    if (TagType == DeclSpec::TST_interface && AS != AS_public) {
+      Diag(ASLoc, diag::err_access_specifier_interface) << (AS == AS_protected);
+    }
+
+    if (Actions.ActOnAccessSpecifier(NewAS, ASLoc, EndLoc,
+                                     AccessAttrs.getList())) {
+      // found another attribute than only annotations
+      AccessAttrs.clear();
+    }
+
+    return DeclGroupPtrTy();
+  }
+
+  if (Tok.is(tok::annot_pragma_openmp))
+    return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, AccessAttrs, TagType,
+                                                      TagDecl);
+
+  // Parse all the comma separated declarators.
+  return ParseCXXClassMemberDeclaration(AS, AccessAttrs.getList());
+}
+
 /// ParseCXXMemberSpecification - Parse the class definition.
 ///
 ///       member-specification:
@@ -2973,101 +3060,14 @@
     CurAS = AS_private;
   else
     CurAS = AS_public;
-  ParsedAttributes AccessAttrs(AttrFactory);
+  ParsedAttributesWithRange AccessAttrs(AttrFactory);
 
   if (TagDecl) {
     // While we still have something to read, read the member-declarations.
-    while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
+    while (Tok.isNot(tok::r_brace) && !isEofOrEom())
       // Each iteration of this loop reads one member-declaration.
-
-      if (getLangOpts().MicrosoftExt && Tok.isOneOf(tok::kw___if_exists,
-                                                    tok::kw___if_not_exists)) {
-        ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS);
-        continue;
-      }
-
-      // Check for extraneous top-level semicolon.
-      if (Tok.is(tok::semi)) {
-        ConsumeExtraSemi(InsideStruct, TagType);
-        continue;
-      }
-
-      if (Tok.is(tok::annot_pragma_vis)) {
-        HandlePragmaVisibility();
-        continue;
-      }
-
-      if (Tok.is(tok::annot_pragma_pack)) {
-        HandlePragmaPack();
-        continue;
-      }
-
-      if (Tok.is(tok::annot_pragma_align)) {
-        HandlePragmaAlign();
-        continue;
-      }
-
-      if (Tok.is(tok::annot_pragma_openmp)) {
-        ParseOpenMPDeclarativeDirective();
-        continue;
-      }
-
-      if (Tok.is(tok::annot_pragma_ms_pointers_to_members)) {
-        HandlePragmaMSPointersToMembers();
-        continue;
-      }
-
-      if (Tok.is(tok::annot_pragma_ms_pragma)) {
-        HandlePragmaMSPragma();
-        continue;
-      }
-
-      // If we see a namespace here, a close brace was missing somewhere.
-      if (Tok.is(tok::kw_namespace)) {
-        DiagnoseUnexpectedNamespace(cast<NamedDecl>(TagDecl));
-        break;
-      }
-
-      AccessSpecifier AS = getAccessSpecifierIfPresent();
-      if (AS != AS_none) {
-        // Current token is a C++ access specifier.
-        CurAS = AS;
-        SourceLocation ASLoc = Tok.getLocation();
-        unsigned TokLength = Tok.getLength();
-        ConsumeToken();
-        AccessAttrs.clear();
-        MaybeParseGNUAttributes(AccessAttrs);
-
-        SourceLocation EndLoc;
-        if (TryConsumeToken(tok::colon, EndLoc)) {
-        } else if (TryConsumeToken(tok::semi, EndLoc)) {
-          Diag(EndLoc, diag::err_expected)
-              << tok::colon << FixItHint::CreateReplacement(EndLoc, ":");
-        } else {
-          EndLoc = ASLoc.getLocWithOffset(TokLength);
-          Diag(EndLoc, diag::err_expected)
-              << tok::colon << FixItHint::CreateInsertion(EndLoc, ":");
-        }
-
-        // The Microsoft extension __interface does not permit non-public
-        // access specifiers.
-        if (TagType == DeclSpec::TST_interface && CurAS != AS_public) {
-          Diag(ASLoc, diag::err_access_specifier_interface)
-            << (CurAS == AS_protected);
-        }
-
-        if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc,
-                                         AccessAttrs.getList())) {
-          // found another attribute than only annotations
-          AccessAttrs.clear();
-        }
-
-        continue;
-      }
-
-      // Parse all the comma separated declarators.
-      ParseCXXClassMemberDeclaration(CurAS, AccessAttrs.getList());
-    }
+      ParseCXXClassMemberDeclarationWithPragmas(
+          CurAS, AccessAttrs, static_cast<DeclSpec::TST>(TagType), TagDecl);
 
     T.consumeClose();
   } else {
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 printOMPDeclareSimdAttr(Decl *D);
 
     /// Print an Objective-C method type in parentheses.
     ///
@@ -202,7 +203,8 @@
     AttrVec &Attrs = D->getAttrs();
     for (AttrVec::const_iterator i=Attrs.begin(), e=Attrs.end(); i!=e; ++i) {
       Attr *A = *i;
-      A->printPretty(Out, Policy);
+      if (!isa<OMPDeclareSimdDeclAttr>(A))
+        A->printPretty(Out, Policy);
     }
   }
 }
@@ -407,7 +409,18 @@
   }
 }
 
+void DeclPrinter::printOMPDeclareSimdAttr(Decl *D) {
+  for (auto *Attr : D->specific_attrs<OMPDeclareSimdDeclAttr>())
+    Attr->printPrettyPragma(Out, Policy);
+  if (D->hasAttr<OMPDeclareSimdDeclAttr>())
+    Indent();
+}
+
 void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
+  if (!D->getDescribedFunctionTemplate() &&
+      !D->isFunctionTemplateSpecialization())
+    printOMPDeclareSimdAttr(D);
+
   CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
   CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D);
   if (!Policy.SuppressSpecifiers) {
@@ -914,11 +927,13 @@
   if (PrintInstantiation) {
     TemplateParameterList *Params = D->getTemplateParameters();
     for (auto *I : D->specializations()) {
+      printOMPDeclareSimdAttr(I);
       PrintTemplateParameters(Params, I->getTemplateSpecializationArgs());
       Visit(I);
     }
   }
 
+  printOMPDeclareSimdAttr(D->getTemplatedDecl());
   return VisitRedeclarableTemplateDecl(D);
 }
 
Index: lib/Sema/SemaOpenMP.cpp
===================================================================
--- lib/Sema/SemaOpenMP.cpp
+++ lib/Sema/SemaOpenMP.cpp
@@ -1336,6 +1336,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");
@@ -2130,6 +2131,7 @@
                                          EndLoc);
     break;
   case OMPD_threadprivate:
+  case OMPD_declare_simd:
     llvm_unreachable("OpenMP Directive is not allowed");
   case OMPD_unknown:
     llvm_unreachable("Unknown OpenMP directive");
@@ -2147,6 +2149,24 @@
   return Res;
 }
 
+Sema::DeclGroupPtrTy
+Sema::ActOnOpenMPDeclareSimdDirective(ArrayRef<OMPClause *> Clauses,
+                                      Decl *ADecl, SourceLocation StartLoc) {
+  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();
+  }
+
+  auto *NewAttr = new (Context) OMPDeclareSimdDeclAttr(
+      SourceRange(StartLoc, StartLoc), Context, /*SI=*/0);
+  ADecl->addAttr(NewAttr);
+  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
@@ -348,6 +348,8 @@
       break;
     }
     break;
+  case OMPD_declare_simd:
+    break;
   case OMPD_unknown:
   case OMPD_threadprivate:
   case OMPD_section:
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -2385,9 +2385,13 @@
                                                  LateParsedAttrList &LateAttrs);
   void MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(Declarator &D,
                                                                VirtSpecifiers &VS);
-  void ParseCXXClassMemberDeclaration(AccessSpecifier AS, AttributeList *Attr,
-                  const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
-                  ParsingDeclRAIIObject *DiagsFromTParams = nullptr);
+  DeclGroupPtrTy ParseCXXClassMemberDeclaration(
+      AccessSpecifier AS, AttributeList *Attr,
+      const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
+      ParsingDeclRAIIObject *DiagsFromTParams = nullptr);
+  DeclGroupPtrTy ParseCXXClassMemberDeclarationWithPragmas(
+      AccessSpecifier &AS, ParsedAttributesWithRange &AccessAttrs,
+      DeclSpec::TST TagType, Decl *TagDecl);
   void ParseConstructorInitializer(Decl *ConstructorDecl);
   MemInitResult ParseMemInitializer(Decl *ConstructorDecl);
   void HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
@@ -2416,7 +2420,10 @@
   //===--------------------------------------------------------------------===//
   // OpenMP: Directives and clauses.
   /// \brief Parses declarative OpenMP directives.
-  DeclGroupPtrTy ParseOpenMPDeclarativeDirective();
+  DeclGroupPtrTy ParseOpenMPDeclarativeDirectiveWithExtDecl(
+      AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
+      DeclSpec::TST TagType = DeclSpec::TST_unspecified,
+      Decl *TagDecl = nullptr);
   /// \brief Parses simple list of variables.
   ///
   /// \param Kind Kind of the directive.
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;
@@ -7875,6 +7876,12 @@
                                         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);
+
   OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
                                          Expr *Expr,
                                          SourceLocation StartLoc,
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -7648,6 +7648,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,10 @@
   "'#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">;
+def err_omp_decl_in_declare_simd : Error<
+  "function 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
@@ -1610,3 +1610,33 @@
 arguments, with arbitrary offsets.
   }];
 }
+
+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
@@ -2064,3 +2064,17 @@
   let SemaHandler = 0;
   let Documentation = [Undocumented];
 }
+
+def OMPDeclareSimdDecl : Attr {
+  let Spellings = [Pragma<"omp", "declare simd">];
+  let Subjects = SubjectList<[Function]>;
+  let SemaHandler = 0;
+  let HasCustomParsing = 1;
+  let Documentation = [OMPDeclareSimdDocs];
+  let AdditionalMembers = [{
+  void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const {
+    OS << "#pragma omp declare simd\n";
+  }
+  }];
+}
+
Index: include/clang/Basic/OpenMPKinds.def
===================================================================
--- include/clang/Basic/OpenMPKinds.def
+++ include/clang/Basic/OpenMPKinds.def
@@ -103,6 +103,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,144 @@
+// 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: }
+//
+
+// Explicit specialization with <C=int>.
+// 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)
+{
+  // Implicit specialization with <C=float>.
+  // 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: float taddpf(float *a, float *b)     {
+  // CHECK-NEXT: return *a + *b;
+  // CHECK-NEXT: }
+  #pragma options align=packed
+  #pragma GCC visibility push(default)
+  #pragma omp declare simd
+  float taddpf(float *a, float *b) { return *a + *b; }
+  #pragma GCC visibility pop
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: #pragma omp declare simd
+// CHECK-NEXT: int tadd(int b) {
+// CHECK-NEXT: return this->x[b] + b;
+// CHECK-NEXT: }
+  #pragma omp declare simd
+  #pragma GCC visibility push(default)
+  #pragma options align=packed
+  #pragma omp declare simd
+  #pragma GCC visibility pop
+  int tadd(int b) { return x[b] + b; }
+
+private:
+  int x[10];
+};
+
+// 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: #pragma omp declare simd
+// CHECK-NEXT: #pragma omp declare simd
+// CHECK-NEXT: int tadd(int b) {
+// CHECK-NEXT: return this->x[b] + 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 options align=packed
+  #pragma GCC visibility push(default)
+  #pragma omp declare simd
+  float taddpf(float *a, float *b) { return *a + *b; }
+  #pragma GCC visibility pop
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: float taddpf(float *a, float *b) {
+// CHECK-NEXT: return *a + *b;
+// CHECK-NEXT: }
+
+  #pragma omp declare simd
+  #pragma GCC visibility push(default)
+  #pragma options align=packed
+  #pragma omp declare simd
+  #pragma GCC visibility pop
+  int tadd(int b) { return x[b] + b; }
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: #pragma omp declare simd
+// CHECK-NEXT: int tadd(int b) {
+// CHECK-NEXT: return this->x[b] + b;
+// CHECK-NEXT: }
+
+private:
+  int x[X];
+};
+// CHECK: };
+
+// CHECK: TVV<16> t16;
+TVV<16> t16;
+
+void f() {
+  float a = 1.0f, b = 2.0f;
+  float r = t16.taddpf(&a, &b);
+  int res = t16.tadd(b);
+}
+
+#endif
Index: test/OpenMP/declare_simd_messages.cpp
===================================================================
--- test/OpenMP/declare_simd_messages.cpp
+++ test/OpenMP/declare_simd_messages.cpp
@@ -0,0 +1,54 @@
+// 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();
+
+// expected-error@+1 {{single declaration is expected with 'declare simd' \
directive}} +#pragma omp declare simd
+int b, c;
+
+#pragma omp declare simd
+template <class C>
+void h(C *hp, C *hp2, C *hq, C *lin) {
+  b = 0;
+}
+
+#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;
+};
+// expected-error@+1 {{function declaration is expected with 'declare simd' \
directive}} +#pragma omp declare simd
+// expected-error@+1 {{function declaration is expected with 'declare simd' \
directive}} +#pragma omp declare simd



_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic