Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -2088,3 +2088,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 << "\n"; + } + }]; +} + Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -1612,3 +1612,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 @@ -993,6 +993,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_decl_in_declare_simd : Error< + "function declaration is expected after '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 @@ -7660,6 +7660,10 @@ "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_single_decl_in_declare_simd : Error< + "single declaration is expected after 'declare simd' directive">; +def err_omp_function_expected : Error< + "'#pragma omp declare simd' can only be applied to functions">; 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 @@ -106,6 +106,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 @@ -2395,7 +2395,8 @@ ParsingDeclRAIIObject *DiagsFromTParams = nullptr); DeclGroupPtrTy ParseCXXClassMemberDeclarationWithPragmas( AccessSpecifier &AS, ParsedAttributesWithRange &AccessAttrs, - DeclSpec::TST TagType, Decl *TagDecl); + DeclSpec::TST TagType, Decl *TagDecl, + bool OnlyFunctionAndPragmas = false); void ParseConstructorInitializer(Decl *ConstructorDecl); MemInitResult ParseMemInitializer(Decl *ConstructorDecl); void HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo, @@ -2424,7 +2425,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; @@ -7873,6 +7874,11 @@ SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion); + /// \brief Called on well-formed '\#pragma omp declare simd' after parsing of + /// the associated method/function. + DeclGroupPtrTy ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG, + SourceLocation StartLoc); + OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, SourceLocation StartLoc, Index: lib/AST/DeclPrinter.cpp =================================================================== --- lib/AST/DeclPrinter.cpp +++ lib/AST/DeclPrinter.cpp @@ -95,7 +95,7 @@ void PrintTemplateParameters(const TemplateParameterList *Params, const TemplateArgumentList *Args = nullptr); - void prettyPrintAttributes(Decl *D); + void prettyPrintAttributes(Decl *D, bool PrintPragmas = false); void printDeclType(QualType T, StringRef DeclName, bool Pack = false); }; } @@ -194,15 +194,27 @@ return Out; } -void DeclPrinter::prettyPrintAttributes(Decl *D) { +void DeclPrinter::prettyPrintAttributes(Decl *D, bool PrintPragmas) { if (Policy.PolishForDeclaration) return; - + if (D->hasAttrs()) { AttrVec &Attrs = D->getAttrs(); - for (AttrVec::const_iterator i=Attrs.begin(), e=Attrs.end(); i!=e; ++i) { - Attr *A = *i; - A->printPretty(Out, Policy); + for (auto *A : Attrs) { + switch (A->getKind()) { +#define ATTR(X) +#define PRAGMA_SPELLING_ATTR(X) case attr::X: +#include "clang/Basic/AttrList.inc" + if (PrintPragmas) { + A->printPretty(Out, Policy); + Indent(); + } + break; + default: + if (!PrintPragmas) + A->printPretty(Out, Policy); + break; + } } } } @@ -408,6 +420,10 @@ } void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { + if (!D->getDescribedFunctionTemplate() && + !D->isFunctionTemplateSpecialization()) + prettyPrintAttributes(D, /*PrintPragmas=*/true); + CXXConstructorDecl *CDecl = dyn_cast(D); CXXConversionDecl *ConversionDecl = dyn_cast(D); if (!Policy.SuppressSpecifiers) { @@ -643,6 +659,7 @@ } void DeclPrinter::VisitFieldDecl(FieldDecl *D) { + // FIXME: add printing of pragma attributes if required. if (!Policy.SuppressSpecifiers && D->isMutable()) Out << "mutable "; if (!Policy.SuppressSpecifiers && D->isModulePrivate()) @@ -672,6 +689,7 @@ } void DeclPrinter::VisitVarDecl(VarDecl *D) { + // FIXME: add printing of pragma attributes if required. if (!Policy.SuppressSpecifiers) { StorageClass SC = D->getStorageClass(); if (SC != SC_None) @@ -779,6 +797,7 @@ } void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { + // FIXME: add printing of pragma attributes if required. if (!Policy.SuppressSpecifiers && D->isModulePrivate()) Out << "__module_private__ "; Out << D->getKindName(); @@ -914,11 +933,13 @@ if (PrintInstantiation) { TemplateParameterList *Params = D->getTemplateParameters(); for (auto *I : D->specializations()) { + prettyPrintAttributes(I, /*PrintPragmas=*/true); PrintTemplateParameters(Params, I->getTemplateSpecializationArgs()); Visit(I); } } + prettyPrintAttributes(D->getTemplatedDecl(), /*PrintPragmas=*/true); return VisitRedeclarableTemplateDecl(D); } Index: lib/Basic/OpenMPKinds.cpp =================================================================== --- lib/Basic/OpenMPKinds.cpp +++ lib/Basic/OpenMPKinds.cpp @@ -365,6 +365,8 @@ break; } break; + case OMPD_declare_simd: + break; case OMPD_unknown: case OMPD_threadprivate: case OMPD_section: Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -3617,7 +3617,9 @@ if (Tok.is(tok::annot_pragma_openmp)) { // Result can be ignored, because it must be always empty. - auto Res = ParseOpenMPDeclarativeDirective(); + AccessSpecifier AS = AS_none; + ParsedAttributesWithRange Attrs(AttrFactory); + auto Res = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs); assert(!Res); // Silence possible warnings. (void)Res; Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -2815,15 +2815,15 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas( AccessSpecifier &AS, ParsedAttributesWithRange &AccessAttrs, - DeclSpec::TST TagType, Decl *TagDecl) { - if (getLangOpts().MicrosoftExt && + DeclSpec::TST TagType, Decl *TagDecl, bool OnlyFunctionAndPragmas) { + if (!OnlyFunctionAndPragmas && 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)) { + if (!OnlyFunctionAndPragmas && Tok.is(tok::semi)) { ConsumeExtraSemi(InsideStruct, TagType); return DeclGroupPtrTy(); } @@ -2859,44 +2859,48 @@ 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, ":"); - } + if (!OnlyFunctionAndPragmas) { + 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); - // 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); - } + 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(); + } - if (Actions.ActOnAccessSpecifier(NewAS, ASLoc, EndLoc, - AccessAttrs.getList())) { - // found another attribute than only annotations - AccessAttrs.clear(); + return DeclGroupPtrTy(); } - - return DeclGroupPtrTy(); } if (Tok.is(tok::annot_pragma_openmp)) - return ParseOpenMPDeclarativeDirective(); + return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, AccessAttrs, TagType, + TagDecl); // Parse all the comma separated declarators. return ParseCXXClassMemberDeclaration(AS, AccessAttrs.getList()); 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}, @@ -48,11 +49,12 @@ for (unsigned i = 0; i < llvm::array_lengthof(F); ++i) { 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,8 +85,16 @@ /// /// 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); @@ -109,6 +118,50 @@ return Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers); } break; + case OMPD_declare_simd: { + // The syntax is: + // { #pragma omp declare simd } + // + // + + ConsumeToken(); + // 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); + if (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) + return DeclGroupPtrTy(); + } + // Skip the last annot_pragma_openmp_end. + ConsumeToken(); + + 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) { + if (AS == AS_none) { + assert(TagType == DeclSpec::TST_unspecified); + MaybeParseCXX11Attributes(Attrs); + MaybeParseMicrosoftAttributes(Attrs); + ParsingDeclSpec PDS(*this); + Ptr = ParseExternalDeclaration(Attrs, &PDS); + } else { + Ptr = ParseCXXClassMemberDeclarationWithPragmas( + AS, Attrs, TagType, TagDecl, /*OnlyFunctionAndPragmas=*/true); + } + } + } + if (!Ptr && (isEofOrEom() || Tok.is(tok::r_brace))) { + Diag(Loc, diag::err_omp_decl_in_declare_simd); + return DeclGroupPtrTy(); + } + + return Actions.ActOnOpenMPDeclareSimdDirective(Ptr, Loc); + } case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); break; @@ -310,6 +363,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 @@ -656,8 +656,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 @@ -1345,6 +1345,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"); @@ -2144,6 +2145,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"); @@ -2161,6 +2163,32 @@ return Res; } +Sema::DeclGroupPtrTy +Sema::ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG, + SourceLocation StartLoc) { + if (!DG || DG.get().isNull()) + return DeclGroupPtrTy(); + + if (!DG.get().isSingleDecl()) { + Diag(StartLoc, diag::err_omp_single_decl_in_declare_simd); + return DG; + } + auto *ADecl = DG.get().getSingleDecl(); + 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,58 @@ +// 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 only be applied to functions}} +#pragma omp declare simd +int a; +// expected-error@+2 {{'#pragma omp declare simd' can only be applied to functions}} +#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 after '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; +}; +namespace N { + // expected-error@+1 {{function declaration is expected after 'declare simd' directive}} + #pragma omp declare simd +} +// expected-error@+1 {{function declaration is expected after 'declare simd' directive}} +#pragma omp declare simd +// expected-error@+1 {{function declaration is expected after 'declare simd' directive}} +#pragma omp declare simd