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/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/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/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/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 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 @@ -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/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. /// @@ -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()) { + 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) { @@ -912,11 +928,17 @@ 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 @@ -324,6 +324,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; 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/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(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: @@ -85,6 +97,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) { + LateParseOpenMPDeclarativeDirective(/*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 = 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(static_cast(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/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 Clauses, + Decl *ADecl, SourceLocation StartLoc, + bool LastDirective) { + 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(); + } + if (auto *Attr = ADecl->getAttr()) { + 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 Clauses, Stmt *AStmt, SourceLocation StartLoc, 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/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(D); 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(); + 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"); 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,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 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: } +// + +// Instatiate with 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 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 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 +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 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_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 +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 +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; +};