Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -2064,3 +2064,17 @@ let SemaHandler = 0; let Documentation = [Undocumented]; } + +def OMPDeclareSimdDecl : Attr { + let Spellings = [Pragma<"omp", "declare simd">]; + let Subjects = SubjectList<[Function]>; + let SemaHandler = 0; + let HasCustomParsing = 1; + let Documentation = [OMPDeclareSimdDocs]; + let AdditionalMembers = [{ + void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const { + OS << "#pragma omp declare simd\n"; + } + }]; +} + Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -1610,3 +1610,33 @@ arguments, with arbitrary offsets. }]; } + +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,10 @@ "'#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">; +def err_omp_decl_in_declare_simd : Error< + "function 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 @@ -7648,6 +7648,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 @@ -103,6 +103,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 @@ -2385,9 +2385,13 @@ LateParsedAttrList &LateAttrs); void MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(Declarator &D, VirtSpecifiers &VS); - void ParseCXXClassMemberDeclaration(AccessSpecifier AS, AttributeList *Attr, - const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), - ParsingDeclRAIIObject *DiagsFromTParams = nullptr); + DeclGroupPtrTy ParseCXXClassMemberDeclaration( + AccessSpecifier AS, AttributeList *Attr, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), + ParsingDeclRAIIObject *DiagsFromTParams = nullptr); + DeclGroupPtrTy ParseCXXClassMemberDeclarationWithPragmas( + AccessSpecifier &AS, ParsedAttributesWithRange &AccessAttrs, + DeclSpec::TST TagType, Decl *TagDecl); void ParseConstructorInitializer(Decl *ConstructorDecl); MemInitResult ParseMemInitializer(Decl *ConstructorDecl); void HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo, @@ -2416,7 +2420,10 @@ //===--------------------------------------------------------------------===// // OpenMP: Directives and clauses. /// \brief Parses declarative OpenMP directives. - DeclGroupPtrTy ParseOpenMPDeclarativeDirective(); + DeclGroupPtrTy ParseOpenMPDeclarativeDirectiveWithExtDecl( + AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, + DeclSpec::TST TagType = DeclSpec::TST_unspecified, + Decl *TagDecl = nullptr); /// \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; @@ -7875,6 +7876,12 @@ 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); + OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, SourceLocation StartLoc, 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 printOMPDeclareSimdAttr(Decl *D); /// 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,18 @@ } } +void DeclPrinter::printOMPDeclareSimdAttr(Decl *D) { + for (auto *Attr : D->specific_attrs()) + Attr->printPrettyPragma(Out, Policy); + if (D->hasAttr()) + Indent(); +} + void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { + if (!D->getDescribedFunctionTemplate() && + !D->isFunctionTemplateSpecialization()) + printOMPDeclareSimdAttr(D); + CXXConstructorDecl *CDecl = dyn_cast(D); CXXConversionDecl *ConversionDecl = dyn_cast(D); if (!Policy.SuppressSpecifiers) { @@ -914,11 +927,13 @@ if (PrintInstantiation) { TemplateParameterList *Params = D->getTemplateParameters(); for (auto *I : D->specializations()) { + printOMPDeclareSimdAttr(I); PrintTemplateParameters(Params, I->getTemplateSpecializationArgs()); Visit(I); } } + printOMPDeclareSimdAttr(D->getTemplatedDecl()); return VisitRedeclarableTemplateDecl(D); } Index: lib/Basic/OpenMPKinds.cpp =================================================================== --- lib/Basic/OpenMPKinds.cpp +++ lib/Basic/OpenMPKinds.cpp @@ -348,6 +348,8 @@ break; } break; + case OMPD_declare_simd: + break; case OMPD_unknown: case OMPD_threadprivate: case OMPD_section: Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -2234,8 +2234,9 @@ /// constant-initializer: /// '=' constant-expression /// -void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, - AttributeList *AccessAttrs, +Parser::DeclGroupPtrTy +Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, + AttributeList *AccessAttrs, const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject *TemplateDiags) { if (Tok.is(tok::at)) { @@ -2246,7 +2247,7 @@ ConsumeToken(); SkipUntil(tok::r_brace, StopAtSemi); - return; + return DeclGroupPtrTy(); } // Turn on colon protection early, while parsing declspec, although there is @@ -2280,7 +2281,7 @@ if (SS.isInvalid()) { SkipUntil(tok::semi); - return; + return DeclGroupPtrTy(); } // Try to parse an unqualified-id. @@ -2289,24 +2290,21 @@ if (ParseUnqualifiedId(SS, false, true, true, ParsedType(), TemplateKWLoc, Name)) { SkipUntil(tok::semi); - return; + return DeclGroupPtrTy(); } // TODO: recover from mistakenly-qualified operator declarations. if (ExpectAndConsume(tok::semi, diag::err_expected_after, "access declaration")) { SkipUntil(tok::semi); - return; + return DeclGroupPtrTy(); } - Actions.ActOnUsingDeclaration(getCurScope(), AS, - /* HasUsingKeyword */ false, - SourceLocation(), - SS, Name, - /* AttrList */ nullptr, - /* HasTypenameKeyword */ false, - SourceLocation()); - return; + return DeclGroupPtrTy::make(DeclGroupRef(Actions.ActOnUsingDeclaration( + getCurScope(), AS, + /* HasUsingKeyword */ false, SourceLocation(), SS, Name, + /* AttrList */ nullptr, + /* HasTypenameKeyword */ false, SourceLocation()))); } } @@ -2315,17 +2313,17 @@ if (!TemplateInfo.Kind && Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) { SourceLocation DeclEnd; - ParseStaticAssertDeclaration(DeclEnd); - return; + return DeclGroupPtrTy::make( + DeclGroupRef(ParseStaticAssertDeclaration(DeclEnd))); } if (Tok.is(tok::kw_template)) { assert(!TemplateInfo.TemplateParams && "Nested template improperly parsed?"); SourceLocation DeclEnd; - ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd, - AS, AccessAttrs); - return; + return DeclGroupPtrTy::make( + DeclGroupRef(ParseDeclarationStartingWithTemplate( + Declarator::MemberContext, DeclEnd, AS, AccessAttrs))); } // Handle: member-declaration ::= '__extension__' member-declaration @@ -2357,13 +2355,12 @@ if (Tok.is(tok::kw_namespace)) { Diag(UsingLoc, diag::err_using_namespace_in_class); SkipUntil(tok::semi, StopBeforeMatch); - } else { - SourceLocation DeclEnd; - // Otherwise, it must be a using-declaration or an alias-declaration. - ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo, - UsingLoc, DeclEnd, AS); + return DeclGroupPtrTy(); } - return; + SourceLocation DeclEnd; + // Otherwise, it must be a using-declaration or an alias-declaration. + return DeclGroupPtrTy::make(DeclGroupRef(ParseUsingDeclaration( + Declarator::MemberContext, TemplateInfo, UsingLoc, DeclEnd, AS))); } // Hold late-parsed attributes so we can attach a Decl to them later. @@ -2388,7 +2385,7 @@ TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate && DiagnoseMissingSemiAfterTagDefinition(DS, AS, DSC_class, &CommonLateParsedAttrs)) - return; + return DeclGroupPtrTy(); MultiTemplateParamsArg TemplateParams( TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() @@ -2402,7 +2399,7 @@ Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, TemplateParams); DS.complete(TheDecl); - return; + return DeclGroupPtrTy::make(DeclGroupRef(TheDecl)); } ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext); @@ -2443,7 +2440,7 @@ if (ParseCXXMemberDeclaratorBeforeInitializer( DeclaratorInfo, VS, BitfieldSize, LateParsedAttrs)) { TryConsumeToken(tok::semi); - return; + return DeclGroupPtrTy(); } // Check for a member function definition. @@ -2492,7 +2489,7 @@ // Consume the optional ';' TryConsumeToken(tok::semi); - return; + return DeclGroupPtrTy(); } if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { @@ -2521,7 +2518,7 @@ if (Tok.is(tok::semi)) ConsumeExtraSemi(AfterMemberFunctionDefinition); - return; + return DeclGroupPtrTy::make(DeclGroupRef(FunDecl)); } } @@ -2695,10 +2692,10 @@ SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); // If we stopped at a ';', eat it. TryConsumeToken(tok::semi); - return; + return DeclGroupPtrTy(); } - Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup); + return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup); } /// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer. @@ -2816,6 +2813,96 @@ MaybeParseGNUAttributes(Attrs); } +Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas( + AccessSpecifier &AS, ParsedAttributesWithRange &AccessAttrs, + DeclSpec::TST TagType, Decl *TagDecl) { + if (getLangOpts().MicrosoftExt && + Tok.isOneOf(tok::kw___if_exists, tok::kw___if_not_exists)) { + ParseMicrosoftIfExistsClassDeclaration(TagType, AS); + return DeclGroupPtrTy(); + } + + // Check for extraneous top-level semicolon. + if (Tok.is(tok::semi)) { + ConsumeExtraSemi(InsideStruct, TagType); + return DeclGroupPtrTy(); + } + + if (Tok.is(tok::annot_pragma_vis)) { + HandlePragmaVisibility(); + return DeclGroupPtrTy(); + } + + if (Tok.is(tok::annot_pragma_pack)) { + HandlePragmaPack(); + return DeclGroupPtrTy(); + } + + if (Tok.is(tok::annot_pragma_align)) { + HandlePragmaAlign(); + return DeclGroupPtrTy(); + } + + if (Tok.is(tok::annot_pragma_ms_pointers_to_members)) { + HandlePragmaMSPointersToMembers(); + return DeclGroupPtrTy(); + } + + if (Tok.is(tok::annot_pragma_ms_pragma)) { + HandlePragmaMSPragma(); + return DeclGroupPtrTy(); + } + + // If we see a namespace here, a close brace was missing somewhere. + if (Tok.is(tok::kw_namespace)) { + DiagnoseUnexpectedNamespace(cast(TagDecl)); + return DeclGroupPtrTy(); + } + + AccessSpecifier NewAS = getAccessSpecifierIfPresent(); + if (NewAS != AS_none) { + // Current token is a C++ access specifier. + AS = NewAS; + SourceLocation ASLoc = Tok.getLocation(); + unsigned TokLength = Tok.getLength(); + ConsumeToken(); + AccessAttrs.clear(); + MaybeParseGNUAttributes(AccessAttrs); + + SourceLocation EndLoc; + if (TryConsumeToken(tok::colon, EndLoc)) { + } else if (TryConsumeToken(tok::semi, EndLoc)) { + Diag(EndLoc, diag::err_expected) + << tok::colon << FixItHint::CreateReplacement(EndLoc, ":"); + } else { + EndLoc = ASLoc.getLocWithOffset(TokLength); + Diag(EndLoc, diag::err_expected) + << tok::colon << FixItHint::CreateInsertion(EndLoc, ":"); + } + + // The Microsoft extension __interface does not permit non-public + // access specifiers. + if (TagType == DeclSpec::TST_interface && AS != AS_public) { + Diag(ASLoc, diag::err_access_specifier_interface) << (AS == AS_protected); + } + + if (Actions.ActOnAccessSpecifier(NewAS, ASLoc, EndLoc, + AccessAttrs.getList())) { + // found another attribute than only annotations + AccessAttrs.clear(); + } + + return DeclGroupPtrTy(); + } + + if (Tok.is(tok::annot_pragma_openmp)) + return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, AccessAttrs, TagType, + TagDecl); + + // Parse all the comma separated declarators. + return ParseCXXClassMemberDeclaration(AS, AccessAttrs.getList()); +} + /// ParseCXXMemberSpecification - Parse the class definition. /// /// member-specification: @@ -2973,101 +3060,14 @@ CurAS = AS_private; else CurAS = AS_public; - ParsedAttributes AccessAttrs(AttrFactory); + ParsedAttributesWithRange AccessAttrs(AttrFactory); if (TagDecl) { // While we still have something to read, read the member-declarations. - while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { + while (Tok.isNot(tok::r_brace) && !isEofOrEom()) // Each iteration of this loop reads one member-declaration. - - if (getLangOpts().MicrosoftExt && Tok.isOneOf(tok::kw___if_exists, - tok::kw___if_not_exists)) { - ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS); - continue; - } - - // Check for extraneous top-level semicolon. - if (Tok.is(tok::semi)) { - ConsumeExtraSemi(InsideStruct, TagType); - continue; - } - - if (Tok.is(tok::annot_pragma_vis)) { - HandlePragmaVisibility(); - continue; - } - - if (Tok.is(tok::annot_pragma_pack)) { - HandlePragmaPack(); - continue; - } - - if (Tok.is(tok::annot_pragma_align)) { - HandlePragmaAlign(); - continue; - } - - if (Tok.is(tok::annot_pragma_openmp)) { - ParseOpenMPDeclarativeDirective(); - continue; - } - - if (Tok.is(tok::annot_pragma_ms_pointers_to_members)) { - HandlePragmaMSPointersToMembers(); - continue; - } - - if (Tok.is(tok::annot_pragma_ms_pragma)) { - HandlePragmaMSPragma(); - continue; - } - - // If we see a namespace here, a close brace was missing somewhere. - if (Tok.is(tok::kw_namespace)) { - DiagnoseUnexpectedNamespace(cast(TagDecl)); - break; - } - - AccessSpecifier AS = getAccessSpecifierIfPresent(); - if (AS != AS_none) { - // Current token is a C++ access specifier. - CurAS = AS; - SourceLocation ASLoc = Tok.getLocation(); - unsigned TokLength = Tok.getLength(); - ConsumeToken(); - AccessAttrs.clear(); - MaybeParseGNUAttributes(AccessAttrs); - - SourceLocation EndLoc; - if (TryConsumeToken(tok::colon, EndLoc)) { - } else if (TryConsumeToken(tok::semi, EndLoc)) { - Diag(EndLoc, diag::err_expected) - << tok::colon << FixItHint::CreateReplacement(EndLoc, ":"); - } else { - EndLoc = ASLoc.getLocWithOffset(TokLength); - Diag(EndLoc, diag::err_expected) - << tok::colon << FixItHint::CreateInsertion(EndLoc, ":"); - } - - // The Microsoft extension __interface does not permit non-public - // access specifiers. - if (TagType == DeclSpec::TST_interface && CurAS != AS_public) { - Diag(ASLoc, diag::err_access_specifier_interface) - << (CurAS == AS_protected); - } - - if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc, - AccessAttrs.getList())) { - // found another attribute than only annotations - AccessAttrs.clear(); - } - - continue; - } - - // Parse all the comma separated declarators. - ParseCXXClassMemberDeclaration(CurAS, AccessAttrs.getList()); - } + ParseCXXClassMemberDeclarationWithPragmas( + CurAS, AccessAttrs, static_cast(TagType), TagDecl); T.consumeClose(); } else { Index: lib/Parse/ParseOpenMP.cpp =================================================================== --- lib/Parse/ParseOpenMP.cpp +++ lib/Parse/ParseOpenMP.cpp @@ -31,6 +31,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_target, OMPD_unknown /*data*/, OMPD_target_data}, @@ -46,13 +47,14 @@ 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); @@ -64,12 +66,11 @@ if (!TokenIsAnnotation && SDKind == OMPD_unknown) { TokenMatched = - ((i == 0) && + ((i == 1) && !P.getPreprocessor().getSpelling(Tok).compare("point")) || - ((i == 1) && !P.getPreprocessor().getSpelling(Tok).compare("data")); - } else { + ((i == 2) && !P.getPreprocessor().getSpelling(Tok).compare("data")); + } else TokenMatched = SDKind == F[i][1] && SDKind != OMPD_unknown; - } if (TokenMatched) { P.ConsumeToken(); @@ -84,14 +85,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( + AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, + DeclSpec::TST TagType, Decl *TagDecl) { 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: @@ -109,6 +121,97 @@ 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(); + + 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(AS, Attrs, TagType, + TagDecl); + else + // Here we expect to see some function declaration. + while (Tok.isNot(tok::r_brace) && !isEofOrEom() && + (!Ptr || Ptr.get().isNull())) { + if (AS == AS_none || TagType == DeclSpec::TST_unspecified) { + MaybeParseCXX11Attributes(Attrs); + MaybeParseMicrosoftAttributes(Attrs); + ParsingDeclSpec PDS(*this); + Ptr = ParseExternalDeclaration(Attrs, &PDS); + } else + Ptr = ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType, + TagDecl); + } + if (!Ptr || Ptr.get().isNull()) { + if (isEofOrEom()) + Diag(Loc, diag::err_omp_decl_in_declare_simd); + return DeclGroupPtrTy(); + } + if (!Ptr.get().isSingleDecl()) + Diag(Loc, diag::err_omp_single_decl_in_declare_simd); + + // 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(); + } + // The last seen token is annot_pragma_openmp_end - need to check for + // extra tokens. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_declare_simd); + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + } + // Skip the last annot_pragma_openmp_end. + ConsumeToken(); + + if (Ptr.get().isSingleDecl()) + return Actions.ActOnOpenMPDeclareSimdDirective( + Clauses, Ptr.get().getSingleDecl(), Loc); + return Ptr; + } case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); break; @@ -310,6 +413,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 @@ -652,8 +652,10 @@ case tok::annot_pragma_opencl_extension: HandlePragmaOpenCLExtension(); return DeclGroupPtrTy(); - case tok::annot_pragma_openmp: - return ParseOpenMPDeclarativeDirective(); + case tok::annot_pragma_openmp: { + AccessSpecifier AS = AS_none; + return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, attrs); + } case tok::annot_pragma_ms_pointers_to_members: HandlePragmaMSPointersToMembers(); return DeclGroupPtrTy(); Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -1336,6 +1336,7 @@ case OMPD_cancellation_point: case OMPD_cancel: case OMPD_flush: + case OMPD_declare_simd: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); @@ -2130,6 +2131,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"); @@ -2147,6 +2149,24 @@ return Res; } +Sema::DeclGroupPtrTy +Sema::ActOnOpenMPDeclareSimdDirective(ArrayRef Clauses, + Decl *ADecl, SourceLocation StartLoc) { + if (auto *FTD = dyn_cast(ADecl)) + ADecl = FTD->getTemplatedDecl(); + + if (!isa(ADecl)) { + Diag(ADecl->getLocation(), diag::err_omp_function_expected) + << ADecl->getDeclContext()->isFileContext(); + return DeclGroupPtrTy(); + } + + auto *NewAttr = new (Context) OMPDeclareSimdDeclAttr( + SourceRange(StartLoc, StartLoc), Context, /*SI=*/0); + ADecl->addAttr(NewAttr); + return ConvertDeclToDeclGroup(ADecl); +} + StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, 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: test/OpenMP/declare_simd_ast_print.cpp =================================================================== --- test/OpenMP/declare_simd_ast_print.cpp +++ test/OpenMP/declare_simd_ast_print.cpp @@ -0,0 +1,144 @@ +// 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 void h(C *hp, C *hp2, C *hq, C *lin) { +} + +// CHECK: #pragma omp declare simd +// CHECK-NEXT: template 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 void h(float *hp, float *hp2, float *hq, float *lin) { +// CHECK-NEXT: } + +// CHECK: #pragma omp declare simd +// CHECK: template void h(C *hp, C *hp2, C *hq, C *lin) { +// CHECK-NEXT: } +// + +// Explicit specialization with . +// 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) +{ + // Implicit specialization with . + // 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: float taddpf(float *a, float *b) { + // CHECK-NEXT: return *a + *b; + // CHECK-NEXT: } + #pragma options align=packed + #pragma GCC visibility push(default) + #pragma omp declare simd + float taddpf(float *a, float *b) { return *a + *b; } + #pragma GCC visibility pop + +// CHECK: #pragma omp declare simd +// CHECK-NEXT: #pragma omp declare simd +// CHECK-NEXT: int tadd(int b) { +// CHECK-NEXT: return this->x[b] + b; +// CHECK-NEXT: } + #pragma omp declare simd + #pragma GCC visibility push(default) + #pragma options align=packed + #pragma omp declare simd + #pragma GCC visibility pop + int tadd(int b) { return x[b] + b; } + +private: + int x[10]; +}; + +// CHECK: template 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: #pragma omp declare simd +// CHECK-NEXT: #pragma omp declare simd +// CHECK-NEXT: int tadd(int b) { +// CHECK-NEXT: return this->x[b] + b; +// CHECK-NEXT: } +// CHECK: } +template +class TVV { +public: +// CHECK: template 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 options align=packed + #pragma GCC visibility push(default) + #pragma omp declare simd + float taddpf(float *a, float *b) { return *a + *b; } + #pragma GCC visibility pop + +// CHECK: #pragma omp declare simd +// CHECK-NEXT: float taddpf(float *a, float *b) { +// CHECK-NEXT: return *a + *b; +// CHECK-NEXT: } + + #pragma omp declare simd + #pragma GCC visibility push(default) + #pragma options align=packed + #pragma omp declare simd + #pragma GCC visibility pop + int tadd(int b) { return x[b] + b; } + +// CHECK: #pragma omp declare simd +// CHECK-NEXT: #pragma omp declare simd +// CHECK-NEXT: int tadd(int b) { +// CHECK-NEXT: return this->x[b] + b; +// CHECK-NEXT: } + +private: + int x[X]; +}; +// CHECK: }; + +// CHECK: TVV<16> t16; +TVV<16> t16; + +void f() { + float a = 1.0f, b = 2.0f; + float r = t16.taddpf(&a, &b); + int res = t16.tadd(b); +} + +#endif Index: test/OpenMP/declare_simd_messages.cpp =================================================================== --- test/OpenMP/declare_simd_messages.cpp +++ test/OpenMP/declare_simd_messages.cpp @@ -0,0 +1,54 @@ +// 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 only}} +#pragma omp declare simd +int a; +// expected-error@+2 {{'#pragma omp declare simd' can be applied to functions 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(); + +// expected-error@+1 {{single declaration is expected with 'declare simd' directive}} +#pragma omp declare simd +int b, c; + +#pragma omp declare simd +template +void h(C *hp, C *hp2, C *hq, C *lin) { + b = 0; +} + +#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 +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; +}; +// expected-error@+1 {{function declaration is expected with 'declare simd' directive}} +#pragma omp declare simd +// expected-error@+1 {{function declaration is expected with 'declare simd' directive}} +#pragma omp declare simd