]> granicus.if.org Git - clang/commitdiff
[OPENMP 4.0] Initial support for '#pragma omp declare simd' directive.
authorAlexey Bataev <a.bataev@hotmail.com>
Wed, 30 Mar 2016 10:43:55 +0000 (10:43 +0000)
committerAlexey Bataev <a.bataev@hotmail.com>
Wed, 30 Mar 2016 10:43:55 +0000 (10:43 +0000)
Initial parsing/sema/serialization/deserialization support for '#pragma
omp declare simd' directive.
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.
If the function has any declarations, then the declare simd construct
for any declaration that has one must be equivalent to the one specified
 for the definition. Otherwise, the result is unspecified.
This pragma can be applied many times to the same declaration.
Internally this pragma is represented as an attribute. But we need special processing for this pragma because it must be used before function declaration, this directive is applied to.
Differential Revision: http://reviews.llvm.org/D10599

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@264853 91177308-0d34-0410-b5e6-96231b3b80d8

16 files changed:
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/Basic/OpenMPKinds.cpp
lib/Parse/ParseDecl.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Parse/ParseOpenMP.cpp
lib/Parse/Parser.cpp
lib/Sema/SemaOpenMP.cpp
test/OpenMP/declare_simd_ast_print.c [new file with mode: 0644]
test/OpenMP/declare_simd_ast_print.cpp [new file with mode: 0644]
test/OpenMP/declare_simd_messages.cpp [new file with mode: 0644]

index c7a797cdd13e5a743a69224e51adb8154dd6be6a..33d90b094fac4edc6d67680f82a028128f2f26df 100644 (file)
@@ -2244,6 +2244,17 @@ def OMPCaptureNoInit : InheritableAttr {
   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 {}
+  }];
+}
+
 def InternalLinkage : InheritableAttr {
   let Spellings = [GNU<"internal_linkage">, CXX11<"clang", "internal_linkage">];
   let Subjects = SubjectList<[Var, Function, CXXRecord]>;
index 9a53feb27b25f67e4f18398b0032ebd6caa85fae..24803c15be0fbb22d8906156594312bb4d99a65d 100644 (file)
@@ -1888,6 +1888,41 @@ 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 in 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
+
+  }];
+}
+
 def NotTailCalledDocs : Documentation {
   let Category = DocCatFunction;
   let Content = [{
index 2f30e43847d3153de8c5d348389d61a7e51632b6..79f7437c7534617fca52a253bef519b26d2db6e5 100644 (file)
@@ -953,6 +953,8 @@ def err_omp_expected_identifier_for_critical : Error<
   "expected identifier specifying the name of the 'omp critical' directive">;
 def err_omp_expected_reduction_identifier : Error<
   "expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&', or '||'">;
+def err_omp_decl_in_declare_simd : Error<
+  "function declaration is expected after 'declare simd' directive">;
 def err_omp_unknown_map_type : Error<
   "incorrect map type, expected one of 'to', 'from', 'tofrom', 'alloc', 'release', or 'delete'">;
 def err_omp_unknown_map_type_modifier : Error<
index b465173b198185ef3c43b840251f77acfd9a612a..cac2a117272c2821800e68fceb42f1ba8d4383b4 100644 (file)
@@ -8039,6 +8039,10 @@ def err_omp_single_copyprivate_with_nowait : Error<
   "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_single_decl_in_declare_simd : Error<
+  "single declaration is expected after 'declare simd' directive">;
+def err_omp_function_expected : Error<
+  "'#pragma omp declare simd' can only be applied to functions">;
 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 030824d2c1504cc6f1b6400b6a54ca6e76288d8d..b2d2af6f079210cc9ad598f2c544f78618d0b825 100644 (file)
@@ -156,6 +156,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_reduction, "declare reduction")
+OPENMP_DIRECTIVE_EXT(declare_simd, "declare simd")
 OPENMP_DIRECTIVE(taskloop)
 OPENMP_DIRECTIVE_EXT(taskloop_simd, "taskloop simd")
 OPENMP_DIRECTIVE(distribute)
index ecfd3a382e7828309e950456a8892eb7442047b8..430598205f460a796de7480b45246e17e91d1c6b 100644 (file)
@@ -2428,7 +2428,7 @@ private:
       ParsingDeclRAIIObject *DiagsFromTParams = nullptr);
   DeclGroupPtrTy ParseCXXClassMemberDeclarationWithPragmas(
       AccessSpecifier &AS, ParsedAttributesWithRange &AccessAttrs,
-      DeclSpec::TST TagType, Decl *TagDecl);
+      DeclSpec::TST TagType, Decl *Tag);
   void ParseConstructorInitializer(Decl *ConstructorDecl);
   MemInitResult ParseMemInitializer(Decl *ConstructorDecl);
   void HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
@@ -2457,7 +2457,10 @@ private:
   //===--------------------------------------------------------------------===//
   // OpenMP: Directives and clauses.
   /// \brief Parses declarative OpenMP directives.
-  DeclGroupPtrTy ParseOpenMPDeclarativeDirective(AccessSpecifier AS);
+  DeclGroupPtrTy ParseOpenMPDeclarativeDirectiveWithExtDecl(
+      AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
+      DeclSpec::TST TagType = DeclSpec::TST_unspecified,
+      Decl *TagDecl = nullptr);
   /// \brief Parse 'omp declare reduction' construct.
   DeclGroupPtrTy ParseOpenMPDeclareReductionDirective(AccessSpecifier AS);
   /// \brief Parses simple list of variables.
index eb234c4856688f15a56a3000cb193e1bc20ab879..9b9b0e3c4c80be823e1f33f482badcdd55320582 100644 (file)
@@ -146,6 +146,7 @@ namespace clang {
   class ObjCProtocolDecl;
   class OMPThreadPrivateDecl;
   class OMPDeclareReductionDecl;
+  class OMPDeclareSimdDecl;
   class OMPClause;
   struct OverloadCandidate;
   class OverloadCandidateSet;
@@ -8087,6 +8088,11 @@ public:
       SourceLocation EndLoc,
       llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA);
 
+  /// \brief Called on well-formed '\#pragma omp declare simd' after parsing of
+  /// the associated method/function.
+  DeclGroupPtrTy ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG,
+                                                 SourceLocation StartLoc);
+
   OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
                                          Expr *Expr,
                                          SourceLocation StartLoc,
index 3b5bc56036b242a3a775bb430b33003e1ef8fdb5..fa40d016c9eaa8d089a3597c5a44af66852d714d 100644 (file)
@@ -485,6 +485,8 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
       break;
     }
     break;
+  case OMPD_declare_simd:
+    break;
   case OMPD_cancel:
     switch (CKind) {
 #define OPENMP_CANCEL_CLAUSE(Name)                                             \
index fef5d8d4441a10623c7b232043dc96d697391c98..84204aadb189bd1d34b2352527d4938c7b08b8ab 100644 (file)
@@ -3654,8 +3654,10 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
     }
 
     if (Tok.is(tok::annot_pragma_openmp)) {
-      // There may be declared reduction operator inside structure/union.
-      (void)ParseOpenMPDeclarativeDirective(AS_public);
+      // Result can be ignored, because it must be always empty.
+      AccessSpecifier AS = AS_none;
+      ParsedAttributesWithRange Attrs(AttrFactory);
+      (void)ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs);
       continue;
     }
 
index 9d8106361e693787e928d86ab9d92315e96a329f..cfe49ca2cc3a00bf985a0715bb7b4e3738823805 100644 (file)
@@ -2919,7 +2919,8 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas(
   }
 
   if (Tok.is(tok::annot_pragma_openmp))
-    return ParseOpenMPDeclarativeDirective(AS);
+    return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, AccessAttrs, TagType,
+                                                      TagDecl);
 
   // Parse all the comma separated declarators.
   return ParseCXXClassMemberDeclaration(AS, AccessAttrs.getList());
index 7a924b4ce2bfa49c6d9fd9b179fbdd637d3dd015..96cf37912f2ab3b84cfc76b1a8b108a58cd73fa4 100644 (file)
@@ -65,6 +65,7 @@ static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) {
   static const unsigned F[][3] = {
     { OMPD_cancellation, OMPD_point, OMPD_cancellation_point },
     { OMPD_declare, OMPD_reduction, OMPD_declare_reduction },
+    { OMPD_declare, OMPD_simd, OMPD_declare_simd },
     { OMPD_target, OMPD_data, OMPD_target_data },
     { OMPD_target, OMPD_enter, OMPD_target_enter },
     { OMPD_target, OMPD_exit, OMPD_target_exit },
@@ -332,8 +333,14 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
 ///        annot_pragma_openmp 'declare' 'reduction' [...]
 ///        annot_pragma_openmp_end
 ///
-Parser::DeclGroupPtrTy
-Parser::ParseOpenMPDeclarativeDirective(AccessSpecifier AS) {
+///       declare-simd-directive:
+///         annot_pragma_openmp 'declare simd' {<clause> [,]}
+///         annot_pragma_openmp_end
+///         <function declaration/definition>
+///
+Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
+    AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
+    DeclSpec::TST TagType, Decl *Tag) {
   assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
   ParenBraceBracketBalancer BalancerRAIIObj(*this);
 
@@ -373,6 +380,47 @@ Parser::ParseOpenMPDeclarativeDirective(AccessSpecifier AS) {
       return Res;
     }
     break;
+  case OMPD_declare_simd: {
+    // The syntax is:
+    // { #pragma omp declare simd }
+    // <function-declaration-or-definition>
+    //
+
+    ConsumeToken();
+    // 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);
+      while (Tok.isNot(tok::annot_pragma_openmp_end))
+        ConsumeAnyToken();
+    }
+    // Skip the last annot_pragma_openmp_end.
+    ConsumeToken();
+
+    DeclGroupPtrTy Ptr;
+    if (Tok.is(tok::annot_pragma_openmp)) {
+      Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, TagType, Tag);
+    } else if (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
+      // Here we expect to see some function declaration.
+      if (AS == AS_none) {
+        assert(TagType == DeclSpec::TST_unspecified);
+        MaybeParseCXX11Attributes(Attrs);
+        MaybeParseMicrosoftAttributes(Attrs);
+        ParsingDeclSpec PDS(*this);
+        Ptr = ParseExternalDeclaration(Attrs, &PDS);
+      } else {
+        Ptr =
+            ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType, Tag);
+      }
+    }
+    if (!Ptr) {
+      Diag(Loc, diag::err_omp_decl_in_declare_simd);
+      return DeclGroupPtrTy();
+    }
+
+    return Actions.ActOnOpenMPDeclareSimdDirective(Ptr, Loc);
+  }
   case OMPD_unknown:
     Diag(Tok, diag::err_omp_unknown_directive);
     break;
@@ -627,6 +675,11 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
     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 07f60cbbe167b8530ee949dcb9581f835fb7e997..9ed2d72fcd9d081abea655fe0d6a4ff774133dc1 100644 (file)
@@ -659,8 +659,10 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
   case tok::annot_pragma_opencl_extension:
     HandlePragmaOpenCLExtension();
     return nullptr;
-  case tok::annot_pragma_openmp:
-    return ParseOpenMPDeclarativeDirective(/*AS=*/AS_none);
+  case tok::annot_pragma_openmp: {
+    AccessSpecifier AS = AS_none;
+    return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, attrs);
+  }
   case tok::annot_pragma_ms_pointers_to_members:
     HandlePragmaMSPointersToMembers();
     return nullptr;
index 8ce67c8f9c28640e3265c7efc6d78ec11254565a..3c50eec3a67173620f65ca02c7a1ec85254625bd 100644 (file)
@@ -1701,6 +1701,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
   case OMPD_target_enter_data:
   case OMPD_target_exit_data:
   case OMPD_declare_reduction:
+  case OMPD_declare_simd:
     llvm_unreachable("OpenMP Directive is not allowed");
   case OMPD_unknown:
     llvm_unreachable("Unknown OpenMP directive");
@@ -3155,6 +3156,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
     break;
   case OMPD_threadprivate:
   case OMPD_declare_reduction:
+  case OMPD_declare_simd:
     llvm_unreachable("OpenMP Directive is not allowed");
   case OMPD_unknown:
     llvm_unreachable("Unknown OpenMP directive");
@@ -3175,6 +3177,32 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
   return Res;
 }
 
+Sema::DeclGroupPtrTy
+Sema::ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG,
+                                      SourceLocation StartLoc) {
+  if (!DG || DG.get().isNull())
+    return DeclGroupPtrTy();
+
+  if (!DG.get().isSingleDecl()) {
+    Diag(StartLoc, diag::err_omp_single_decl_in_declare_simd);
+    return DG;
+  }
+  auto *ADecl = DG.get().getSingleDecl();
+  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 = OMPDeclareSimdDeclAttr::CreateImplicit(
+      Context, SourceRange(StartLoc, StartLoc));
+  ADecl->addAttr(NewAttr);
+  return ConvertDeclToDeclGroup(ADecl);
+}
+
 StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
                                               Stmt *AStmt,
                                               SourceLocation StartLoc,
diff --git a/test/OpenMP/declare_simd_ast_print.c b/test/OpenMP/declare_simd_ast_print.c
new file mode 100644 (file)
index 0000000..d2b91eb
--- /dev/null
@@ -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) __attribute__((cold));
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: #pragma omp declare simd
+// CHECK-NEXT: void add_1(float *d, float *s1, float *s2) __attribute__((cold))
+
+#endif
diff --git a/test/OpenMP/declare_simd_ast_print.cpp b/test/OpenMP/declare_simd_ast_print.cpp
new file mode 100644 (file)
index 0000000..aff2c94
--- /dev/null
@@ -0,0 +1,131 @@
+// 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) __attribute__((cold));
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: void add_1(float *d) __attribute__((cold));
+//
+
+#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) __attribute__((cold))    {
+  // CHECK-NEXT: return a + b;
+  // CHECK-NEXT: }
+  #pragma omp declare simd
+  int add(int a, int b) __attribute__((cold)) { return a + b; }
+
+  // CHECK: #pragma omp declare simd
+  // CHECK-NEXT: float taddpf(float *a, float *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: #pragma omp declare simd
+// CHECK-NEXT: int tadd(int b) {
+// CHECK-NEXT: return this->x[b] + b;
+// CHECK-NEXT: }
+  #pragma omp declare simd
+  #pragma omp declare simd
+  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 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: }
+
+  #pragma omp declare simd
+  #pragma omp declare simd
+  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
diff --git a/test/OpenMP/declare_simd_messages.cpp b/test/OpenMP/declare_simd_messages.cpp
new file mode 100644 (file)
index 0000000..2085bfc
--- /dev/null
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -verify -fopenmp -x c++ -std=c++11 -fms-extensions %s
+
+// expected-error@+1 {{expected an OpenMP directive}}
+#pragma omp declare
+
+// expected-error@+2 {{'#pragma omp declare simd' can only be applied to functions}}
+#pragma omp declare simd
+int a;
+// expected-error@+2 {{'#pragma omp declare simd' can only be applied to functions}}
+#pragma omp declare simd
+#pragma omp threadprivate(a)
+int var;
+#pragma omp threadprivate(var)
+
+// expected-error@+2 {{expected an OpenMP directive}} expected-error@+1 {{function declaration is expected after 'declare simd' directive}}
+#pragma omp declare simd
+#pragma omp declare
+
+// expected-error@+3 {{function declaration is expected after 'declare simd' directive}}
+// expected-error@+1 {{function declaration is expected after 'declare simd' directive}}
+#pragma omp declare simd
+#pragma omp declare simd
+#pragma options align=packed
+int main();
+
+// expected-error@+3 {{function declaration is expected after 'declare simd' directive}}
+// expected-error@+1 {{function declaration is expected after 'declare simd' directive}}
+#pragma omp declare simd
+#pragma omp declare simd
+#pragma init_seg(compiler)
+int main();
+
+// expected-error@+1 {{single declaration is expected after '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 {
+// expected-error@+2 {{function declaration is expected after 'declare simd' directive}}
+#pragma init_seg(compiler)
+#pragma omp declare simd
+#pragma init_seg(compiler)
+  void h(T *hp) {
+// expected-error@+1 {{unexpected OpenMP directive '#pragma omp declare simd'}}
+#pragma omp declare simd
+    *hp = *t;
+  }
+
+private:
+  T t;
+};
+
+namespace N {
+  // expected-error@+1 {{function declaration is expected after 'declare simd' directive}}
+  #pragma omp declare simd
+}
+// expected-error@+1 {{function declaration is expected after 'declare simd' directive}}
+#pragma omp declare simd
+// expected-error@+1 {{function declaration is expected after 'declare simd' directive}}
+#pragma omp declare simd