Hi rsmith, aaron.ballman, hfinkel, ejstotzer, fraggamuffin, Inital parsing/sema/serialization/deserialization support for '#pragma omp declare simd' directive. The declare simd construct can be applied to a function to enable the creation of one or more versions that can process multiple arguments using SIMD instructions from a single invocation from a SIMD loop. If the function has any declarations, then the declare simd construct for any declaration that has one must be equivalent to the one specified for the definition. Otherwise, the result is unspecified. This pragma can be aplied many times to the same declaration. Internally this pragma is represented as an attribute. But we need special processing for this pragma because it must be used before function declaration, this directive is appplied to. If pragma is applied to method declared/defined in the class lexical context, then the delayed parsing procedure is used. Also delayed parsing is used for poarsing a pragma itself, because this directive has several clauses that can reference arguments of the associated function/method.
http://reviews.llvm.org/D10599 Files: include/clang/AST/ASTMutationListener.h include/clang/Basic/Attr.td include/clang/Basic/DiagnosticParseKinds.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/OpenMPKinds.def include/clang/Parse/Parser.h include/clang/Sema/Sema.h include/clang/Serialization/ASTWriter.h lib/AST/DeclPrinter.cpp lib/Basic/OpenMPKinds.cpp lib/Frontend/MultiplexConsumer.cpp lib/Parse/ParseDeclCXX.cpp lib/Parse/ParseOpenMP.cpp lib/Parse/Parser.cpp lib/Sema/SemaOpenMP.cpp lib/Serialization/ASTCommon.h lib/Serialization/ASTReaderDecl.cpp lib/Serialization/ASTWriter.cpp test/OpenMP/declare_simd_ast_print.c test/OpenMP/declare_simd_ast_print.cpp test/OpenMP/declare_simd_messages.cpp EMAIL PREFERENCES http://reviews.llvm.org/settings/panel/emailpreferences/
Index: test/OpenMP/declare_simd_messages.cpp =================================================================== --- test/OpenMP/declare_simd_messages.cpp +++ test/OpenMP/declare_simd_messages.cpp @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -x c++ -std=c++11 %s + +// expected-error@+1 {{expected an OpenMP directive}} +#pragma omp declare + +// expected-error@+2 {{'#pragma omp declare simd' can be applied to functions or methods only}} +#pragma omp declare simd +int a; +// expected-error@+2 {{'#pragma omp declare simd' can be applied to functions or methods only}} +#pragma omp declare simd +#pragma omp threadprivate(a) +int var; +#pragma omp threadprivate(var) + +// expected-error@+2 {{expected an OpenMP directive}} +#pragma omp declare simd +#pragma omp declare + +#pragma omp declare simd +#pragma omp declare simd +int main(); + +#pragma omp declare simd +template <class C> +void h(C *hp, C *hp2, C *hq, C *lin) { +} + +#pragma omp declare simd +template <> +void h(int *hp, int *hp2, int *hq, int *lin) { + h((float *)hp, (float *)hp2, (float *)hq, (float *)lin); +} + +template <class T> +struct St { +#pragma omp declare simd + void h(T *hp) { +// expected-error@+1 {{unexpected OpenMP directive '#pragma omp declare simd'}} +#pragma omp declare simd + *hp = *t; + } + +private: + T t; +}; 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 + 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 +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 = []; + let SemaHandler = 0; + let Documentation = [Undocumented]; + 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; } + }]; +} + 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">; } // 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. + 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(); + + 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 + /// 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); +} 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(); + } + 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)); + 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); + } PrintTemplateParameters(Params, I->getTemplateSpecializationArgs()); Visit(I); } } + if (auto *Attr = D->getTemplatedDecl()->getAttr<OMPDeclareSimdDeclAttr>()) { + print(Attr); + } 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]; + } + 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(); + } + 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); + } + 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 +/// 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!"); + // 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(); + } +} + /// \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)); + D->addAttr(Attr); + break; + } + case UPD_DECL_EXPORTED: unsigned SubmoduleID = readSubmoduleID(Record, Idx); auto *Exported = cast<NamedDecl>(D); Index: lib/Serialization/ASTCommon.h =================================================================== --- lib/Serialization/ASTCommon.h +++ lib/Serialization/ASTCommon.h @@ -36,6 +36,7 @@ UPD_MANGLING_NUMBER, UPD_STATIC_LOCAL_NUMBER, UPD_DECL_MARKED_OPENMP_THREADPRIVATE, + UPD_DECL_MARKED_OPENMP_DECLARE_SIMD, UPD_DECL_EXPORTED }; Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -4615,6 +4615,14 @@ Record); break; + case UPD_DECL_MARKED_OPENMP_DECLARE_SIMD: { + auto *Attr = D->getAttr<OMPDeclareSimdDeclAttr>(); + AddSourceRange(Attr->getRange(), Record); + Record.push_back(Attr->getNumberOfDirectives()); + Record.push_back(Attr->getComplete() ? 1 : 0); + break; + } + case UPD_DECL_EXPORTED: Record.push_back(getSubmoduleID(Update.getModule())); break; @@ -5761,6 +5769,14 @@ DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_THREADPRIVATE)); } +void ASTWriter::DeclarationMarkedOpenMPDeclareSimd(const Decl *D) { + assert(!WritingAST && "Already writing the AST!"); + if (!D->isFromASTFile()) + return; + + DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_DECLARE_SIMD)); +} + void ASTWriter::RedefinedHiddenDefinition(const NamedDecl *D, Module *M) { assert(!WritingAST && "Already writing the AST!"); assert(D->isHidden() && "expected a hidden declaration");
_______________________________________________ cfe-commits mailing list cfe-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits