Hal, it is not a problem to emit the diagnostic for naked pragmas, but I expect a lot of troubles with warnings for pragmas with a lot of clauses, mixed different way. But if you really-really think, that we need this stuff, I'll add it. :)

Best regards,
Alexey Bataev
=============
Software Engineer
Intel Compiler Team

07.07.2015 15:35, Hal Finkel пишет:
----- Original Message -----
From: "Aaron Ballman" <aaron.ball...@gmail.com>
To: "Alexey Bataev" <a.bat...@hotmail.com>
Cc: reviews+d10599+public+2871690e17faf...@reviews.llvm.org, "Richard Smith" 
<rich...@metafoo.co.uk>, "Hal Finkel"
<hfin...@anl.gov>, ejstot...@gmail.com, fraggamuf...@gmail.com, "llvm cfe" 
<cfe-commits@cs.uiuc.edu>
Sent: Tuesday, July 7, 2015 7:18:04 AM
Subject: Re: [PATCH] [OPENMP] Initial support for '#pragma omp declare simd' 
directive.

On Tue, Jul 7, 2015 at 7:40 AM, Bataev, Alexey <a.bat...@hotmail.com>
wrote:
I tend to agree with hal that this should be a warning. It's low
priority, definitely, but silently allowing the programmer to get
away
with incorrect code doesn't seem beneficial to anyone. It would
also
point out the two other places in your tests that have this exact
same
code pattern with no additional testing benefit. ;-)

This code is correct, OpenMP standard allows to mark the same
function many
times with the same pragma. Here is an excerpt:
Eww, but fair enough. :-)
Okay, but this was not my point. I did not say it should be an error. Warnings 
are not for incorrect code, they are for correct code were we feel the user 
*probably* intended something else. If a function is marked with several 
identical 'omp declare simd' pragmas, is that likely to be intentional or a 
mistake of some kind?

Even if we decide on a warning here, I'm fine with adding it in follow-up. I 
think it would need to account for the other clauses as well anyway.

Thanks again,
Hal

#pragma omp declare simd [clause[[,] clause] ...] new-line
[#pragma omp declare simd [clause[[,] clause] ...] new-line]
[...]
function definition or declaration

There may be multiple declare simd directives for a function (C,
C++,
Fortran) or subroutine (Fortran).

I would also like to see a test for #pragma omp declare simd that
is
at the end of the TU with no futher statements (to ensure it gets
diagnosed).

Ok, will be added.

Copy paste error?
Nope, I have to verify that the compiler allows to mark the same
function
several times with '#pragma omp declare simd' according to
standard.
Fair, but we don't need that tested multiple times.

This attribute has a pragma spelling where the namespace is openmp
and
the name is declare. It's the same pattern used by the loop hint
and
init_seg pragmas.

Can't add spellings, it breaks -ast-print mode (pragmas are printed
just
like attributes, directly after function declaration).
That means -ast-print is broken and should be fixed.

Please document this attribute as it does have a pragma spelling.

Will add

This attribute appears to be missing its Subjects clause as well.
That's not information we currently care about for pragmas, but I
would like the declarative part of the attribute to match the
semantic
expectations.

Will add too.

I've not seen any tests for ObjC, so does this really apply to
methods?
I'll fix this message.

Capitalize the first word in the documentation part of the
sentence.
Thanks, fixed.

Drop the virtual, add override.
Fixed.

Drop the "if"
Fixed

Can you use a range-based for loop please?
Done

This is not an implicit attribute because it's the direct result
of
the user typing something in source code.
Fixed.

This really weirds me out. That means this function doesn't parse
just
the pragma, it also parses any external declaration.
Yes, we have to parse function right after pragma to be able
correctly
handle clauses associated with this pragma. These clauses may have
refernces
to function arguments and because of that we have to parse the
function
first and only then the pragma itself.
Can we update the name of the function to suggest this?

The comments don't look correct here.
Missed this one, thanks.

Is this safe to assert in a parsing method, or should this be
diagnosed?
There always must be at least one token if the compiler works
correctly -
tok::annot_pragma_openmp. No need to diagnose.
Good deal, thank you!

Has this situation already been diagnosed? If so, then why are we
generating the tokens in a way that require this work? And if not,
are
we missing a diagnostic here?
Yes, this was diagnosed already. We need to remove cached tokens,
so just
skip them.
Thank you!

~Aaron

Attribute is not implicit.
Fixed.

Best regards,
Alexey Bataev
=============
Software Engineer
Intel Compiler Team

06.07.2015 16:13, Aaron Ballman пишет:

On Mon, Jun 22, 2015 at 7:35 AM, Alexey Bataev
<a.bat...@hotmail.com>
wrote:
Hi rsmith, aaron.ballman, hfinkel, ejstotzer, fraggamuffin,

Inital 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 aplied 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 appplied to.
If pragma is applied to method declared/defined in the class
lexical
context, then the delayed parsing procedure is used.
Also delayed parsing is used for poarsing a pragma itself,
because this
directive has several clauses that can reference arguments of the
associated
function/method.

http://reviews.llvm.org/D10599

Files:
    include/clang/AST/ASTMutationListener.h
    include/clang/Basic/Attr.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

EMAIL PREFERENCES
    http://reviews.llvm.org/settings/panel/emailpreferences/
Index: test/OpenMP/declare_simd_messages.cpp
===================================================================
--- test/OpenMP/declare_simd_messages.cpp
+++ test/OpenMP/declare_simd_messages.cpp
@@ -0,0 +1,45 @@
+// 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 or methods only}}
+#pragma omp declare simd
+int a;
+// expected-error@+2 {{'#pragma omp declare simd' can be applied
to
functions or methods 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

I tend to agree with hal that this should be a warning. It's low
priority, definitely, but silently allowing the programmer to get
away
with incorrect code doesn't seem beneficial to anyone. It would
also
point out the two other places in your tests that have this exact
same
code pattern with no additional testing benefit. ;-)

+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;
+};

I would also like to see a test for #pragma omp declare simd that
is
at the end of the TU with no futher statements (to ensure it gets
diagnosed).

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

Copy paste error?

+  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_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

Copy paste error?

+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: include/clang/Basic/OpenMPKinds.def
===================================================================
--- include/clang/Basic/OpenMPKinds.def
+++ include/clang/Basic/OpenMPKinds.def
@@ -94,6 +94,7 @@
   OPENMP_DIRECTIVE_EXT(parallel_for_simd, "parallel for simd")
   OPENMP_DIRECTIVE_EXT(parallel_sections, "parallel sections")
   OPENMP_DIRECTIVE_EXT(for_simd, "for simd")
+OPENMP_DIRECTIVE_EXT(declare_simd, "declare simd")

   // OpenMP clauses.
   OPENMP_CLAUSE(if, OMPIfClause)
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -2044,3 +2044,19 @@
     let SemaHandler = 0;
     let Documentation = [Undocumented];
   }
+
+def OMPDeclareSimdDecl : InheritableAttr {
+  // This attribute has no spellings as it is only ever created
implicitly.
+  let Spellings = [];

This attribute has a pragma spelling where the namespace is openmp
and
the name is declare. It's the same pattern used by the loop hint
and
init_seg pragmas.

+  let SemaHandler = 0;
+  let Documentation = [Undocumented];

Please document this attribute as it does have a pragma spelling.

+  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; }

This attribute appears to be missing its Subjects clause as well.
That's not information we currently care about for pragmas, but I
would like the declarative part of the attribute to match the
semantic
expectations.

+  }];
+}
+
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/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -7601,6 +7601,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 or
methods
only">;

I've not seen any tests for ObjC, so does this really apply to
methods?

   } // end of OpenMP category

   let CategoryName = "Related Result Type Issue" in {
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;
@@ -7758,6 +7759,13 @@
                                          Stmt *AStmt,
                                          SourceLocation
StartLoc,
                                          SourceLocation EndLoc);

+  /// \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/AST/ASTMutationListener.h
===================================================================
--- include/clang/AST/ASTMutationListener.h
+++ include/clang/AST/ASTMutationListener.h
@@ -113,6 +113,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.

Capitalize the first word in the documentation part of the
sentence.

+  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/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -1019,6 +1019,19 @@
       CachedTokens *ExceptionSpecTokens;
     };

+  /// \brief An OpenMP declaration inside a class.
+  struct LateParsedOpenMPDeclaration : public
LateParsedDeclaration {
+    explicit LateParsedOpenMPDeclaration(Parser *P) : Self(P) {}
+
+    virtual void ParseLexedMethodDeclarations();

Drop the virtual, add 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).
@@ -2364,7 +2377,13 @@

//===--------------------------------------------------------------------===//
     // OpenMP: Directives and clauses.
     /// \brief Parses declarative OpenMP directives.
-  DeclGroupPtrTy ParseOpenMPDeclarativeDirective();
+  /// \param Level Current level of declarative directive, in
case if it
is

Drop the "if"

+  /// 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/Serialization/ASTWriter.h
===================================================================
--- include/clang/Serialization/ASTWriter.h
+++ include/clang/Serialization/ASTWriter.h
@@ -859,6 +859,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;
   };

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;

   private:
@@ -221,6 +222,11 @@
     for (size_t i = 0, e = Listeners.size(); i != e; ++i)
       Listeners[i]->DeclarationMarkedOpenMPThreadPrivate(D);
   }
+void
MultiplexASTMutationListener::DeclarationMarkedOpenMPDeclareSimd(
+    const Decl *D) {
+  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+    Listeners[i]->DeclarationMarkedOpenMPDeclareSimd(D);
+}

Can you use a range-based for loop please?

   void
   MultiplexASTMutationListener::RedefinedHiddenDefinition(const
NamedDecl *D,
                                                                Module
                                                                *M)
{
     for (auto *L : Listeners)
Index: lib/Basic/OpenMPKinds.cpp
===================================================================
--- lib/Basic/OpenMPKinds.cpp
+++ lib/Basic/OpenMPKinds.cpp
@@ -324,6 +324,8 @@
         break;
       }
       break;
+  case OMPD_declare_simd:
+    break;
     case OMPD_unknown:
     case OMPD_threadprivate:
     case OMPD_section:
Index: lib/Sema/SemaOpenMP.cpp
===================================================================
--- lib/Sema/SemaOpenMP.cpp
+++ lib/Sema/SemaOpenMP.cpp
@@ -1283,6 +1283,7 @@
     case OMPD_barrier:
     case OMPD_taskwait:
     case OMPD_flush:
+  case OMPD_declare_simd:
       llvm_unreachable("OpenMP Directive is not allowed");
     case OMPD_unknown:
       llvm_unreachable("Unknown OpenMP directive");
@@ -1989,6 +1990,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");
@@ -2006,6 +2008,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();
+  }

Elide braces.

+  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 = OMPDeclareSimdDeclAttr::CreateImplicit(
+        Context, 1, LastDirective, SourceRange(StartLoc,
StartLoc));

This is not an implicit attribute because it's the direct result
of
the user typing something in source code.

+    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/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.
       ///
@@ -405,7 +406,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) {
@@ -912,11 +928,17 @@
     if (PrintInstantiation) {
       TemplateParameterList *Params = D->getTemplateParameters();
       for (auto *I : D->specializations()) {
+      if (auto *Attr = I->getAttr<OMPDeclareSimdDeclAttr>()) {
+        print(Attr);
+      }

Elide braces.

         PrintTemplateParameters(Params,
I->getTemplateSpecializationArgs());
         Visit(I);
       }
     }

+  if (auto *Attr =
D->getTemplatedDecl()->getAttr<OMPDeclareSimdDeclAttr>()) {
+    print(Attr);
+  }

Elide braces.

     return VisitRedeclarableTemplateDecl(D);
   }

Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -2942,7 +2942,7 @@
         }

         if (Tok.is(tok::annot_pragma_openmp)) {
-        ParseOpenMPDeclarativeDirective();
+        ParseOpenMPDeclarativeDirective(/*IsInTagDecl=*/true);
           continue;
         }

Index: lib/Parse/ParseOpenMP.cpp
===================================================================
--- lib/Parse/ParseOpenMP.cpp
+++ lib/Parse/ParseOpenMP.cpp
@@ -30,18 +30,26 @@
     // E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd
     // TODO: add other combined directives in topological order.
     const OpenMPDirectiveKind F[][3] = {
-    { OMPD_for, OMPD_simd, OMPD_for_simd },
-    { OMPD_parallel, OMPD_for, OMPD_parallel_for },
-    { OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd },
-    { OMPD_parallel, OMPD_sections, OMPD_parallel_sections }
+      {OMPD_unknown /*declare*/, OMPD_simd, OMPD_declare_simd},
+      {OMPD_for, OMPD_simd, OMPD_for_simd},
+      {OMPD_parallel, OMPD_for, OMPD_parallel_for},
+      {OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd},
+      {OMPD_parallel, OMPD_sections, OMPD_parallel_sections}
     };
     auto Tok = P.getCurToken();
     auto DKind =
         Tok.isAnnotation()
             ? OMPD_unknown
             :
getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
+  bool TokenMatched = false;
     for (unsigned i = 0; i < llvm::array_lengthof(F); ++i) {
-    if (DKind == F[i][0]) {
+    if (!Tok.isAnnotation() && DKind == OMPD_unknown) {
+      TokenMatched =
+          (i == 0) &&
!P.getPreprocessor().getSpelling(Tok).compare("declare");
+    } else {
+      TokenMatched = DKind == F[i][0];
+    }

Elide braces.

+    if (TokenMatched) {
         Tok = P.getPreprocessor().LookAhead(0);
         auto SDKind =
             Tok.isAnnotation()
@@ -61,13 +69,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:
@@ -85,6 +97,86 @@
         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();
+    }

Elide braces.

+    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);

This really weirds me out. That means this function doesn't parse
just
the pragma, it also parses any external declaration.

+    }
+    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);
+
+    Actions.StartOpenMPClauses();
+    while (Tok.isNot(tok::annot_pragma_openmp_end)) {
+      OpenMPClauseKind CKind = Tok.isAnnotation()
+                                   ? OMPC_unknown
+                                   :
getOpenMPClauseKind(PP.getSpelling(Tok));
+      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.EndOpenMPClauses();
+    // 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;
@@ -118,6 +210,69 @@
     return DeclGroupPtrTy();
   }

+/// \brief Late parsing of declarative OpenMP directives.
+///
+///       threadprivate-directive:
+///         annot_pragma_openmp 'threadprivate'
simple-variable-list

The comments don't look correct here.

+///         annot_pragma_openmp_end
+///
+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!");

Is this safe to assert in a parsing method, or should this be
diagnosed?

+  // 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();

Has this situation already been diagnosed? If so, then why are we
generating the tokens in a way that require this work? And if not,
are
we missing a diagnostic here?

+  }
+}
+
   /// \brief Parsing of declarative or executable OpenMP
   directives.
   ///
   ///       threadprivate-directive:
@@ -274,6 +429,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/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/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -3888,6 +3888,14 @@
             Reader.Context, ReadSourceRange(Record, Idx)));
         break;

+    case UPD_DECL_MARKED_OPENMP_DECLARE_SIMD: {
+      auto *Attr = OMPDeclareSimdDeclAttr::CreateImplicit(
+          Reader.Context, Record[Idx++], Record[Idx++] != 0,
+          ReadSourceRange(Record, Idx));

Attribute is not implicit.

+      D->addAttr(Attr);
+      break;
+    }
+
       case UPD_DECL_EXPORTED:
         unsigned SubmoduleID = readSubmoduleID(Record, Idx);
         auto *Exported = cast<NamedDecl>(D);
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
   };

Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -4615,6 +4615,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;
@@ -5761,6 +5769,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");



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

Reply via email to