[PATCH] [OPENMP] Initial support for '#pragma omp declare simd' directive.
Hal Finkel
hfinkel at anl.gov
Tue Jul 7 05:47:42 PDT 2015
----- Original Message -----
> From: "Aaron Ballman" <aaron.ballman at gmail.com>
> To: "Hal Finkel" <hfinkel at anl.gov>
> Cc: reviews+D10599+public+2871690e17faf647 at reviews.llvm.org, "Richard Smith" <richard at metafoo.co.uk>, "Eric Stotzer"
> <ejstotzer at gmail.com>, "Michael Wong" <fraggamuffin at gmail.com>, "llvm cfe" <cfe-commits at cs.uiuc.edu>, "Alexey
> Bataev" <a.bataev at hotmail.com>
> Sent: Tuesday, July 7, 2015 7:44:13 AM
> Subject: Re: [PATCH] [OPENMP] Initial support for '#pragma omp declare simd' directive.
>
> On Tue, Jul 7, 2015 at 8:35 AM, Hal Finkel <hfinkel at anl.gov> wrote:
> > ----- 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.
>
> My acquiescence is because the standard says it's a well-formed
> construct, and I'm somewhat hesitant to diagnose on well-formed,
> benign code. But I also agree with your logic on whether this is code
> the user intended or not. I suspect with macros, intention becomes
> slightly more muddy.
>
> Btw, is this expected to work?
Yes, I believe that should work.
-Hal
>
> // a.h
> #pragma omp declare simd
>
> // a.cpp
> #include "a.h"
> void f() {}
>
> ~Aaron
>
> >
> > 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
>
--
Hal Finkel
Assistant Computational Scientist
Leadership Computing Facility
Argonne National Laboratory
More information about the cfe-commits
mailing list