Index: include/clang/AST/ASTMutationListener.h =================================================================== --- include/clang/AST/ASTMutationListener.h +++ include/clang/AST/ASTMutationListener.h @@ -115,6 +115,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/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -2054,3 +2054,21 @@ let SemaHandler = 0; let Documentation = [Undocumented]; } + +def OMPDeclareSimdDecl : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = [Pragma<"omp", "declare simd">]; + let Subjects = SubjectList<[Function]>; + let SemaHandler = 0; + let HasCustomParsing = 1; + let Documentation = [OMPDeclareSimdDocs]; + 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/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -1583,3 +1583,33 @@ The ``returns_nonnull`` attribute implies that returning a null pointer is undefined behavior, which the optimizer may take advantage of. The ``_Nonnull`` type qualifier indicates that a pointer cannot be null in a more general manner (because it is part of the type system) and does not imply undefined behavior, making it more widely applicable }]; } + +def OMPDeclareSimdDocs : Documentation { + let Category = DocCatStmt; + let Heading = "#pragma omp declare simd"; + let Content = [{ +The declare simd construct can be applied to a function to enable the creation of one or more versions that can process multiple arguments using SIMD instructions from a single invocation from a SIMD loop. The declare simd directive is a declarative directive. There may be multiple declare simd directives for a function. The use of a declare simd construct on a function enables the creation of SIMD +versions of the associated function that can be used to process multiple arguments from a single invocation from a SIMD loop concurrently. +The syntax of the declare simd construct is as follows: + + .. code-block:: c + + #pragma omp declare simd [clause[[,] clause] ...] new-line + [#pragma omp declare simd [clause[[,] clause] ...] new-line] + [...] + function definition or declaration + +where clause is one of the following: + + .. code-block:: c + + simdlen(length) + linear(argument-list[:constant-linear-step]) + aligned(argument-list[:alignment]) + uniform(argument-list) + inbranch + notinbranch + + }]; +} + 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 @@ -7637,6 +7637,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 only">; def err_omp_wrong_cancel_region : Error< "one of 'for', 'parallel', 'sections' or 'taskgroup' is expected">; def err_omp_parent_cancel_region_nowait : Error< Index: include/clang/Basic/OpenMPKinds.def =================================================================== --- include/clang/Basic/OpenMPKinds.def +++ include/clang/Basic/OpenMPKinds.def @@ -99,6 +99,7 @@ OPENMP_DIRECTIVE_EXT(parallel_sections, "parallel sections") OPENMP_DIRECTIVE_EXT(for_simd, "for simd") OPENMP_DIRECTIVE_EXT(cancellation_point, "cancellation point") +OPENMP_DIRECTIVE_EXT(declare_simd, "declare simd") // OpenMP clauses. OPENMP_CLAUSE(if, OMPIfClause) Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -1021,6 +1021,19 @@ CachedTokens *ExceptionSpecTokens; }; + /// \brief An OpenMP declaration inside a class. + struct LateParsedOpenMPDeclaration : public LateParsedDeclaration { + explicit LateParsedOpenMPDeclaration(Parser *P) : Self(P) {} + + void ParseLexedMethodDeclarations() 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). @@ -2416,7 +2429,13 @@ //===--------------------------------------------------------------------===// // OpenMP: Directives and clauses. /// \brief Parses declarative OpenMP directives. - DeclGroupPtrTy ParseOpenMPDeclarativeDirective(); + /// \param Level Current level of declarative directive, in case it is allowed + /// to apply multiple declarative directives to the same declaration. + DeclGroupPtrTy ParseOpenMPDeclarativeDirectiveWithExtDecl(bool IsInTagDecl, + unsigned Level = 0); + /// \brief Late parse directive. + void LateParseOpenMPDeclarativeDirectiveWithTemplateFunction( + OpenMPDirectiveKind DKind, SourceLocation Loc); /// \brief Parses simple list of variables. /// /// \param Kind Kind of the directive. 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; @@ -7869,6 +7870,13 @@ SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion); + /// \brief Called on well-formed '\#pragma omp declare simd' after parsing of + /// the associated method/function. + DeclGroupPtrTy ActOnOpenMPDeclareSimdDirective(ArrayRef Clauses, + Decl *ADecl, + SourceLocation StartLoc, + bool LastDirective); + OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, SourceLocation StartLoc, Index: include/clang/Serialization/ASTWriter.h =================================================================== --- include/clang/Serialization/ASTWriter.h +++ include/clang/Serialization/ASTWriter.h @@ -865,6 +865,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; void AddedAttributeToRecord(const Attr *Attr, const RecordDecl *Record) override; Index: lib/AST/DeclPrinter.cpp =================================================================== --- lib/AST/DeclPrinter.cpp +++ lib/AST/DeclPrinter.cpp @@ -36,6 +36,7 @@ void ProcessDeclGroup(SmallVectorImpl& Decls); void Print(AccessSpecifier AS); + void print(OMPDeclareSimdDeclAttr *A); /// Print an Objective-C method type in parentheses. /// @@ -202,7 +203,8 @@ AttrVec &Attrs = D->getAttrs(); for (AttrVec::const_iterator i=Attrs.begin(), e=Attrs.end(); i!=e; ++i) { Attr *A = *i; - A->printPretty(Out, Policy); + if (!isa(A)) + A->printPretty(Out, Policy); } } } @@ -407,7 +409,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()) { + if (D->getTemplatedKind() != + FunctionDecl::TK_FunctionTemplateSpecialization && + D->getTemplatedKind() != FunctionDecl::TK_FunctionTemplate && + D->getTemplatedKind() != + FunctionDecl::TK_DependentFunctionTemplateSpecialization) + print(Attr); + } CXXConstructorDecl *CDecl = dyn_cast(D); CXXConversionDecl *ConversionDecl = dyn_cast(D); if (!Policy.SuppressSpecifiers) { @@ -914,11 +931,15 @@ if (PrintInstantiation) { TemplateParameterList *Params = D->getTemplateParameters(); for (auto *I : D->specializations()) { + if (auto *Attr = I->getAttr()) + print(Attr); PrintTemplateParameters(Params, I->getTemplateSpecializationArgs()); Visit(I); } } + if (auto *Attr = D->getTemplatedDecl()->getAttr()) + print(Attr); return VisitRedeclarableTemplateDecl(D); } Index: lib/Basic/OpenMPKinds.cpp =================================================================== --- lib/Basic/OpenMPKinds.cpp +++ lib/Basic/OpenMPKinds.cpp @@ -338,6 +338,8 @@ break; } break; + case OMPD_declare_simd: + break; case OMPD_unknown: case OMPD_threadprivate: case OMPD_section: 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; void AddedAttributeToRecord(const Attr *Attr, const RecordDecl *Record) override; @@ -223,6 +224,11 @@ for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->DeclarationMarkedOpenMPThreadPrivate(D); } +void MultiplexASTMutationListener::DeclarationMarkedOpenMPDeclareSimd( + const Decl *D) { + for (auto *Listener : Listeners) + Listener->DeclarationMarkedOpenMPDeclareSimd(D); +} void MultiplexASTMutationListener::RedefinedHiddenDefinition(const NamedDecl *D, Module *M) { for (auto *L : Listeners) Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -2975,7 +2975,7 @@ } if (Tok.is(tok::annot_pragma_openmp)) { - ParseOpenMPDeclarativeDirective(); + ParseOpenMPDeclarativeDirectiveWithExtDecl(/*IsInTagDecl=*/true); continue; } Index: lib/Parse/ParseOpenMP.cpp =================================================================== --- lib/Parse/ParseOpenMP.cpp +++ lib/Parse/ParseOpenMP.cpp @@ -30,6 +30,7 @@ // E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd // TODO: add other combined directives in topological order. const OpenMPDirectiveKind F[][3] = { + {OMPD_unknown /*declare*/, OMPD_simd, OMPD_declare_simd}, {OMPD_unknown /*cancellation*/, OMPD_unknown /*point*/, OMPD_cancellation_point}, {OMPD_for, OMPD_simd, OMPD_for_simd}, @@ -43,25 +44,25 @@ : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok)); bool TokenMatched = false; for (unsigned i = 0; i < llvm::array_lengthof(F); ++i) { - if (!Tok.isAnnotation() && DKind == OMPD_unknown) { + if (!Tok.isAnnotation() && DKind == OMPD_unknown) TokenMatched = - (i == 0) && - !P.getPreprocessor().getSpelling(Tok).compare("cancellation"); - } else { + ((i == 0) && + !P.getPreprocessor().getSpelling(Tok).compare("declare")) || + ((i == 1) && + !P.getPreprocessor().getSpelling(Tok).compare("cancellation")); + else TokenMatched = DKind == F[i][0] && DKind != OMPD_unknown; - } if (TokenMatched) { Tok = P.getPreprocessor().LookAhead(0); auto SDKind = Tok.isAnnotation() ? OMPD_unknown : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok)); - if (!Tok.isAnnotation() && DKind == OMPD_unknown) { + if (!Tok.isAnnotation() && SDKind == OMPD_unknown) TokenMatched = - (i == 0) && !P.getPreprocessor().getSpelling(Tok).compare("point"); - } else { + (i == 1) && !P.getPreprocessor().getSpelling(Tok).compare("point"); + else TokenMatched = SDKind == F[i][1] && SDKind != OMPD_unknown; - } if (TokenMatched) { P.ConsumeToken(); DKind = F[i][2]; @@ -75,14 +76,25 @@ /// /// threadprivate-directive: /// annot_pragma_openmp 'threadprivate' simple-variable-list +/// annot_pragma_omp_end /// -Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { +/// declare-simd-directive: +/// annot_pragma_openmp 'declare simd' { [,]} +/// annot_pragma_omp_end +/// +/// +Parser::DeclGroupPtrTy +Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(bool IsInTagDecl, + unsigned Level) { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); ParenBraceBracketBalancer BalancerRAIIObj(*this); + auto AnnotationVal = reinterpret_cast(Tok.getAnnotationValue()); SourceLocation Loc = ConsumeToken(); SmallVector Identifiers; - auto DKind = ParseOpenMPDirectiveKind(*this); + OpenMPDirectiveKind DKind = + (AnnotationVal == 0) ? ParseOpenMPDirectiveKind(*this) + : static_cast(AnnotationVal); switch (DKind) { case OMPD_threadprivate: @@ -100,6 +112,86 @@ return Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers); } break; + case OMPD_declare_simd: { + // The syntax is: + // { #pragma omp declare simd } + // + // + if (AnnotationVal == 0) + // Skip 'simd' if it was restored from cached tokens. + ConsumeToken(); + if (IsInTagDecl) { + LateParseOpenMPDeclarativeDirectiveWithTemplateFunction( + /*DKind=*/OMPD_declare_simd, Loc); + return DeclGroupPtrTy(); + } + + SmallVector, OMPC_unknown + 1> + FirstClauses(OMPC_unknown + 1); + SmallVector Clauses; + SmallVector 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 = ParseOpenMPDeclarativeDirectiveWithExtDecl(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); + + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + OpenMPClauseKind CKind = Tok.isAnnotation() + ? OMPC_unknown + : getOpenMPClauseKind(PP.getSpelling(Tok)); + Actions.StartOpenMPClause(CKind); + 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.EndOpenMPClause(); + } + // 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; @@ -135,6 +227,70 @@ return DeclGroupPtrTy(); } +/// \brief Late parsing of declarative OpenMP directives. +/// +/// declare-simd: +/// annot_pragma_openmp 'declare simd' { [,]} +/// annot_pragma_openmp_end +///