[PATCH] [OPENMP] Initial support for '#pragma omp declare simd' directive.

Aaron Ballman aaron.ballman at gmail.com
Tue Jul 7 05:57:30 PDT 2015


On Tue, Jul 7, 2015 at 8:56 AM, Hal Finkel <hfinkel at anl.gov> wrote:
> ----- Original Message -----
>> From: "Alexey Bataev" <a.bataev at hotmail.com>
>> To: "Hal Finkel" <hfinkel at anl.gov>, "Aaron Ballman" <aaron.ballman at gmail.com>
>> Cc: reviews+D10599+public+2871690e17faf647 at reviews.llvm.org, "Richard Smith" <richard at metafoo.co.uk>,
>> ejstotzer at gmail.com, fraggamuffin at gmail.com, "llvm cfe" <cfe-commits at cs.uiuc.edu>
>> Sent: Tuesday, July 7, 2015 7:52:02 AM
>> Subject: Re: [PATCH] [OPENMP] Initial support for '#pragma omp declare simd' directive.
>>
>> 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. :)
>
> Let's wait and think about it :)
>
> My underlying thought is that a warning will catch cases where the user intended to declare the function for, say, 2 different simd lengths, but actually just repeated one simd length twice. Regardless, let's revisit this once we have support for some clauses here.

Agreed. :-)

~Aaron

>
> Thanks again,
> Hal
>
>>
>> Best regards,
>> Alexey Bataev
>> =============
>> Software Engineer
>> Intel Compiler Team
>>
>> 07.07.2015 15:35, Hal Finkel пишет:
>> > ----- Original Message -----
>> >> From: "Aaron Ballman" <aaron.ballman at gmail.com>
>> >> To: "Alexey Bataev" <a.bataev at hotmail.com>
>> >> Cc: reviews+D10599+public+2871690e17faf647 at reviews.llvm.org,
>> >> "Richard Smith" <richard at metafoo.co.uk>, "Hal Finkel"
>> >> <hfinkel at anl.gov>, ejstotzer at gmail.com, fraggamuffin at gmail.com,
>> >> "llvm cfe" <cfe-commits at 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.bataev at 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.bataev at 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 at +1 {{expected an OpenMP directive}}
>> >>>> +#pragma omp declare
>> >>>> +
>> >>>> +// expected-error at +2 {{'#pragma omp declare simd' can be
>> >>>> applied
>> >>>> to
>> >>>> functions or methods only}}
>> >>>> +#pragma omp declare simd
>> >>>> +int a;
>> >>>> +// expected-error at +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 at +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 at +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");
>> >>>
>>
>>
>
> --
> Hal Finkel
> Assistant Computational Scientist
> Leadership Computing Facility
> Argonne National Laboratory




More information about the cfe-commits mailing list